4. 诊断请求与响应:请求报文格式、肯定响应与否定响应、NRC机制详解
各位同学,今天我们聊一个非常核心的话题——诊断请求与响应。说白了,就是ECU和诊断仪之间怎么“对话”。你发一个请求,它回一个响应。但这里面的门道,远比“一问一答”要复杂得多。
我记得刚入行那会儿,调试一个CAN节点,死活收不到肯定响应。查了三天,最后发现是请求报文里的地址信息填错了。嗯,从那以后,我对报文格式就格外敏感。
4.1 请求报文格式:你发出去的是什么?
UDS诊断请求,本质上是一个CAN报文。但它的数据场(Data Field)有严格的格式要求。我个人习惯把请求报文拆成三部分来看:
- SID(服务标识符):1个字节,告诉ECU你要干什么。比如0x22是“读取数据”,0x2E是“写入数据”。
- Sub-function(子功能):1个字节(可选)。有些服务需要子功能来细化操作,比如0x11(ECU复位)的0x01是“硬复位”,0x03是“软复位”。
- Data(数据参数):N个字节。具体内容取决于服务。比如读取数据时,这里放的是DID(数据标识符)。
一个典型的请求报文结构(以0x22服务为例):
| CAN ID | DLC | Byte 0 | Byte 1 | Byte 2 | ... |
| 0x7DF | 0x08 | 0x22 | 0xF1 | 0x90 | ... |
Byte 0是SID(0x22),Byte 1和Byte 2是DID(0xF190)。后面的字节是填充或扩展数据。
你想想看,ECU收到这个报文后,它怎么知道该回什么?这就引出了我们的响应机制。
4.2 肯定响应与否定响应:ECU的两种回答
ECU收到请求后,只有两种回答:
- 肯定响应(Positive Response):请求被正确理解和执行。格式是
[SID + 0x40] + 数据。比如0x22服务的肯定响应,SID就是0x62。 - 否定响应(Negative Response):请求没通过。格式是
0x7F + [请求的SID] + [NRC]。
这里有个细节:肯定响应的SID是请求SID加上0x40。为什么是0x40?这是协议规定的,我们记住就行。但否定响应的SID永远是0x7F,后面跟着你发出去的那个SID,再加一个NRC。
我的一个小技巧:调试时,如果看到0x7F开头的报文,先别慌。看第三个字节,那就是NRC。NRC能告诉你ECU为什么拒绝你。比瞎猜强多了。
4.3 NRC机制详解:ECU为什么说“不”?
NRC(Negative Response Code)是UDS协议里最精华的部分之一。它用一个字节告诉你拒绝原因。常见的NRC有几十种,但实际项目中常用的也就十几种。
我曾经在一个项目中,客户反馈ECU总是返回NRC 0x31(请求超出范围)。查了半天,发现是DID的地址写错了。嗯,这种低级错误,犯过一次就不会再犯了。
下面这张表,是我个人整理的“高频NRC速查表”,建议你收藏:
| NRC(十六进制) | 名称 | 常见原因 |
|---|---|---|
| 0x10 | 一般拒绝 | 请求格式错误,或ECU无法处理 |
| 0x11 | 不支持该服务 | SID不在ECU支持列表中 |
| 0x12 | 子功能不支持 | Sub-function无效 |
| 0x13 | 报文长度错误 | 数据场长度不对 |
| 0x22 | 条件不满足 | ECU当前状态不允许执行该操作 |
| 0x31 | 请求超出范围 | DID、RID等参数无效 |
| 0x33 | 安全访问拒绝 | 未解锁或解锁失败 |
| 0x35 | 无效的密钥 | 安全访问的Key不匹配 |
| 0x78 | 请求正在处理 | ECU需要更多时间,稍后重试 |
注意:NRC 0x78比较特殊。它表示ECU已经接受了请求,但需要时间处理。这时候诊断仪应该等待,而不是立即重发。我曾经见过一个测试脚本,因为没处理0x78,导致ECU被连续请求冲垮。
4.4 请求与响应的完整流程
为了让你更直观地理解,我画了一张流程图。它展示了从诊断仪发送请求,到ECU返回响应的完整路径。
从这张图你可以看到,ECU的处理逻辑其实很清晰:收到请求 -> 解析 -> 判断 -> 响应。但实际代码实现时,判断逻辑会非常复杂。比如,你要检查SID是否支持、子功能是否有效、报文长度是否正确、当前安全等级是否足够……每一步都可能返回不同的NRC。
4.5 实战中的避坑指南
最后,分享几个我踩过的坑:
- NRC 0x78的处理:ECU返回0x78时,不要立即重发。等一段时间(比如50ms)再试。我曾经见过一个测试脚本,因为没处理0x78,导致ECU被连续请求冲垮。
- 报文长度校验:有些ECU对报文长度非常敏感。多一个字节或少一个字节,都可能返回NRC 0x13。我建议你在发送前,先确认DLC(数据长度码)是否正确。
- 安全访问的顺序:很多服务需要先解锁才能用。如果你收到NRC 0x33,先检查一下是否已经执行了安全访问的“请求种子”和“发送密钥”步骤。
我的习惯:在项目初期,我会先写一个“NRC映射表”,把ECU可能返回的所有NRC都列出来,并注明原因和解决方案。这样调试时,看到NRC就能快速定位问题。
好了,关于诊断请求与响应,我们就聊到这里。记住,报文格式是基础,NRC是灵魂。理解了这两点,UDS诊断你就入门了。