
在实际车载诊断项目里第一次接触 UDS 的朋友看到“19 02 FF”或“19 04 0A 05 01”这类报文时很容易被参数和响应结构绕晕。19 服务是 UDS 中读取故障码信息的核心服务涵盖数量统计、故障码列表、快照记录、扩展数据等多个子功能。本文以 19 服务的 01、02、04、06 四个高频子功能为主线结合请求报文和正/负响应报文实例完整拆解每一帧的含义、参数设计和排查思路。如果你是刚接触 UDS 诊断协议的学生、测试工程师或者正在做 ECU 刷写、产线检测、售后诊断工具开发的开发者这篇文章都适用。看完之后你不仅知道“怎么发”还能理解“为什么这样设计”。1. 19服务是什么从UDS诊断体系说起1.1 UDS诊断协议定位UDSUnified Diagnostic Services统一诊断服务是 ISO 14229 标准定义的一套汽车诊断协议目前在整车电子电气架构中基本属于标配。它在 OSI 七层模型中位于应用层底层可以承载在 CAN、CAN FD、LIN、以太网DoIP等不同的传输层协议上。在 UDS 的协议框架里服务通过 SIDService Identifier服务标识符区分。例如 0x10 是诊断会话控制0x22 是按标识符读取数据0x27 是安全访问0x14 是清除故障码0x19 则是读取故障码信息。每个服务还可以细分为不同的子功能19 服务是整个 UDS 体系中结构最丰富、使用频率最高的服务之一。故障码的产生、确认、恢复、历史存储、环境数据记录都要依赖 19 服务来读取。1.2 19服务解决什么问题ECUElectronic Control Unit电子控制单元在运行过程中会持续监控传感器、执行器、通信链路的状态。当某个监测项超出阈值或逻辑不满足时ECU 内部会记录一个 DTCDiagnostic Trouble Code诊断故障码并在状态字节中标记故障类型。但记录 DTC 只是第一步诊断人员还需要知道当前 ECU 一共存了多少条 DTC这些 DTC 是当前激活的还是历史残留的每个 DTC 对应的故障状态、发生次数、行驶里程、环境温度等附加信息是什么怎么在清除 DTC 之前把现场数据保存下来方便复现和分析这些诉求全部由 19 服务来承载。所以 19 服务的核心定位就是按条件读取 DTC 相关信息。1.3 19服务子功能总览19 服务下有多个子功能不同子功能获取的信息粒度不同。本文重点讲解实际项目中最常用的 4 个子功能名称作用0x01reportNumberOfDTCByStatusMask按状态掩码统计 DTC 数量0x02reportDTCByStatusMask按状态掩码返回 DTC 列表0x04reportDTCSnapshotRecordByDTCNumber返回指定 DTC 的快照记录0x06reportDTCExtDataRecordByDTCNumber返回指定 DTC 的扩展数据记录简单理解01 是“数一下有多少条”02 是“把故障码列出来”04 是“查看某个故障码发生时的现场快照”06 是“查看某个故障码的附加统计信息”。这几类信息组合起来基本能覆盖故障诊断和售后分析的绝大多数场景。2. 必须理解的基础概念DTC、状态字节与状态掩码2.1 DTC常见格式在传统 CAN 诊断系统中最常用的是 ISO 15031-6 规定的 2 字节 DTC 格式。例如 0x0A05、0x0A06、0x12AA 这类数值。2 字节 DTC 中的高 2 位用于表示故障类型例如00P 开头动力系统01C 开头底盘系统10B 开头车身系统11U 开头网络通信系统剩余位用于表示具体的故障编号和子类型。随着 ISO 14229-1:2020 标准的更新DTC 也可以使用 3 字节格式其中第三字节用于描述故障的具体类型例如“信号无效”“信号超时”“信号不合理”等。目前很多新平台已经在使用 3 字节 DTC但对于老平台和现产车2 字节 DTC 仍然大量存在。在 19 服务的响应中DTCFormatIdentifierDTC 格式标识符字段用于告知调用方当前 ECU 使用的 DTC 格式。例如 0x00 通常表示 ISO 14229-1 定义的标准格式。读者在实际开发时必须先确认目标项目使用的是 2 字节还是 3 字节 DTC否则解析 DTC 列表时会出现错位。2.2 DTC状态字节每一位的含义DTC 状态字节是 19 服务中最重要的概念之一。它不只表示“是不是有故障”而是一个包含 8 个独立含义的位域每一位都代表一种诊断状态。以 2 字节 DTC 1 字节状态为例状态字节定义如下Bit掩码值含义bit00x01testFailed最近一次测试失败bit10x02testFailedThisOperationCycle当前操作循环中测试失败bit20x04pendingDTC待确认故障码bit30x08confirmedDTC已确认故障码bit40x10testNotCompletedSinceLastClear上次清除后测试未完成bit50x20testFailedSinceLastClear上次清除后测试失败过bit60x40testNotCompletedThisOperationCycle当前操作循环测试未完成bit70x80warningIndicatorRequested请求点亮故障指示灯实际报文中一个状态字节可能同时包含多位。例如 0x45 表示 bit0、bit2、bit6 置位即“最近测试失败 待确认 当前循环未完成”。这里的组合逻辑完全取决于故障检测策略不同 ECU 可能给出不同的状态组合。2.3 状态掩码如何筛选目标DTC19 服务的 01 和 02 子功能都要求调用方传入一个状态掩码用于筛选想要查看的 DTC。例如状态掩码 0xFF匹配所有状态位返回全部 DTC。状态掩码 0x08只匹配 confirmedDTC 位即只返回已确认的 DTC。状态掩码 0x04只匹配 pendingDTC 位即只返回待确认的 DTC。状态掩码 0x29匹配 bit0、bit3、bit5即返回最近测试失败且已确认的 DTC。筛选的原理是对状态字节做按位与运算。只要状态字节与掩码的与结果不为 0该 DTC 就满足查询条件。这里容易误以为 19 服务返回的 DTC 状态必须完全等于掩码值实际上并不是正确理解是“状态字节与掩码按位与后非 0”。因此在工程中查询“所有 DTC”时一般直接使用 0xFF查询“有效故障”时优先使用包含 confirmedDTCbit3的掩码例如 0x09 或 0x0D查询“历史故障”时配合 testFailedSinceLastClearbit5、confirmedDTCbit3等位一起判断。2.4 会话控制与安全访问预备知识19 服务通常在默认会话下就允许调用但存在一些限制部分 ECU 只在扩展诊断会话或编程会话下开放 19 服务的某些子功能。读取某些敏感 DTC 或环境数据时可能需要先执行 0x27 安全访问完成解锁后再发 19 请求。如果车辆处于行驶模式或总线通信繁忙状态ECU 可能因为内部条件不满足返回 NRC 0x22conditionsNotCorrect。所以在排查 19 服务异常响应时不要一上来就怀疑报文格式先确认当前诊断会话状态以及是否已解锁安全访问。这也是很多初学者最容易忽略的点。3. 子功能01报告DTC数量3.1 功能说明与请求格式子功能 01 的名称是 reportNumberOfDTCByStatusMask作用是让 ECU 统计符合条件的 DTC 数量。它只返回数量不返回具体 DTC 内容因此报文很短。请求报文格式如下字节位置内容说明byte00x19SID读 DTC 信息byte10x01子功能报告 DTC 数量byte2状态掩码筛选规则例如 0xFF举一个最简单的例子发一帧 CAN 请求19 01 FF0x19服务 ID0x01子功能 010xFF状态掩码匹配所有状态这里如果使用物理寻址请求报文 ID 通常是指向目标 ECU 的诊断物理请求 ID例如 0x7E0实际值取决于整车网络设计。如果使用功能寻址例如 0x7DF总线上的多个 ECU 都可能响应需要特别注意响应冲突。3.2 正响应报文结构ECU 收到 19 01 请求后如果支持该子功能且参数合法会返回正响应字节位置内容说明byte00x59正响应 SID等于请求 SID 0x40byte10x01子功能回显byte2DTCFormatIdentifierDTC 格式标识byte3numberOfDTC_HighByteDTC 数量高字节byte4numberOfDTC_LowByteDTC 数量低字节byte5statusOfDTC回显请求中的状态掩码其中 numberOfDTC 是两字节大端整数最大可以表示 65535 个 DTC。statusOfDTC 字段回显请求掩码用于告诉调用方这个数量是基于什么筛选条件统计出来的。3.3 报文实例假设某个 BMS电池管理系统内存有两条 DTC0x0A05 和 0x0A06发送 19 01 FF 后正响应示意如下59 01 00 00 02 FF逐字节解析0x59正响应 SID0x01子功能回显确认是 01 的响应0x00DTCFormatIdentifier表示 ISO 14229-1 标准格式0x00 0x02DTC 数量为 20xFF回显状态掩码 0xFF如果发送 19 01 04只统计 pendingDTC 状态的故障码而当前只有 0x0A05 处于 pending 状态响应就可能是59 01 00 00 01 04这里 DTC 数量变成了 1状态掩码回显为 0x04。通过这种方式诊断仪可以在不获取完整 DTC 列表的情况下快速判断是否存在某个状态下的故障码。4. 子功能02报告DTC4.1 功能说明与请求格式子功能 02 的名称是 reportDTCByStatusMask作用是按状态掩码返回 DTC 列表以及每个 DTC 的状态字节。这是诊断工具显示故障码列表时最常用的请求。请求报文格式如下字节位置内容说明byte00x19SIDbyte10x02子功能报告 DTCbyte2状态掩码筛选规则例如 0xFF示例请求19 02 FF这条报文的意思是把当前 ECU 存储的所有 DTC 和状态返回给我。4.2 正响应报文结构19 02 的正响应相对复杂一些因为它包含了一个变长的 DTC 列表。以 2 字节 DTC 格式为例字节位置内容说明byte00x59正响应 SIDbyte10x02子功能回显byte2状态掩码回显请求中的 statusOfDTCbyte3DTCFormatIdentifierDTC 格式标识byte4~byte5numberOfDTCDTC 总数量byte6~byte8DTC1 Status1第 1 条 DTC 和状态byte9~byte11DTC2 Status2第 2 条 DTC 和状态......以此类推每条 DTC 记录由 3 字节组成2 字节 DTC 号 1 字节状态。如果响应很长底层传输层会按照 ISO-TP 协议拆分成多帧发送。4.3 报文实例继续使用上述 BMS 的示例。请求19 02 FF假设 ECU 返回单帧正响应59 02 FF 00 00 02 0A 05 45 0A 06 0A逐字节解析0x59正响应 SID0x02子功能回显0xFF状态掩码回显0x00DTC 格式标识0x00 0x02共有 2 条 DTC0x0A 0x05第 1 条 DTC 是 0x0A050x45DTC 0x0A05 的状态字节示例状态值为 450x0A 0x06第 2 条 DTC 是 0x0A060x0ADTC 0x0A06 的状态字节示例状态值为 0A这里 0x45 表示 0100 0101即 bit0、bit2、bit6 置位代表“最近测试失败”“待确认”“当前循环测试未完成”。0x0A 表示 0000 1010即 bit1、bit3 置位代表“当前循环测试失败”且“已确认”。实际项目中状态字节的具体含义需要结合故障监测策略判断。如果只查询已确认故障码请求为19 02 08响应可能只剩已确认的 DTC59 02 08 00 00 01 0A 06 0A这里返回了 1 条 DTC说明只有 0x0A06 处于 confirmed 状态。4.4 多帧响应与缓冲区不足的处理当 DTC 列表数量较大或者 DTC 状态数据结构较长时单帧 CAN 报文可能放不下底层会自动使用 ISO-TP 多帧传输。在 CAN 2.0 中单帧数据场最多 8 字节而 19 02 的正响应很可能超过 8 字节因此大部分项目都会进入多帧流程。多帧传输包括首帧、连续帧和流控帧。工具侧需要正确解析 ISO-TP 层才能把多个连续帧拼接成完整数据再交给上层解析 19 02 的有效载荷。如果在 CANoe 等工具中看到 19 02 响应只返回了前半部分通常是因为没有正确配置 ISO-TP 接收缓冲区。测试工具的网络层没有启用接收流控能力。请求中未要求 ECU 拆分传输。另外需要注意19 02 响应中把 numberOfDTC 放在 DTC 列表前面是为了让上位机可以预估数据长度。但由于一帧 CAN 报文很难装下全部 DTC上位机不能只根据首帧长度判断列表结束必须按 numberOfDTC 字段循环解析完整 DTC 记录。5. 子功能04报告快照记录5.1 快照记录的概念和用途快照记录Snapshot Record是故障发生瞬间 ECU 保存的一批环境数据。比如单体电压、SOC、电池温度、车速、总里程、系统电压等。快照记录的意义在于故障发生后很多现场信息会随工况变化而消失。诊断人员通过读取快照可以还原故障发生时的“现场”从而判断故障原因。这是一种非常关键的诊断手段。每个 DTC 可以关联一个或多个快照记录快照记录编号从 1 开始。不同的快照记录可能代表不同工况或不同故障分类下的环境数据。5.2 请求报文结构子功能 04 的请求必须指定 DTC 号和快照记录号字节位置内容说明byte00x19SIDbyte10x04子功能报告快照记录byte2~byte3DTC number目标 DTC例如 0x0A05byte4快照记录号0x01 表示第 1 条快照0xFF 表示全部示例请求19 04 0A 05 01含义读取 DTC 0x0A05 的第 1 条快照记录。5.3 正响应报文结构19 04 正响应包含 DTC 信息以及一个快照记录参数列表。由于快照的数据内容由 OEM 自定义所以参数标识符、参数长度和参数值都无法一概而论。报文中必须通过“参数标识符 参数长度 参数值”的方式组织数据上位机才能逐个解析。典型的正响应结构如下字节位置内容说明byte00x59正响应 SIDbyte10x04子功能回显byte2~byte3DTC number当前 DTCbyte4statusOfDTCDTC 当前状态byte5snapshotRecordNumber当前快照记录号byte6参数项数量该快照中包含的参数个数byte7~byteN参数列表多个“参数ID 参数长度 参数值”快照记录的核心是参数列表。只要数据组织方式一致诊断工具就能把其中所有参数解析出来并以表格或曲线形式展示给用户。5.4 报文实例假设 DTC 0x0A05 的第 1 条快照包含两个参数电池组最高电压参数标识符 0x01长度 2 字节和电池组最高温度参数标识符 0x02长度 1 字节。请求19 04 0A 05 01正响应示例59 04 0A 05 45 01 02 01 02 03 E8 02 01 5A逐字节解析0x59正响应 SID0x04子功能回显0x0A 0x05DTC 为 0x0A050x45DTC 当前状态字节0x01当前快照记录号0x02该快照包含 2 个参数0x01第 1 个参数的标识符表示“电池组最高电压”0x02参数长度为 2 字节0x03 0xE8参数值即电压 1000单位 0.1V实际为 100.0V0x02第 2 个参数的标识符表示“电池组最高温度”0x01参数长度为 1 字节0x5A参数值即温度 90单位 1℃实际为 90℃从这个例子可以看出19 04 的难点并不在于协议本身而在于参数标识符和参数长度的 OEM 自定义规则。开发诊断工具时需要先拿到对应 ECU 的诊断规范或 DBC/CDD 文件才能正确翻译快照数据。6. 子功能06报告扩展数据记录6.1 扩展数据记录的概念和用途扩展数据记录Extended Data Record也是附加在 DTC 上的信息但和快照记录略有不同。快照记录强调的是“故障发生瞬间的环境数据”扩展数据则更偏向“统计与累计信息”。常见的扩展数据包括故障出现次数故障老化计数器故障第一次发生的时间或里程故障最后一次发生的时间或里程故障连续激活次数内存中循环测试的累计次数扩展数据主要用于故障频次分析和老化评估。售后场景中通过扩展数据可以知道某个故障码是偶发还是持续是刚出现还是已经存在很长时间。6.2 请求报文结构子功能 06 的请求格式与 04 非常相似也需要 DTC 号和扩展数据记录号字节位置内容说明byte00x19SIDbyte10x06子功能报告扩展数据记录byte2~byte3DTC number目标 DTCbyte4扩展数据记录号0x01 表示第 1 块扩展数据0xFF 表示全部示例请求19 06 0A 05 01含义读取 DTC 0x0A05 的第 1 块扩展数据记录。6.3 正响应报文结构19 06 的正响应与 19 04 类似字节位置内容说明byte00x59正响应 SIDbyte10x06子功能回显byte2~byte3DTC number当前 DTCbyte4statusOfDTCDTC 当前状态byte5扩展数据记录号当前记录号byte6~byteN扩展数据参数参数长度与参数值与快照记录一样扩展数据的具体内容由 ECU 诊断规范定义不同厂商的差异很大。例如同一个“故障出现次数”字段在 A 厂商的 ECU 里可能使用 2 字节在 B 厂商的 ECU 里可能使用 4 字节。开发工具时必须以目标 OEM 的规范为准。6.4 报文实例假设 DTC 0x0A05 的第 1 块扩展数据只有一项故障出现次数长度 2 字节当前值为 100x000A。请求19 06 0A 05 01正响应示例59 06 0A 05 45 01 01 02 00 0A逐字节解析0x59正响应 SID0x06子功能回显0x0A 0x05DTC 为 0x0A050x45DTC 当前状态字节0x01扩展数据记录号0x01当前扩展数据项数量为 10x02数据长度 2 字节0x00 0x0A故障出现次数为 10如果 ECU 把故障出现次数放在偏移固定位置也可能不返回参数标识符而直接返回定长数据。例如某些 OEM 会规定扩展数据记录按固定字节结构排列这样上位机只需要按照字节偏移去解析即可。所以 19 06 的响应格式会有“定长结构”和“TLV 结构”两种常见形态必须在开发前确认。7. 负响应与常见NRC梳理7.1 NRC报文格式当 ECU 无法处理请求时不会返回 0x59 开头的正响应而是返回负响应报文字节位置内容说明byte00x7F负响应 SIDbyte10x19原始服务 ID表示是 19 服务的负响应byte2NRC负响应码例如