4、UDS诊断服务详解(上):读取数据(0x22)、读取故障码(0x19)、写入数据(0x2E)
各位好,欢迎来到实战手册的第四讲。
今天咱们聊聊UDS诊断服务里最常用的三个“老面孔”——0x22、0x19和0x2E。说实话,这三个服务我几乎每天都在用。不管是产线刷写还是售后排查,它们都是绕不开的基础操作。
你想想看,一个TBOX连上车之后,第一件事是什么?肯定是先看看车在说什么。读数据、读故障码、写配置,这三板斧打好了,后面的事情就顺了。
4.1 读取数据(0x22)—— 想查什么就查什么
0x22服务,全称是“ReadDataByIdentifier”。说白了,就是通过一个ID去拿ECU里的某个数据。这个ID叫DID(Data Identifier),每个DID对应一个具体的数据项。
报文结构长什么样?
请求报文很简单:
| 字节 | 内容 | 说明 |
|------|----------------|--------------------------|
| 0 | 0x22 | 服务ID |
| 1-2 | DID (高字节+低字节) | 比如 0xF190 表示VIN码 |
正响应报文:
| 字节 | 内容 | 说明 |
|------|----------------|--------------------------|
| 0 | 0x62 | 服务ID + 0x40 |
| 1-2 | DID | 回显请求中的DID |
| 3..N | 数据 | 实际读取到的数据内容 |
负响应报文:
| 字节 | 内容 | 说明 |
|------|----------------|--------------------------|
| 0 | 0x7F | 负响应固定开头 |
| 1 | 0x22 | 回显请求的服务ID |
| 2 | NRC | 否定响应码 |
常见DID举例:
- 0xF190:VIN码(17字节ASCII)
- 0xF186:ECU硬件版本号
- 0xF187:ECU软件版本号
- 0xF18C:ECU序列号
- 0x0100-0xFFFF:各OEM自定义的DID
我个人习惯,在开发TBOX远程诊断功能时,会把常用的DID整理成一个配置文件。这样换项目时改改配置就行,不用动代码。嗯,这里要注意:不同OEM对DID的定义可能完全不同,千万别拿A项目的DID去B项目用,会出大问题。
小技巧: 如果你要读多个DID,可以用0x22一次请求多个DID吗?答案是不行。0x22一次只能读一个DID。想批量读?后面我们会讲0x23服务,那个是专门干这个的。
4.2 读取故障码(0x19)—— 车到底哪里不舒服?
0x19服务,全称是“ReadDTCInformation”。这个服务比0x22复杂多了,因为它有子功能(SubFunction)。
为什么会这样?因为故障码的信息太丰富了。你不仅要读当前故障码,还要读历史故障码、故障发生时的快照数据、故障发生的次数等等。一个服务ID搞不定,所以用子功能来区分。
最常用的子功能:
| 子功能(SubFunction) | 含义 | 说明 |
|---|---|---|
| 0x01 | 读取当前故障码数量 | 返回当前激活的DTC个数 |
| 0x02 | 读取当前故障码 | 返回所有当前激活的DTC列表 |
| 0x0A | 读取所有故障码(含历史) | 返回所有存储的DTC |
| 0x04 | 读取故障码快照数据 | 返回故障发生时的环境数据 |
| 0x06 | 读取故障码扩展数据 | 返回故障发生次数、老化计数器等 |
举个例子,读当前故障码:
请求: 0x19 0x02
响应: 0x59 0x02 [DTC1高字节] [DTC1低字节] [状态字节] [DTC2高字节] [DTC2低字节] [状态字节] ...
这里的状态字节很关键。它用8个bit告诉你这个故障码的“身世”:
- Bit 0:测试失败(当前有故障)
- Bit 1:当前故障(确认过)
- Bit 2:历史故障(曾经有过)
- Bit 3:老化计数器
- Bit 4-7:保留位
注意: 我曾经在项目里踩过一个坑——读故障码时只看了Bit0,以为没故障就完事了。结果客户反馈说车偶尔报故障,查了半天才发现是历史故障码没清。所以,读故障码时一定要看完整的状态字节,尤其是Bit2(历史故障)和Bit3(老化计数器)。
另外,0x19服务还有一个很实用的功能——读取故障码快照数据(子功能0x04)。这个数据记录了故障发生那一瞬间的车辆状态,比如车速、水温、发动机转速等。对于远程诊断来说,这个数据太重要了。我经常跟团队说:“没有快照数据的故障码,就像没有监控录像的事故现场,你永远不知道当时发生了什么。”
4.3 写入数据(0x2E)—— 给ECU“写纸条”
0x2E服务,全称是“WriteDataByIdentifier”。和0x22正好相反,它是往ECU里写数据的。
报文结构:
请求: 0x2E [DID高字节] [DID低字节] [数据...]
响应: 0x6E [DID高字节] [DID低字节] [数据...]
看起来很简单对吧?但这里有个大坑——不是所有DID都能写。有些DID是只读的,你写进去ECU会给你一个NRC(否定响应码)。
常见的NRC:
| NRC | 含义 | 说明 |
|---|---|---|
| 0x31 | 请求超出范围 | DID不存在或数据格式不对 |
| 0x72 | 写入条件不满足 | 比如需要先进入扩展会话才能写 |
| 0x13 | 数据长度错误 | 你给的数据长度和DID定义的不一致 |
避坑指南: 我曾经在远程刷写配置时,用0x2E写一个DID,结果一直返回0x72。查了半天才发现,那个DID需要在“扩展会话模式”下才能写。所以,写数据之前一定要确认两件事:1)当前会话模式对不对;2)安全访问(Security Access)解锁了没有。
实际应用场景:
- 写VIN码:产线刷写时,用0x2E把VIN码写入ECU
- 写配置参数:比如远程修改TBOX的上报周期、服务器地址等
- 写个性化设置:比如调整座椅记忆、灯光模式等
你想想看,如果没有0x2E服务,那TBOX的远程配置功能就完全没法实现了。每次改配置都得去4S店用诊断仪连车,多麻烦。
4.4 三个服务的协作关系
这三个服务在实际项目中经常配合使用。我举个例子:
- 先用0x19读故障码,发现某个传感器报“电压过高”
- 再用0x22读该传感器的实时电压值,确认当前状态
- 最后用0x2E写入一个校准参数,调整传感器的阈值
你看,读故障码发现问题,读数据确认问题,写数据解决问题。一套组合拳下来,远程诊断就闭环了。
总结一下:
- 0x22:读数据,一次一个DID,简单直接
- 0x19:读故障码,子功能多,信息丰富
- 0x2E:写数据,注意会话模式和权限
好了,这一讲就到这里。下一讲我们会继续聊UDS诊断服务的“下半场”——0x23(批量读取)、0x14(清除故障码)和0x10(诊断会话控制)。这些服务在远程诊断中同样重要,咱们到时候再细聊。
记住一句话:诊断服务是TBOX和ECU沟通的“语言”,把这门语言学好了,远程诊断功能开发就成功了一半。