2.9 读取DTC信息(0x19)——查看症状清单
一个服务,掌管所有“查病历“的需求
你在第1.5节的完整诊断流程中已经见过0x19——你向ECU询问“有多少个confirmed故障码“,ECU回答“3个“,你继续追问“哪三个?P0102、P0305、C0421——它们的故障快照数据给我看看“。
0x19是UDS协议里子功能最多的SID——一共19种子功能(ISO 14229-1:2013定义0x01~0x13),每种子功能应对不同的DTC查询场景。为什么需要19种?因为 “查病历“本身不是一种操作——它是一系列不同维度的追问:
| 你问的问题 | 对应子功能 | 为什么需要独立子功能 |
|---|---|---|
| 有多少个Confirmed的DTC? | 0x01 reportNumberOfDTCByStatusMask | 只需数字——先了解一下严重性——别急着展开全部详情 |
| 列出所有这些DTC和状态 | 0x02 reportDTCByStatusMask | 展开列表——每个DTC 4字节(3+DTCStatus=1) |
| 这些DTC的快照数据可以拿吗? | 0x03 reportDTCSnapshotIdentification | DID+record信息——先拿到有哪些快照可以获取 |
| P0305的快照数据给我 | 0x04 reportDTCSnapshotRecordByDTCNumber | 基于DTC号拿完整的快照数据 |
| 有多少排放OBD相关DTC? | 0x12 | OBD-II的法规需求——和UDS DTC并行管理 |
| 镜像内存里有什么DTC? | 0x0F | 不可擦除的“备份病历“ |
核心洞察:0x19不是被设计成“一个强大的DTC查询工具“——它是被逐个子功能需求叠加出来的。每一个子功能的诞生都对应一个实际诊断场景:“法规要求能看到排放OBD永久码”(→ 0x12/0x13/0x15)、“维修站需要DTC冻结帧来定位故障发生上下文”(→ 0x03/0x04)、“产线需要批量验证所有支持的DTC”(→ 0x0A)——因此19种子功能逐层叠加。
请求报文结构
Byte 1: sub-function (reportType, bit6-0)
bit7 = suppressPosRsp
bit6-0 = 0x01~0x19
Byte 2+: 附加参数 (取决于子功能)
各子功能的附加参数不能一一全讲——但核心几类子功能如下:
核心子功能A组:按状态掩码查询
0x01 reportNumberOfDTCByStatusMask: 报告数量(无具体DTC)
0x02 reportDTCByStatusMask: 报告DTC列表(含DTC编号+状态字节)
0x01→0x02构成典型的“先问有多少,再问具体内容“两阶段查询模式——先用量统计判断严重性,再展开完整列表。
附加参数:DTCStatusMask (1字节)
请求格式:
0x19 0x01 0x09
sub DTCStatusMask=0x09=(confirmedDTC|testFailed)
正响应(0x01):
Byte 0: 0x59
Byte 1: 0x01 (子功能回声)
Byte 2: DTCStatusAvailabilityMask (0x09)
Byte 3: DTCFormatIdentifier (0x01=OBD, 0x02=J1939, 0x03=ISO14229)
Byte 4-5: DTCCount (大端序) → 有几个DTC
正响应(0x02):
Byte 0: 0x59
Byte 1: 0x02
Byte 2: DTCStatusAvailabilityMask
Byte 3+: 重复N次 [ DTC(3 bytes) + statusOfDTC(1 byte) ]
例子:读取所有confirmed的DTC列表:
请求: 0x19 0x02 0x08 → DTCStatusMask=0x08 (confirmedDTC)
响应: 0x59 0x02 0x08 0x01 0x02 0x08 0x09 0x01 0x03 0x04 0x0F
mask DTC1:010208 status=09 DTC2:010304 status=0F
解读:
DTC1 = 0x010208 → OBD格式 P0102 (MAF传感器电路低电压), status=testFailed+confirmed
DTC2 = 0x010304 → OBD格式 P0304 (4号缸失火), status=testFailed+confirmed+testNotCompletedSinceLastClear+warningIndicatorRequested
> 注:ISO 14229-1使用三字节DTC编码(如0x010208),OBD-II使用五字符编码(如P0102),两者之间通过标准映射规则互相转换——高半字节决定前缀(0x0→P, 0x1→C, 0x2→B, 0x3→U),后续字节决定数字部分。
核心子功能B组:冻结帧/快照查询
0x03 reportDTCSnapshotIdentification: 列出所有有快照的DTC
0x04 reportDTCSnapshotRecordByDTCNumber: 根据DTC编号获取快照数据
冻结帧(Freeze Frame)是DTC发生那一刻ECU自动记录的一组环境参数——发动机转速、车速、冷却液温度、进气温度、燃油修正——帮助诊断技师理解故障发生的上下文。
Step 1: 查明哪些DTC有快照
请求: 0x19 0x03
响应: 0x59 0x03 0x01 0x02 0x03 0x01 0x01 0x03 0x05 0x02
DTC1:010203 Record=1 DTC2:010305 Record=2
P0103有1条快照记录,P0305有2条快照记录
Step 2: 拿到快照
请求: 0x19 0x04 0x01 0x03 0x05 0x02
sub DTC=010305 recordNumber 0x02
响应: 0x59 0x04 + DTCAndStatusRecord + DTCSnapshotRecord
...包含一组数据项 (每个数据项是一个DID + dataRecord)
VehicleSpeed=87km/h, EngineSpeed=2450rpm, CoolantTemp=92°C, LTFT=+3.1%
核心子功能C组:扩展数据
0x06 reportDTCExtDataRecordByDTCNumber: 获取扩展数据记录
扩展数据是DTC的辅助信息——故障计数器、衰老计数器、发生时间、里程数——这些信息对诊断仪来说极其关键。比如“故障计数器=127“表示一个DTC已经发生了127次——这是个高频故障——而不是偶尔一次短路。
镜像内存的特殊含义
ISO 14229-1:2013引入了 镜像内存(Mirror Memory) 的概念:
- DTC可以在两个存储器中共存——主存储器和镜像存储器
- 0x14清除DTC只清除主存储器——镜像存储器的DTC不被清除
- 镜像存储器的读取通过0x19的子功能0x0F~0x11完成
为什么需要镜像内存?法规需求——某些排放相关的DTC必须保留“永久记录“——即使主诊断清除了也不能消除痕迹。类似于你的医疗记录会被注销——但你的医疗记录归档到医管局的备份不能随意注销。
本篇小结
- 0x19读DTC信息是UDS里子功能最多的SID——19种子功能分别应对11种DTC查询维度:数量统计、列表枚举、快照、扩展数据、OBD合规、镜像内存、永久状态等。
- DTCStatusMask是0x19的核心参数——它定义“满足匹配条件“的DTC集合。statusOfDTC的8位编码(取Bit掩码比较)使查询粒度极细化——你不仅能查“confirmed DTC“,还能查“confirmed+testFailed且pending的DTC“。
- 快照(Freeze Frame)和扩展数据是0x19最强大的诊断能力——不是看“你有多少故障“,而是看“什么时候故障、故障的瞬间引擎正在做什么“。
- 镜像内存(Mirror Memory)给诊断数据持久性提供了第二重保障——即使主内存被清除也不丢排放合规相关的永久记录。
【下集预告】:DTC查完了——但每个DTC的状态字节到底在说什么?testFailed、confirmed、pending、warningIndicator这些bit位不是一堆随机标志——它们构成了一个故障的完整生命周期:从“首次检测到异常“到“确认“到“维修后清除“。0x19的子功能依赖这个状态字节做筛选——不理解状态字节,你读到的DTC列表就是一团乱码。下一节我们拆开这个字节的每一位。