3. UDS服务基础:服务分类、请求与响应机制
好,咱们今天聊聊UDS服务的核心骨架。说实话,UDS(统一诊断服务)是汽车诊断的通用语言。你想想看,不管你是做ECU开发,还是做售后诊断仪,都得跟它打交道。
我个人习惯把UDS比作「医生和病人的对话」。诊断仪是医生,ECU是病人。医生问「你哪里不舒服?」,ECU回答「我这儿疼」。这个一问一答,就是UDS的请求与响应。
3.1 UDS服务分类
UDS服务按功能分成六大类。嗯,这里我列个表,你一看就明白。
| 类别 | SID范围 | 典型服务 | 我常用来干嘛 |
|---|---|---|---|
| 诊断和通信管理 | 0x10 - 0x3E | 10(诊断会话控制)、11(ECU复位)、3E(Tester Present) | 建立连接、保持会话 |
| 数据传输 | 0x22 - 0x2E | 22(读取数据)、2E(写入数据) | 读DTC、读版本号 |
| 存储数据传输 | 0x14 - 0x19 | 14(清除诊断信息)、19(读取DTC信息) | 清故障码、查故障码 |
| 输入输出控制 | 0x2F | 2F(输入输出控制) | 强制驱动某个执行器 |
| 远程激活 | 0x31 | 31(例程控制) | 执行自检、刷写 |
| 上传下载 | 0x34 - 0x37 | 34(请求下载)、36(传输数据)、37(请求退出传输) | 刷写固件 |
我在项目中遇到过最常用的就是0x22和0x2E。说白了,读数据、写数据,占了诊断工作量的80%。
3.2 请求与响应机制
UDS的通信模式很简单:请求-响应。诊断仪发一个请求,ECU必须回一个响应。
请求格式长这样:
请求: [SID] + [Sub-function/数据参数]
响应: [SID+0x40] + [数据]
举个例子,我想读ECU的软件版本号:
请求: 22 F1 90
→ SID=0x22(读取数据)
→ DID=0xF190(软件版本号标识符)
响应: 62 F1 90 01 02 03 04
→ SID=0x62(0x22+0x40)
→ DID=0xF190
→ 数据=01 02 03 04(版本号)
你发现没有?响应的SID永远是请求SID加上0x40。这是UDS的硬性规定。我曾经在调试时遇到一个ECU,它返回的SID不对,结果诊断仪直接不认。嗯,这种低级错误其实挺常见的。
3.3 SID与Sub-function
SID(服务标识符)是1个字节,范围0x00-0xFF。但并不是所有值都能用。UDS标准只定义了部分SID,剩下的留给OEM自定义。
有些服务支持Sub-function(子功能)。比如0x10(诊断会话控制)就有多个子功能:
- 0x01:默认会话(Default Session)
- 0x02:编程会话(Programming Session)
- 0x03:扩展会话(Extended Session)
请求格式变成:
请求: 10 03
→ SID=0x10
→ Sub-function=0x03(扩展会话)
这里有个关键点:Sub-function的最高位(bit 7)是抑制正响应指示位(SPR)。如果bit 7=1,ECU就不回正响应。我建议你在批量刷写时用这个技巧,能省不少总线时间。
重要: 不是所有服务都有Sub-function。比如0x22(读取数据)就没有。你查UDS标准时,注意看服务定义表格里的「Sub-function」列。
3.4 正响应与负响应
ECU收到请求后,要么回正响应,要么回负响应。没有第三种可能。
正响应:SID+0x40,后面跟数据。表示请求成功执行。
负响应:固定格式是 0x7F + 请求SID + NRC。NRC是负响应码,告诉你为什么失败。
常见的NRC有这些:
| NRC | 含义 | 我踩过的坑 |
|---|---|---|
| 0x11 | 不支持请求 | ECU根本没实现这个服务 |
| 0x12 | 子功能不支持 | 比如0x10只支持01和03,你发了02 |
| 0x13 | 消息长度错误 | 多发或少发了字节 |
| 0x22 | 条件不满足 | 比如没进入编程会话就想刷写 |
| 0x31 | 请求超出范围 | DID不存在或数据值非法 |
| 0x78 | 请求正在处理 | ECU需要时间,让你等等 |
注意: 负响应码0x78比较特殊。它表示「我收到了,但还没处理完,你先别急」。诊断仪收到0x78后,应该等待一段时间再重新请求。我曾经见过一个项目,诊断仪收到0x78后直接超时报错,其实是它自己没处理好。
举个例子,你发了一个不支持的SID:
请求: 99 01
→ SID=0x99(ECU不认识)
响应: 7F 99 11
→ 0x7F(负响应标识)
→ 0x99(你请求的SID)
→ 0x11(NRC:不支持请求)
你看,ECU很诚实。它不会假装没收到,而是明确告诉你「我不支持这个服务」。这就是UDS设计的精妙之处——明确的错误反馈。
3.5 避坑指南
我曾经在调试一个ECU时,发现它总是返回0x22(条件不满足)。查了半天,原来是没先发0x10 03进入扩展会话。你想想看,ECU在默认会话下,很多服务是不开放的。所以我的习惯是:先切会话,再发服务。
还有一点:正响应不能保证数据正确。ECU返回0x62 F1 90 01 02 03 04,只代表它成功执行了读取操作,不代表版本号真的是01 02 03 04。数据对不对,你得靠其他手段验证。嗯,这算是诊断工程师的「职业病」吧——永远保持怀疑。
最后,记住一个原则:UDS是面向连接的协议。诊断仪和ECU之间,必须先建立会话,才能做其他操作。就像打电话,你得先拨号接通,才能说话。
好了,这一章的内容就这些。下一章咱们聊聊具体的服务实现,比如怎么用0x22读数据、怎么用0x2E写数据。到时候我会拿实际项目中的代码片段来演示。