一、19 服务是什么?为什么它是诊断的"第一入口"?
0x19 的作用只有一句话:按需读取 ECU 中存储的 DTC(诊断故障码)及其相关信息。
当 ECU 检测到异常时(传感器短路、执行器卡滞、通信丢失……),它会做三件事:
- 生成标准化的 DTC(如 P0301 = 1 缸失火);
- 记录故障状态位(当前激活?已确认?等待清除?);
- 可选地记录关联数据——快照(故障发生瞬间的运行数据)、扩展数据(老化计数、发生次数等)。
19 服务就是把这些信息标准化读出来的接口。它定义了"怎么请求"和"怎么反馈",让诊断仪可以跨品牌、跨 ECU 类型地读取故障数据。
先澄清两个流行误解:
⚠️误解 1:"当前故障"和"历史故障"是两个不同的子功能。不是。UDS 里没有"读取当前故障码"或"读取历史故障码"的专用子功能。区分当前和历史靠的是状态掩码(statusMask)的比特位组合——同一个子功能 0x02 配不同 statusMask,读出来的范围就不同。
⚠️误解 2:以太网下 ECU 能返回 DTC 文本描述(如"P0301:1 缸失火")。不能。UDS 响应里只有数值(DTC 编号、状态字节、原始数据),不含任何文本字符串。DTC 的文字描述存储在诊断仪本地的数据库(ODX/CDD)里,不是 ECU 返回的。
二、子功能全景:标准定义了 29 个,常用的是这 8 个
ISO 14229-1(2020/2023 版)为 0x19 定义了0x01–0x1D 共 29 个子功能。全部列出不现实,下面按使用频率给出完整速查表:
| 子功能 | 标准名称 | 一句话说明 | 频率 |
|---|---|---|---|
| 0x01 | reportNumberOfDTCByStatusMask | 按状态掩码统计匹配的 DTC数量 | ★★★ |
| 0x02 | reportDTCByStatusMask | 按状态掩码读取匹配的 DTC列表 + 状态字节(最常用) | ★★★★★ |
| 0x03 | reportDTCSnapshotIdentificationByDTCNumber | 按 DTC 号查询有哪些快照记录号 | ★ |
| 0x04 | reportDTCSnapshotRecordByDTCNumber | 按 DTC 号 + 快照记录号读取故障快照 | ★★★ |
| 0x05 | reportDTCStoredDataByDTCNumber | 按 DTC 号读取存储数据 | ★ |
| 0x06 | reportDTCExtendedDataRecordByDTCNumber | 按 DTC 号 + 记录号读取扩展数据(老化/计数/时间) | ★★★ |
| 0x07 | reportNumberOfDTCBySeverityMaskRecord | 按严重度掩码统计数量 | ★ |
| 0x08 | reportDTCBySeverityMaskRecord | 按严重度掩码读取 DTC | ★ |
| 0x09 | reportSeverityInformationOfDTC | 读取指定 DTC 的严重度信息 | ★ |
| 0x0A | reportSupportedDTC | 读取 ECU支持的全部 DTC(出厂固有能力) | ★★ |
| 0x0B | reportFirstTestFailedDTC | 首次 testFailed 的 DTC | ★ |
| 0x0C | reportFirstConfirmedDTC | 首次 confirmed 的 DTC | ★ |
| 0x0D | reportMostRecentTestFailedDTC | 最近一次 testFailed 的 DTC | ★ |
| 0x0E | reportMostRecentConfirmedDTC | 最近一次 confirmed 的 DTC | ★ |
| 0x0F | reportMirrorMemoryDTCByStatusMask | 镜像存储 DTC(按状态掩码) | ★ |
| 0x14 | reportDTCFaultDetectionCounter | 读取 DTC 故障检测计数器 | ★ |
| 0x15 | reportDTCWithPermanentStatus | 读取永久 DTC(法规强制,0x14 服务清不掉) | ★★★ |
| 0x16 | reportDTCBySeverityMaskRecord(带扩展) | 严重度相关扩展 | ★ |
| 0x17 | reportUserDefMemoryDTCByStatusMask | 用户自定义内存 DTC | ★ |
| 0x18 | reportUserDefMemoryDTCSnapshotRecordByDTCNumber | 用户自定义内存快照 | ★ |
| 0x19 | reportSupportedDTCExtDataRecordByDTCNumber | 支持的 DTC 扩展数据 | ★ |
| 0x1A | reportSupportedDTCByStatusMask | 按状态掩码读支持的 DTC | ★ |
| 0x1B | WWHSOBDReportDTCByStatusMask(WWH-OBD) | 排放法规专用 | ★ |
| 0x1C | WWHOBDReportDTCWithPermanentStatus(WWH-OBD) | 排放法规专用 | ★ |
| 0x1D | WWHOBDReportDTCBySeverityMaskRecord(WWH-OBD) | 排放法规专用 | ★ |
⚠️ 网上资料最常见的三处张冠李戴:
- 把0x04说成"读取历史故障码"——它是读快照;
- 把0x06说成"读取永久故障码"——它是读扩展数据;永久 DTC 是0x15;
- 把0x08说成"读取故障快照"——它是按严重度掩码读 DTC。
另外,"0x03、0x05 未使用"也是错的——0x03 和 0x05 在 2020 版标准中都有定义。
三个核心概念的关系
DTC 本体(编号 + 状态字节) ├── 快照(Snapshot / Freeze Frame):故障发生瞬间的运行数据(转速、水温、车速…) │ → 用 0x04 读取 ├── 扩展数据(Extended Data):老化计数、发生次数、故障出现/消失时间… │ → 用 0x06 读取 └── 永久状态(Permanent):排放法规要求,清不掉 → 用 0x15 读取三、报文格式:逐子功能拆解
通用规则
- 请求第 1 字节:SID = 0x19;
- 请求第 2 字节:子功能码;
- 响应第 1 字节:0x59(= 0x19 + 0x40);
- 响应第 2 字节:回显子功能码;
- DTC 编号一律 3 字节(这是 UDS 与 KWP2000 的关键区别,KWP 是 2 字节);
- statusMask 一律 1 字节(不是 2 字节!)。
3.1 子功能 0x01:reportNumberOfDTCByStatusMask(统计数量)
请求:19 01 <statusMask> (3 字节) 示例:19 01 FF (统计所有状态的 DTC) 响应:59 01 <statusMask> <DTCFormatIdentifier> <DTCCount 高> <DTCCount 低> 示例:59 01 FF 00 00 02 (共 2 个匹配的 DTC)- DTCFormatIdentifier:0x00 = ISO 15031-6(SAE J2012),0x01 = ISO 14229-1,0x02 = SAE J1939-73 等;
- DTCCount 是 2 字节无符号整数。
3.2 子功能 0x02:reportDTCByStatusMask(读 DTC 列表)——最常用
请求:19 02 <statusMask> (3 字节) 示例:19 02 FF (读所有状态的 DTC) 19 02 01 (只读 testFailed=1 的,即"当前激活") 19 02 08 (只读 confirmedDTC=1 的) 响应:59 02 <statusMask> <DTCFormatIdentifier> [<DTC 3字节> <statusOfDTC 1字节>] × N 示例:59 02 FF 00 00 03 01 09 (1 个 DTC:0x000301 = P0301,状态 0x09)关键点:
- 没有显式的"DTC 数量"字节——数量由响应总长度推算:
N = (总长度 - 4) / 4; - 每个 DTC 占4 字节(3 字节编号 + 1 字节状态),不是 3 字节;
- 网上常见的"2 字节 DTC 掩码 0xFFFF"是KWP2000 的遗留概念,在 UDS 中不存在。
3.3 子功能 0x04:reportDTCSnapshotRecordByDTCNumber(读快照)
请求:19 04 <DTC 3字节> <snapshotRecordNumber> (5 字节) 示例:19 04 00 03 01 01 (读 P0301 的第 1 组快照) 19 04 00 03 01 FF (FF = 读所有快照记录) 响应:59 04 <DTC 3字节> <statusOfDTC> [<snapshotRecordNumber> <快照数据>] × N- 快照数据的内容(哪些 DID、什么顺序)由 OEM 定义,查诊断规范;
- 如果该 DTC 没有快照,ECU 可能返回空数据或 NRC 0x31。
3.4 子功能 0x06:reportDTCExtendedDataRecordByDTCNumber(读扩展数据)
请求:19 06 <DTC 3字节> <extendedDataRecordNumber>(5 字节) 示例:19 06 00 03 01 01 (读 P0301 的第 1 组扩展数据) 19 06 00 03 01 FE (FE = 读所有扩展数据记录) 19 06 00 03 01 FF (FF = OEM 自定义) 响应:59 06 <DTC 3字节> <statusOfDTC> [<extendedDataRecordNumber> <扩展数据>] × N- 扩展数据典型内容:故障发生次数(occurrence counter)、老化计数(aging counter)、最近一次故障时间等;
- 记录号和内容格式由 OEM 定义。
3.5 子功能 0x15:reportDTCWithPermanentStatus(读永久 DTC)
请求:19 15 (2 字节,无额外参数) 响应:59 15 <DTCFormatIdentifier> [<DTC 3字节>] × N 示例:59 15 00 00 03 01 (1 个永久 DTC:P0301)- 永久 DTC 是排放法规强制的,0x14 服务清不掉;
- 只有故障真实修复、相关监测器重新通过后,ECU 才自动清除;
- 没有永久 DTC 时,响应只有 3 字节:
59 15 <formatId>。
3.6 子功能 0x0A:reportSupportedDTC(读支持的 DTC 全集)
请求:19 0A (2 字节) 响应:59 0A <DTCFormatIdentifier> [<DTC 3字节> <statusOfDTC 1字节>] × N- 返回的是 ECU出厂固有能力——它能检测哪些 DTC;
- 这里的 statusOfDTC 通常全为 0x00(因为不是实际故障状态)。
四、DTC 状态位:8 位定义必须记准
statusOfDTC 是 1 字节 8 位,每一位都有标准定义:
| Bit | 掩码 | 名称 | 含义 |
|---|---|---|---|
| 0 | 0x01 | testFailed | 本检测周期测试失败(≈"当前存在") |
| 1 | 0x02 | testFailedThisOperationCycle | 本运行周期内曾 testFailed |
| 2 | 0x04 | pendingDTC | 待确认 DTC |
| 3 | 0x08 | confirmedDTC | 已确认存储(≈"已存储") |
| 4 | 0x10 | testNotCompletedSinceLastClear | 自上次清除后测试未完成 |
| 5 | 0x20 | testFailedSinceLastClear | 自上次清除后曾 testFailed |
| 6 | 0x40 | testNotCompletedThisOperationCycle | 本运行周期测试未完成 |
| 7 | 0x80 | warningIndicatorRequested | 请求点亮警告灯 |
"当前故障"vs"历史故障"的正确区分
| 目标 | statusMask 用法 | 说明 |
|---|---|---|
| 当前激活的故障 | 19 02 01 | bit0 = 1:testFailed |
| 已确认但当前未检测到("历史") | 19 02 08或19 02 09再筛选 bit0=0 | bit3 = 1 且 bit0 = 0 |
| 所有故障 | 19 02 FF | 全掩码 |
| 等待清除后重新检测的 | 19 02 10 | bit4 = 1 |
⚠️ 网上资料常见的状态位错误:
- "0x02 = 历史激活"——错,bit1 是 testFailedThisOperationCycle;
- "0x04 = 已存储"——错,已存储是bit3(0x08,confirmedDTC);
- 把状态位简化成"0x01 当前、0x02 历史、0x04 存储"三个值——这是对标准的错误简化。
实例解析
响应59 02 FF 00 00 03 01 09:
- 59 = 肯定响应;02 = 子功能;FF = statusMask 回显;00 = DTCFormatIdentifier;
- DTC = 0x000301 →P0301(1 缸失火);
- status = 0x09 = 0x01 + 0x08 =testFailed + confirmedDTC→ 当前激活且已确认存储。
五、DTC 编号格式:3 字节,别写成 2 字节
| 项目 | KWP2000(旧) | UDS(ISO 14229-1) |
|---|---|---|
| DTC 编码长度 | 2 字节 | 3 字节 |
| P0301 的十六进制 | 0x03 0x01 | 0x00 0x03 0x01 |
| statusMask | 2 字节 | 1 字节 |
3 字节 DTC 与 OBD DTC 字符串的对应关系:
0x000301 → P0301(1 缸失火) 0x001001 → B1001(车身控制模块内部故障) 0x00C123 → C0123(底盘类) 0x00U073 → U0073(网络通信类)⚠️ 原文把 P0301 写成 2 字节
0x03 0x01,这是 KWP2000 的格式。在 UDS 里一律 3 字节,否则报文长度就不对,ECU 会报 0x13。
六、标准操作流程:从"读码"到"定位"
以"车辆亮故障灯,排查当前故障"为例:
1. 19 01 FF 统计 DTC 数量(快速判断有没有故障) → 59 01 FF 00 00 02 (2 个) 2. 19 02 FF 读取所有 DTC 列表 → 59 02 FF 00 00 03 01 09 (P0301,testFailed + confirmed) 00 05 22 01 (P0522,testFailed) 3. 19 04 00 03 01 FF 读 P0301 的快照(故障瞬间的转速、水温…) → 59 04 00 03 01 09 01 <快照数据> 4. 19 06 00 03 01 FE 读 P0301 的扩展数据(发生次数、老化计数…) → 59 06 00 03 01 09 01 <扩展数据> 5. 根据 DTC + 快照 + 扩展数据定位故障 → P0301 + 快照显示高转速 → 检查 1 缸点火线圈/火花塞 6. 修复后,19 02 01 确认 testFailed 的 DTC 消失 → 59 02 01 00 (无匹配 DTC) 7. 14 FF FF FF 清除已修复的 DTC(见 14 服务文章) 8. 19 15 确认无永久 DTC 残留 → 59 15 00 (无永久 DTC)要点:
- 快照和扩展数据与具体 DTC 绑定,读取时必须携带 3 字节 DTC 编号;
- 清除前先用 19 服务备份(清掉的数据无法通过 UDS 恢复);
- 修复验证用
19 02 01(只看 testFailed),比19 02 FF更聚焦。
七、NRC 速查表
| NRC | 标准名称 | 典型场景 | 处理 |
|---|---|---|---|
| 0x11 | serviceNotSupported | ECU 不支持 0x19(极罕见) | 查规范 |
| 0x12 | subFunctionNotSupported | 请求了 ECU 不支持的子功能(如低成本 ECU 不支持 0x08) | 换子功能 |
| 0x13 | incorrectMessageLengthOrInvalidFormat | 报文长度不对(如 statusMask 写成 2 字节) | 检查帧长度 |
| 0x31 | requestOutOfRange | DTC 编号不存在、快照记录号超范围 | 核对参数 |
| 0x33 | securityAccessDenied | OEM 加了安全锁(少见,0x19 通常是低权限操作) | 先做 27 服务 |
| 0x7F | serviceNotSupportedInActiveSession | 当前会话不允许(少见) | 切换会话 |
| 0x22 | conditionsNotCorrect | 通用"条件不满足" | 检查前提条件 |
| 0x78 | requestCorrectlyReceived-ResponsePending | "已收到,请稍候" | 不要重发,等最终响应 |
高频误读提醒:
- 0x11 是"服务不支持",不是"子功能不支持"——子功能不支持是0x12;
- 0x81 是 rpmTooHigh,与"存储器损坏"无关;
- 0x78 不是"资源不可用",是"请稍候"的握手信号,正确姿势是等待。
八、传输层:CAN 与 DoIP 没有功能差异
老规矩,澄清一遍:
- DTC 在任何传输层都是 3 字节,statusMask 都是 1 字节。CAN 单帧(8 字节)装
19 02 FF(3 字节请求)绰绰有余; - 响应在任何传输层都只有数值,不含文本描述。DTC 的文字说明在诊断仪本地数据库里;
- 多 DTC 响应超过单帧容量时,CAN 用 ISO 15765-2 多帧传输,DoIP 用 TCP 分段——这是传输层的事,与应用层格式无关;
- 标准编号:
| 标准 | 内容 |
|---|---|
| ISO 14229-1 | 应用层服务定义(本文主体) |
| ISO 14229-2 | 会话层服务 |
| ISO 14229-3 | UDS on CAN |
| ISO 14229-5 | UDS on IP |
| ISO 13400 | DoIP(基于 IP 的诊断传输) |
| ISO 15765-2 | CAN 传输层(多帧) |
九、实战 Checklist
- ✅ 读码顺序:先
19 01(数量)→19 02(列表)→19 04(快照)→19 06(扩展数据); - ✅ DTC 一律 3 字节,statusMask 一律 1 字节;
- ✅ 区分"当前/历史"靠 statusMask 的 bit 组合,不靠子功能号;
- ✅ 永久 DTC 用
19 15读,0x14 清不掉是法规设计; - ✅ 清除前用 19 服务备份;修复验证用
19 02 01; - ❌ 不要期待响应里有 DTC 文本描述;
- ❌ 不要把 0x04 当"读历史故障"、0x06 当"读永久 DTC"、0x08 当"读快照";
- ❌ 不要写 2 字节 DTC 掩码——那是 KWP2000。
十、总结
19 服务的正确画像:
- 子功能丰富:标准定义 29 个,日常用 0x01/0x02/0x04/0x06/0x15 五个就覆盖 90% 场景;
- 格式统一:DTC 3 字节、statusMask 1 字节、响应无文本——跨传输层一致;
- 状态位是关键:8 位定义必须记准,"当前 vs 历史"靠 bit 组合而非子功能号;
- 快照和扩展数据与 DTC 绑定:读取时必须携带 3 字节 DTC 编号。
一句话记住:"19 02 FF 读列表,19 04 读快照,19 06 读扩展,19 15 读永久"——这就是 19 服务的实战四件套。
本文与《彻底搞懂 UDS 14 服务》构成故障诊断闭环:19 服务是"读",14 服务是"清",先读后备份再清,清完再验证。两篇连读效果更佳。