3、诊断请求与响应:请求(Request)与响应(Response)机制、物理寻址与功能寻址

好,咱们今天聊聊诊断通信里最核心的两个动作——请求和响应。说白了,就是ECU和诊断仪之间怎么“对话”。你发一句,它回一句,就这么简单。但这里面的门道,可不少。

3.1 诊断请求(Request)的结构

一个诊断请求,本质上就是一串字节。我习惯把它拆成三部分来看:

  • 服务标识符(SID):这是请求的“身份证”。比如0x10代表“诊断会话控制”,0x22代表“读取数据标识符”。一个字节,清清楚楚。
  • 子功能(Sub-function):有些服务需要细分。比如0x10后面跟着0x01,表示“切换到默认会话”;0x02表示“切换到扩展会话”。
  • 数据参数(Data):具体要操作的数据。比如读取某个DID(数据标识符),这里就填DID的值。

举个例子,一个典型的读取VIN码的请求:

0x22 0xF1 0x90

0x22是SID(读取数据),0xF190是DID(VIN码的标识符)。就这么简单。

我的小习惯: 在CANoe里写诊断序列时,我总喜欢先把SID和子功能单独列出来,再拼成完整的报文。这样调试时一眼就能看出问题在哪。

3.2 诊断响应(Response)的机制

ECU收到请求后,必须给个回应。回应分两种:

  • 肯定响应(Positive Response):一切正常。格式是 SID + 0x40,后面跟着数据。比如上面的读取VIN码请求,响应就是 0x62 0xF1 0x90 0x4C 0x53 0x56...(0x62 = 0x22 + 0x40)。
  • 否定响应(Negative Response):出问题了。格式是 0x7F + 请求的SID + 错误码(NRC)。比如 0x7F 0x22 0x31,表示“请求超出范围”。

嗯,这里要注意:否定响应的SID永远是0x7F,不是请求SID加0x40。我刚开始做项目时,有次死活收不到响应,查了半天才发现是自己把NRC的格式搞反了。

我曾经踩过的坑: 有一次在实车上测试,ECU一直回复0x7F 0x22 0x78(请求正确接收但响应待定)。我以为出大问题了,后来才发现这是ECU在告诉我“别急,我还在处理”。0x78这个NRC,说白了就是“稍等一下”。

3.3 物理寻址 vs 功能寻址

这是诊断通信里最容易混淆的概念。我尽量用大白话讲清楚。

3.4 物理寻址(Physical Addressing)

物理寻址,就是“点对点”通信。诊断仪发一条请求,只针对一个特定的ECU。比如你只想读取发动机ECU的故障码,那就用物理寻址。

在CAN总线上,物理寻址的报文ID(CAN ID)通常是固定的。比如诊断仪发请求用0x7DF,ECU回复用0x7E8。你想想看,这样每个ECU都有自己的“专属通道”,互不干扰。

3.5 功能寻址(Functional Addressing)

功能寻址,就是“一对多”通信。诊断仪发一条请求,总线上所有支持该功能的ECU都会响应。比如你想让所有ECU同时进入扩展会话,那就用功能寻址。

功能寻址的CAN ID通常是0x7DF(请求)和0x7E8(响应),但响应时每个ECU会用自己的物理地址回复。我记得有一次做网关测试,发了一条功能寻址的请求,结果十几个ECU同时回复,CAN总线直接爆了。嗯,这就是没做好时序控制的后果。

特性 物理寻址 功能寻址
通信对象 单个ECU 多个ECU
CAN ID(请求) 0x7DF(示例) 0x7DF(示例)
CAN ID(响应) ECU物理地址 ECU物理地址
典型应用 读取特定ECU数据 广播请求(如进入扩展会话)
总线负载 高(多个ECU同时回复)
核心区别: 物理寻址是“我叫你,你回答”;功能寻址是“我叫所有人,谁支持谁回答”。说白了,一个像打电话,一个像在群里@所有人。

3.6 在CANoe中模拟诊断请求与响应

我个人习惯用CANoe的Diagnostic Console来模拟。你只需要配置好ECU的物理地址和功能地址,然后发送请求,就能看到响应。

举个例子,模拟一个读取DID的请求:

// 在CAPL中发送诊断请求
on key 'r'
{
  diagRequest ECU.DiagnosticSessionControl(0x01); // 切换到默认会话
  diagRequest ECU.ReadDataByIdentifier(0xF190);   // 读取VIN码
}

响应会自动解析在Trace窗口里。如果ECU回复了否定响应,CANoe会直接显示NRC,省得你手动去查表。

避坑指南: 我曾经在写CAPL脚本时,忘了设置ECU的物理地址。结果发出去的请求石沉大海,查了半天才发现是地址没对上。所以,配置诊断模块时,第一件事就是确认物理地址和功能地址。

3.7 实际项目中的经验

我记得有一次做OBD(车载诊断)项目,客户要求用功能寻址读取所有ECU的故障码。结果一测试,总线上同时涌出几十条响应,直接把CAN控制器干懵了。后来我加了个延时机制,让ECU在收到功能寻址请求后,随机延迟0-100ms再回复。问题就解决了。

你想想看,功能寻址虽然方便,但也要考虑总线负载。尤其是那些对实时性要求高的系统,比如动力CAN,功能寻址用多了,可能会影响关键报文的传输。

重要提醒: 功能寻址的响应,ECU必须用自己的物理地址回复。千万别用功能地址回复,否则其他ECU会误以为这是给自己的请求,造成混乱。我见过一个新手工程师犯过这个错,结果整个诊断网络都瘫痪了。

好了,关于诊断请求与响应,以及物理寻址和功能寻址,今天就聊到这儿。下一章咱们聊聊诊断会话控制,看看ECU怎么在不同模式间切换。到时候我会分享一个我在项目里遇到的“会话超时”的坑,保证让你印象深刻。