4. UDS协议栈架构

上一章我们把UDS的会话控制和安全访问讲透了。这一章咱们继续往下走,聊聊实际开发中最常用的几个服务——读数据、写数据、读DTC、清DTC。

说实话,这几个服务你几乎每天都会打交道。不管是产线刷写、售后诊断,还是研发阶段的调试,都离不开它们。我个人习惯把这几个服务分成两组:数据访问组(0x22、0x2A、0x2E)和故障管理组(0x19、0x14)。

核心要点: 0x22/0x2E是基础读写,0x2A是周期上报,0x19/0x14是DTC的增删查。理解它们的请求/响应格式和子功能,是诊断开发的基本功。
第4章 UDS服务知识结构 UDS诊断服务(第4章) 数据访问组 0x22 读数据 0x2A 周期读 0x2E 写数据 故障管理组 0x19 读DTC 0x14 清DTC 开发要点 • 0x22/0x2E:DID是核心,注意数据长度和格式 • 0x2A:周期上报的调度策略影响总线负载 • 0x19/0x14:子功能多,状态掩码和组号要搞清

4.1 读取数据(0x22)—— 最常用的诊断服务

0x22服务,说白了就是让诊断仪读取ECU内部的数据。这些数据通过数据标识符(DID)来索引。每个DID对应一个特定的数据对象,比如ECU序列号、软件版本、当前车速、电池电压等等。

请求格式很简单:

请求:0x22 + DID(2字节)
响应:0x62 + DID + 数据内容

举个例子,读取ECU序列号(假设DID = 0xF190):

请求:22 F1 90
响应:62 F1 90 41 42 43 44 45 46 47 48
      ("ABCDEFGH"的ASCII码)
我的经验: DID的分配一定要提前规划好。我在一个项目里见过DID编号混乱,导致产线工具和售后工具不兼容。建议按功能模块划分DID区间,比如0xF1xx给系统信息,0xF2xx给传感器数据,0xF3xx给配置参数。

0x22服务支持一次请求读取多个DID。但要注意,每个DID的数据长度必须固定,否则ECU无法正确解析响应。我建议在诊断规范里明确每个DID的数据类型和长度,避免后期扯皮。

4.2 读取数据周期(0x2A)—— 自动上报的利器

0x2A服务是0x22的升级版。它让ECU按照指定的周期,自动上报DID数据。这在实时监控场景下特别有用,比如标定工程师想看某个信号的变化趋势。

0x2A有三个子功能:

子功能 含义 说明
0x01 开始周期上报 指定DID和上报周期(单位ms)
0x02 停止周期上报 停止指定DID的周期上报
0x03 读取当前周期上报配置 返回当前正在上报的DID列表

请求格式:

开始上报:2A 01 + DID + 周期(2字节,单位ms)
停止上报:2A 02 + DID
读取配置:2A 03
注意: 0x2A服务对ECU的实时性要求很高。我曾经遇到过一个项目,ECU的调度周期是10ms,但客户要求5ms上报一次数据,结果导致CAN总线被占满,其他报文都发不出去。所以,上报周期一定要大于ECU的最小调度周期,一般建议至少是调度周期的2倍。

另外,0x2A服务通常只在扩展会话(0x03)下可用。这是出于安全考虑,防止正常运行时被误触发。

4.3 写入数据(0x2E)—— 改参数、刷配置

0x2E服务用来向ECU写入数据。它和0x22是一对儿,一个读一个写。请求格式:

请求:2E + DID + 数据内容
响应:6E + DID + 数据内容(回显)

举个例子,写入ECU的VIN码(假设DID = 0xF190):

请求:2E F1 90 31 32 33 34 35 36 37 38
      ("12345678"的ASCII码)
响应:6E F1 90 31 32 33 34 35 36 37 38
关键点: 0x2E服务通常需要先进入安全访问(0x27)状态。否则ECU会返回否定响应(NRC = 0x33,安全访问被拒绝)。这是为了防止非授权修改。

