2. 诊断请求与响应机制:SID分类、报文格式与NRC机制
各位同学,咱们今天聊聊诊断通信里最核心的“对话规则”。说白了,就是ECU怎么听懂你发的指令,以及它该怎么回你。
我刚开始做UDS开发时,总觉得协议栈是现成的,写写应用层就行。结果第一次实车测试就栽了跟头——发出去的请求石沉大海,ECU连个负响应都不给。后来才发现,是我对SID的理解太浅了。
好,咱们一步步拆解。
2.1 SID(服务标识符)分类
SID就是一个字节,范围0x00到0xFF。但UDS协议只用了其中一部分。我个人习惯把它们分成三大类:
- 诊断与通信管理类(0x10~0x3E):比如会话控制(0x10)、ECU复位(0x11)、安全访问(0x27)等。这些是“基础设施”,先得把通信通道打通。
- 数据传输类(0x22~0x2E):比如按标识符读取数据(0x22)、按地址读取内存(0x23)、写入数据(0x2E)。这是最常用的,读故障码、读版本号都靠它们。
- 存储与程序管理类(0x2F~0x37):比如输入输出控制(0x2F)、例程控制(0x31)、下载请求(0x34)等。刷写程序、做执行器测试时用得多。
你想想看,ECU收到一个字节,它得先判断:这个SID我支持吗?如果不支持,直接回NRC 0x11(服务不支持)。
重要提醒:每个SID都有对应的“正响应SID”,规则是:正响应SID = 请求SID + 0x40。比如请求0x22,正响应就是0x62。这是协议规定的,别记反了。
2.2 请求报文格式
一个标准的诊断请求报文长这样:
| SID (1字节) | Sub-function (可选, 1字节) | 数据参数 (N字节) |
举个例子,读取ECU的VIN码(假设DID为0xF190):
请求: 22 F1 90
- 0x22: 按标识符读取数据服务
- 0xF1: DID高字节
- 0x90: DID低字节
嗯,这里要注意:有些服务带子功能(Sub-function),比如0x10(诊断会话控制)。子功能字节的低4位是功能位,高4位是抑制正响应位(bit 7)。
我曾经在项目里踩过一个坑:发送0x10 0x03想进入扩展会话,结果ECU没反应。查了半天才发现,0x03的bit7是0,但我的报文长度写错了。记住,子功能字节是必须的,不能省略。
2.3 正响应机制
ECU处理完请求,如果一切正常,就回正响应。格式是:
| 正响应SID (1字节) | 数据参数 (N字节) |
还是读VIN的例子:
请求: 22 F1 90
正响应: 62 F1 90 4C 45 41 50 ... (VIN码ASCII)
看到没?正响应SID是0x62,后面跟着DID和实际数据。我建议你在设计测试用例时,先验证正响应路径——如果正响应都拿不到,就别谈负响应处理了。
2.4 负响应(NRC)机制
这是诊断通信里最“有意思”的部分。ECU说“不行”,但得告诉你为什么不行。负响应报文格式:
| 0x7F (1字节) | 请求SID (1字节) | NRC码 (1字节) |
比如:
请求: 22 F1 90
负响应: 7F 22 31
- 0x7F: 负响应标识
- 0x22: 请求的SID
- 0x31: NRC码,表示“请求超出范围”
常见的NRC码我列个表:
| NRC码 | 含义 | 典型场景 |
|---|---|---|
| 0x11 | 服务不支持 | ECU没实现这个SID |
| 0x12 | 子功能不支持 | SID支持,但子功能没实现 |
| 0x13 | 报文长度或格式错误 | 多发了或少发了字节 |
| 0x22 | 条件不满足 | 没进入正确会话就发请求 |
| 0x31 | 请求超出范围 | DID不存在或数据值非法 |
| 0x35 | 安全访问拒绝 | 没解锁就写数据 |
| 0x78 | 请求正确但正在处理 | ECU需要时间,稍后再问 |
避坑指南:我曾经遇到一个ECU,发送0x22读DID时,它回0x7F 0x22 0x13。我查了半天报文格式,完全正确。最后发现是CAN ID配错了——诊断请求发到了功能寻址,但ECU只响应物理寻址。所以,NRC 0x13不一定真是格式问题,也可能是通信层的问题。
2.5 知识体系总览
下面这张图,是我自己总结的诊断请求与响应核心逻辑。你把它存脑子里,调试时能少走很多弯路。
个人小技巧:调试时如果ECU不回任何响应,先检查CAN物理层和ID配置。如果回了0x7F,别慌——把NRC码查一下,90%的问题都能定位。我习惯在代码里打印出完整的请求和响应报文,一眼就能看出问题。
好了,这一章的内容就这些。记住:SID是服务的“身份证”,正响应是“好的”,负响应是“不行,因为...”。搞懂这三者的关系,诊断通信你就入门了。
可可精品资料库