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码的标识符)。就这么简单。
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的格式搞反了。
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,省得你手动去查表。
3.7 实际项目中的经验
我记得有一次做OBD(车载诊断)项目,客户要求用功能寻址读取所有ECU的故障码。结果一测试,总线上同时涌出几十条响应,直接把CAN控制器干懵了。后来我加了个延时机制,让ECU在收到功能寻址请求后,随机延迟0-100ms再回复。问题就解决了。
你想想看,功能寻址虽然方便,但也要考虑总线负载。尤其是那些对实时性要求高的系统,比如动力CAN,功能寻址用多了,可能会影响关键报文的传输。
好了,关于诊断请求与响应,以及物理寻址和功能寻址,今天就聊到这儿。下一章咱们聊聊诊断会话控制,看看ECU怎么在不同模式间切换。到时候我会分享一个我在项目里遇到的“会话超时”的坑,保证让你印象深刻。