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返回响应的完整路径。

UDS诊断请求与响应流程图 UDS诊断请求与响应流程 诊断仪 发送请求报文 CAN 总线 ECU 解析请求 通过? 肯定响应 (SID+0x40) 否定响应 (0x7F+NRC) 说明:ECU收到请求后,先解析,再判断。通过则回肯定响应,否则回否定响应(含NRC)。

从这张图你可以看到,ECU的处理逻辑其实很清晰:收到请求 -> 解析 -> 判断 -> 响应。但实际代码实现时,判断逻辑会非常复杂。比如,你要检查SID是否支持、子功能是否有效、报文长度是否正确、当前安全等级是否足够……每一步都可能返回不同的NRC。

4.5 实战中的避坑指南

最后,分享几个我踩过的坑:

  • NRC 0x78的处理:ECU返回0x78时,不要立即重发。等一段时间(比如50ms)再试。我曾经见过一个测试脚本,因为没处理0x78,导致ECU被连续请求冲垮。
  • 报文长度校验:有些ECU对报文长度非常敏感。多一个字节或少一个字节,都可能返回NRC 0x13。我建议你在发送前,先确认DLC(数据长度码)是否正确。
  • 安全访问的顺序:很多服务需要先解锁才能用。如果你收到NRC 0x33,先检查一下是否已经执行了安全访问的“请求种子”和“发送密钥”步骤。

我的习惯:在项目初期,我会先写一个“NRC映射表”,把ECU可能返回的所有NRC都列出来,并注明原因和解决方案。这样调试时,看到NRC就能快速定位问题。

好了,关于诊断请求与响应,我们就聊到这里。记住,报文格式是基础,NRC是灵魂。理解了这两点,UDS诊断你就入门了。