我个人习惯把0x2E服务分为两类:

  • 运行时参数: 比如调整某个控制算法的系数,修改后立即生效,但掉电丢失。
  • 持久化参数: 比如VIN码、配置字,修改后需要写入非易失性存储器(EEPROM/Flash),掉电不丢失。

对于持久化参数,写入次数有限制(Flash有擦写寿命)。我在一个量产项目里就遇到过,产线反复写入VIN码导致Flash提前报废。后来我们加了一个保护机制:只有VIN码为空时才允许写入,否则返回NRC 0x72(一般编程失败)。

4.4 读取DTC信息(0x19)—— 故障诊断的核心

0x19服务是UDS里最复杂的服务之一。它用来读取ECU中存储的故障码(DTC)及其相关信息。0x19有28个子功能,但常用的就几个:

子功能 含义 常用场景
0x01 读取DTC数量(按状态掩码) 快速了解当前有多少故障
0x02 读取DTC列表(按状态掩码) 获取所有故障码
0x03 读取DTC快照数据 故障发生时的环境数据
0x04 读取DTC扩展数据 故障发生次数、老化计数器等
0x06 读取DTC(按组号) 按故障类型分组查询
0x0A 读取所有DTC(支持多个状态掩码) 一次性获取所有故障信息

状态掩码(Status Mask)是0x19服务的核心概念。每个DTC都有一个1字节的状态字节,各位含义如下:

位 含义 说明
Bit 0 测试失败 当前诊断测试失败
Bit 1 本次操作周期测试失败 当前驾驶循环内测试失败
Bit 2 已确认的故障 故障被确认并存储
Bit 3 未确认的故障 故障尚未被确认
Bit 4 测试完成 诊断测试已执行完毕
Bit 5 本次操作周期测试未完成 当前驾驶循环内测试未完成
Bit 6 警告指示灯请求 请求点亮故障灯(MIL)
Bit 7 待处理故障 故障待处理
避坑指南: 我曾经在项目里遇到一个问题:售后工具读取DTC时,总是读不到已确认的故障。后来发现是状态掩码写错了。0x19的0x02子功能,状态掩码是按位与的。比如你想读所有已确认的故障(Bit 2 = 1),掩码应该是0x04,而不是0x02。这个细节很容易搞混。

快照数据(Snapshot Data)是0x19的另一个重要功能。它记录了故障发生时的环境数据,比如车速、发动机转速、冷却液温度等。这些数据对故障分析非常有帮助。

4.5 清除DTC信息(0x14)—— 一键恢复出厂

0x14服务用来清除ECU中存储的DTC信息。请求格式很简单:

请求:14 + 组号(1字节)
响应:54 + 组号

组号(Group Number)用来指定要清除哪些DTC:

组号 含义
0x00 清除所有DTC
0x01 - 0xFE 清除指定组的DTC(由OEM定义)
0xFF 清除所有DTC(包括历史记录)
重要提醒: 0x14服务会清除DTC的状态字节、快照数据、扩展数据等所有相关信息。执行后,ECU的故障存储区会被清空。所以,一定要在安全访问状态下才能执行。另外,清除DTC后,ECU会重新运行所有诊断测试,可能会产生新的故障码。

我在一个量产项目里遇到过一个问题:产线在刷写完成后,会执行0x14服务清除所有DTC。但有个ECU在清除后,立即报了一个新的故障码。后来发现是诊断测试的时序问题——清除DTC后,某些测试条件还不满足,导致误报。解决方案是在清除DTC后,延迟一段时间再启动诊断测试。

4.6 本章小结

这一章我们聊了五个核心服务:

  • 0x22(读取数据): 通过DID读取ECU内部数据,支持多DID读取。
  • 0x2A(读取数据周期): 让ECU按周期自动上报数据,适合实时监控。
  • 0x2E(写入数据): 向ECU写入数据,通常需要安全访问。
  • 0x19(读取DTC信息): 读取故障码及其状态、快照、扩展数据。
  • 0x14(清除DTC信息): 清除ECU中的故障码信息。