3、UDS诊断服务详解:读取数据(0x22),写入数据(0x2E),例程控制(0x31)

各位同学,今天我们聊三个最常用的UDS服务。说实话,这三个服务你搞懂了,车载诊断通信的基本功就算打扎实了。我在项目里调试ECU时,80%的时间都在跟它们打交道。

3.1 读取数据服务(0x22)—— 诊断的“眼睛”

0x22服务,说白了就是“读数据”。你想知道ECU当前的水温、车速、故障码状态?发个0x22请求就行。

报文结构很简单:

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

这里的DID(Data Identifier)就是数据标识符。每个DID对应一个特定的数据。比如0xF190通常代表“当前车速”,0xF191代表“发动机转速”。

我个人习惯:把常用的DID整理成一张表贴在工位上。你想想看,每次查规范多浪费时间?

实际项目中的例子:

// 请求读取VIN码(DID = 0xF190)
发送: 22 F1 90
响应: 62 F1 90 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37
// 响应数据就是17位VIN码的ASCII码

嗯,这里要注意:DID的长度是2字节,但有些老协议里也有1字节的。我建议你统一用2字节,兼容性最好。

3.2 写入数据服务(0x2E)—— 诊断的“手”

0x2E服务,就是“写数据”。你想修改ECU的配置参数?比如调整某个传感器的标定值?用这个服务。

报文结构:

请求: 0x2E + DID(2字节) + 要写入的数据
响应: 0x6E + DID(2字节) + 数据

警告:写入操作有风险!我曾经在测试时,不小心写错了某个DID的值,导致ECU直接进入保护模式,整车无法启动。后来花了半天才恢复出厂设置。

避坑指南:我曾经遇到过一个问题——写入成功后,ECU没有立即生效。为什么?因为有些参数需要“存储到非易失性存储器”才能永久生效。否则断电就丢了。

所以,写入后最好再读回来验证一下。这是基本操作。

// 写入ECU的VIN码(DID = 0xF190)
发送: 2E F1 90 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37
响应: 6E F1 90 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37
// 响应数据与请求数据一致,表示写入成功

3.3 例程控制服务(0x31)—— 诊断的“大脑”

0x31服务,这个有点意思。它用来执行ECU内部的“程序”或“算法”。比如启动自检、擦除内存、执行某个标定流程。

报文结构:

请求: 0x31 + 子功能(1字节) + RID(2字节) + 可选参数
响应: 0x71 + 子功能 + RID + 结果数据

子功能有三种:

  • 0x01:启动例程 —— 开始执行
  • 0x02:停止例程 —— 强制终止
  • 0x03:请求例程结果 —— 查询执行状态

RID(Routine Identifier) 就是例程标识符。比如0xFF00代表“内存擦除”,0xFF01代表“自检”。

小技巧:我建议你在设计例程时,把“启动”和“查询结果”分开。因为有些例程执行时间很长(比如擦除Flash需要几秒),你不能一直阻塞总线。

实际项目中的例子:

// 启动内存擦除例程(RID = 0xFF00)
发送: 31 01 FF 00
响应: 71 01 FF 00 00  // 00表示例程已启动

// 查询例程执行结果
发送: 31 03 FF 00
响应: 71 03 FF 00 01  // 01表示执行成功

3.4 三个服务的对比与选择

你可能会问:什么时候用0x22,什么时候用0x2E,什么时候用0x31?

服务 用途 典型场景 注意事项
0x22 读取数据 读取传感器值、状态、版本号 只读,无副作用
0x2E 写入数据 修改配置参数、标定值 有风险,需验证
0x31 执行例程 自检、擦除、标定流程 可能耗时较长

我个人习惯是:能读就不写,能写就不跑例程。因为例程一旦启动,你无法预知它会不会卡死。我在一个项目里就遇到过,例程启动后ECU死机了,只能断电重启。

3.5 实战中的避坑指南

最后,分享几个我踩过的坑:

  1. DID/RID的合法性检查: 有些ECU对DID有范围限制。你发一个不存在的DID,它会回复0x7F(否定响应)。我建议你提前把支持的DID列表固化在代码里。
  2. 写入数据的长度: 0x2E服务要求数据长度必须与DID定义的长度一致。多一个字节或少一个字节,都会报错。我曾经因为少发了一个字节,排查了半天。
  3. 例程的并发问题: 不要同时启动两个例程。有些ECU不支持并发,会直接拒绝第二个请求。你想想看,如果擦除内存和自检同时进行,系统会乱套的。
  4. 响应超时: 例程执行时间可能很长。我建议你把超时时间设置得宽松一些,比如5秒。否则频繁重试反而会加重ECU负担。

总结一下:0x22、0x2E、0x31是UDS诊断的三大基础服务。读数据、写数据、执行例程,覆盖了90%的诊断场景。你只要把这三个服务吃透,后续的0x19(读取故障码)、0x14(清除故障码)就很容易理解了。

好了,这一章就到这里。下一章我们聊0x19和0x14,这两个服务在故障诊断中非常关键。到时候我会分享一个真实案例——如何通过0x19服务定位一个间歇性故障。