第3章:UDS协议入门:ISO 14229-1基础、服务标识符(SID)分类、诊断会话控制
好,咱们今天聊聊UDS。说实话,我刚入行那会儿,面对ISO 14229-1这个标准文档,第一反应是——这玩意儿也太厚了吧?
但你别怕。UDS(统一诊断服务)说白了,就是汽车ECU之间、或者诊断仪和ECU之间,用来“对话”的一套标准语言。你想想看,车上几十个ECU,每个厂家都有自己的协议,那维修站得备多少种诊断仪?所以ISO 14229-1就出来统一江湖了。
3.1 ISO 14229-1到底在讲什么?
ISO 14229-1,全称是“道路车辆——统一诊断服务——第1部分:应用层”。它定义了一套标准化的诊断服务,不依赖底层通信协议。也就是说,不管你是跑在CAN上、LIN上、还是以太网上,UDS的“话术”是一样的。
我个人习惯把UDS协议栈分成三层来看:
- 应用层:就是ISO 14229-1,定义服务ID、参数、响应格式。
- 会话层/网络层:ISO 15765-2(CAN上的传输层),负责分包、重组、流控。
- 数据链路层:CAN、LIN、FlexRay、以太网等物理传输。
嗯,这里要注意:很多新手把UDS和CAN诊断混为一谈。其实UDS是应用层协议,CAN只是它最常见的载体。我在项目中遇到过有人拿着CANoe抓的报文,非说“这个ID 0x7DF是UDS报文”——其实那是ISO 15765-4定义的物理寻址ID,跟UDS服务本身是两码事。
3.2 服务标识符(SID)分类
SID,Service Identifier,服务标识符。每个UDS服务都有一个唯一的ID,占用一个字节。比如0x10是诊断会话控制,0x22是读取数据,0x2E是写入数据。
ISO 14229-1把SID分成了六大类,我整理了一张表,你一看就明白:
| 类别 | SID范围 | 典型服务 | 说明 |
|---|---|---|---|
| 诊断和通信管理 | 0x10 - 0x3E | 0x10(诊断会话控制)、0x11(ECU复位)、0x3E(Tester Present) | 管理诊断会话、通信状态 |
| 数据传输 | 0x22 - 0x2E | 0x22(读取数据)、0x2E(写入数据)、0x23(读取内存) | 读写DID、内存、故障码 |
| 存储数据传输 | 0x14 - 0x19 | 0x14(清除诊断信息)、0x19(读取DTC信息) | 故障码相关操作 |
| 输入输出控制 | 0x2F - 0x30 | 0x2F(输入输出控制) | 强制控制执行器、模拟输入信号 |
| 远程激活 | 0x31 - 0x31 | 0x31(例程控制) | 启动/停止ECU内部例程 |
| 上传/下载 | 0x34 - 0x37 | 0x34(请求下载)、0x36(传输数据)、0x37(请求退出传输) | 刷写ECU固件 |
你看,每个SID背后都对应着一组具体的操作。比如0x22读取数据,你发出去,ECU就得把对应的DID(数据标识符)值返回来。我曾经调试过一个项目,ECU死活不回0x22的响应,查了半天发现是DID的地址范围配置错了——嗯,这种坑踩过一次就记住了。
重要提示:UDS的响应格式是固定的。请求是SID + 子功能/参数,正常响应是SID+0x40 + 数据,否定响应是0x7F + SID + NRC(否定响应码)。比如你发0x10 01,正常响应是0x50 01,否定响应可能是0x7F 10 12(子功能不支持)。
3.3 诊断会话控制(0x10服务)
0x10服务,DiagnosticSessionControl,是UDS里最基础的服务。为什么说它基础?因为ECU上电后默认处于某个会话状态,你想做其他操作,比如刷写、读故障码,必须先切换到对应的会话。
ISO 14229-1定义了三种标准会话:
- 默认会话(Default Session,0x01):ECU上电后的初始状态。功能受限,只能做基本的诊断服务(比如0x3E Tester Present保活)。
- 编程会话(Programming Session,0x02):用于刷写固件。通常需要安全访问(0x27服务)配合。
- 扩展诊断会话(Extended Diagnostic Session,0x03):用于读写数据、执行例程等。比默认会话开放更多服务。
当然,OEM可以自定义会话,比如0x40~0x5F是留给制造商用的。我在某德系车项目里见过他们自定义了0x40作为“安全调试会话”,只有内部工具才能进入。
会话切换的流程很简单:
请求:0x10 03 // 切换到扩展诊断会话
正常响应:0x50 03 00 32 01 F4 // 0x50是响应,03是子功能,后面是P2和P2*定时参数
否定响应:0x7F 10 12 // 子功能不支持
这里有个细节:正常响应里会带两个定时参数——P2(默认响应时间)和P2*(扩展响应时间)。单位是毫秒。比如00 32表示P2=50ms,01 F4表示P2*=500ms。ECU承诺在这个时间内给出响应,如果超时,诊断仪就得重发或者报错。
避坑指南:我曾经遇到过一个问题:ECU在扩展会话下能正常响应0x22,但一切换到默认会话就报0x7F 22 11(服务不支持)。后来查规范才发现,默认会话下很多服务是被禁用的。所以调试时一定要确认当前会话状态。我的习惯是:每次连接诊断仪后,先发一个0x10 03切换到扩展会话,再开始干活。
3.4 会话状态机与超时管理
ECU内部维护着一个会话状态机。你发0x10切换会话,ECU就进入对应的状态。但如果你不发任何请求,ECU会怎么样?
答案是:它会超时退出。
ISO 14229-1规定,ECU在非默认会话下,如果超过S3定时器(通常5秒)没有收到任何诊断请求(包括0x3E保活报文),就会自动切回默认会话。这是为了防止诊断仪断开后,ECU一直留在高权限的会话里,带来安全风险。
所以,实际项目中,诊断仪需要周期性地发送0x3E(Tester Present)来“保活”。0x3E的格式很简单:
请求:0x3E 00 // 零子功能,表示“我还活着”
正常响应:0x7E 00 // 确认收到
嗯,这里有个小技巧:0x3E的响应是可选的。有些ECU配置成不响应0x3E,以节省总线负载。但诊断仪最好还是按有响应来设计,兼容性更好。
注意:千万不要在刷写过程中让S3超时!我见过一个案例,刷写固件时因为网络延迟,诊断仪没来得及发0x3E,ECU自动切回了默认会话,然后刷写服务被拒绝,导致ECU变砖。后来只能通过Bootloader强制恢复。所以刷写时,建议把0x3E的发送间隔设为1~2秒,留足余量。
3.5 实际项目中的会话管理策略
说了这么多理论,咱们聊聊实际怎么用。
我参与过的一个项目,ECU的会话管理策略是这样的:
- 上电后:进入默认会话,只允许0x3E和0x10服务。
- 收到0x10 03:切换到扩展会话,开放0x22、0x2E、0x19、0x14等服务。
- 收到0x10 02:切换到编程会话,但必须先通过安全访问(0x27)验证,才能执行0x34下载请求。
- S3超时:自动回退到默认会话,并清除所有未完成的诊断任务。
你看,会话控制就像一把钥匙。默认会话是“普通门禁”,扩展会话是“办公室门禁”,编程会话是“机房钥匙”。没有对应的权限,你就进不去。
最后,送你一句话:UDS入门不难,难的是把每个服务的边界条件和异常处理想清楚。0x10服务看似简单,但会话切换的时机、超时处理、安全访问的配合,都是容易出bug的地方。我建议你动手搭个简单的UDS模拟器,从0x10开始,一步步把会话状态机跑通,比看十遍标准文档都管用。
好,这一章就到这儿。下一章咱们聊聊0x22和0x2E——怎么读写ECU里的数据。