3. 诊断通信基础
诊断请求处理,说白了就是ECU听懂诊断仪在说什么,然后给出正确回应。这个流程看起来简单,但实际项目中踩过的坑可不少。我刚开始做诊断栈集成时,就曾因为对SID解析顺序理解不到位,导致一个正响应报文里塞错了数据长度——嗯,那会儿排查了整整两天。
今天咱们就把这个流程拆开揉碎了讲。从诊断请求进入DCM开始,到最终生成响应报文,每一步都过一遍。
诊断请求的接收与路由
诊断请求从CAN/LIN/Ethernet物理层进来,经过通信栈层层传递,最终到达DCM模块。这个过程中,DCM需要做两件事:
- 接收校验:检查报文格式是否正确,长度是否合法
- 路由判断:确定这个请求是给自己处理的,还是需要转发给其他ECU
我个人习惯把路由逻辑画成一张决策树,这样调试时一目了然:
DCM对SID的解析
SID(Service Identifier)是诊断请求的第一个字节。DCM拿到SID后,会做三件事:
- SID有效性检查:判断这个SID是否在当前会话下可用
- 会话状态匹配:有些服务只能在特定会话下执行(比如编程会话才能用$31服务)
- 安全等级校验:需要解锁才能访问的服务,先检查安全状态
你想想看,如果SID解析顺序搞反了,会出什么问题?比如先检查安全等级再检查会话状态——那用户明明在默认会话下,却收到一个"安全访问拒绝"的负响应,这就不合理了。AUTOSAR规范里对解析顺序有明确要求,我建议严格按照规范来:
| 步骤 | 检查项 | 失败时返回的NRC |
|---|---|---|
| 1 | SID是否支持 | 0x11(服务不支持) |
| 2 | 当前会话是否允许 | 0x7F(服务不支持当前会话) |
| 3 | 安全访问等级 | 0x33(安全访问拒绝) |
| 4 | 请求报文长度 | 0x13(报文长度错误) |
子功能与数据参数的处理
SID解析通过后,接下来就是子功能(SubFunction)和数据参数(DataParameter)的处理。这里有个容易混淆的点:不是所有服务都有子功能。
举个例子:
- $22(读取数据):没有子功能,直接跟DID(数据标识符)
- $2E(写入数据):没有子功能,直接跟DID+数据
- $31(例程控制):有子功能(0x01=启动,0x02=停止,0x03=查询结果)
- $19(读取DTC):有子功能(0x01=按状态读取,0x02=按掩码读取...)
对于有子功能的服务,DCM需要解析子功能字节中的两个关键位:
子功能字节(1个Byte):
Bit 7: 抑制正响应位(SuppressPosRspMsg)
0 = 需要发送正响应
1 = 抑制正响应(只发负响应)
Bit 6-0: 子功能值(SubFunction)
我记得有一次客户反馈说某个诊断请求没有响应。排查了半天,发现是诊断仪把抑制正响应位置1了,但我们的DCM没处理这个位——直接当无效请求丢弃了。从那以后,我在代码里专门加了一个日志打印,每次收到请求都输出子功能字节的二进制值。
正响应与负响应的生成
响应生成是整个流程的最后一步。正响应和负响应的生成逻辑完全不同,咱们分开说。
正响应生成
正响应的格式很简单:SID + 0x40 + 数据。比如$22服务的正响应就是0x62 + DID + 数据值。但这里有个细节——响应数据的组装顺序必须和请求中的参数顺序一致。
// 正响应报文示例($22读取DID 0xF190)
请求: 0x22 0xF1 0x90
响应: 0x62 0xF1 0x90 0x01 0x02 0x03
| | | |____|____|____|
SID+0x40 DID 数据值(3个字节)
负响应生成
负响应格式固定为:0x7F + SID + NRC。NRC(Negative Response Code)是1个字节的错误码。AUTOSAR定义了约30种NRC,常用的有:
| NRC值 | 含义 | 常见场景 |
|---|---|---|
| 0x11 | 服务不支持 | ECU根本不支持这个SID |
| 0x12 | 子功能不支持 | SID支持,但子功能值无效 |
| 0x13 | 报文长度错误 | 数据参数个数不对 |
| 0x22 | 条件不满足 | 比如写数据时ECU不在合适状态 |
| 0x31 | 请求超出范围 | DID不存在或数据值超限 |
| 0x33 | 安全访问拒绝 | 需要解锁但未解锁 |
| 0x78 | 请求正确但响应待定 | 长时间操作,先回复0x78,后续再发真正响应 |
响应生成的优先级规则
当一个请求存在多个错误时,DCM只返回优先级最高的那个NRC。这个优先级顺序在AUTOSAR规范里有明确定义:
- 0x11(服务不支持)—— 最高优先级
- 0x12(子功能不支持)
- 0x13(报文长度错误)
- 0x22(条件不满足)
- 0x31(请求超出范围)
- 0x33(安全访问拒绝)
- 其他NRC —— 最低优先级
举个例子:如果诊断仪发了一个$2E写入请求,但ECU没解锁(应该返回0x33),同时写入的数据值超出范围(应该返回0x31)。按照优先级规则,DCM会返回0x33而不是0x31。这个逻辑在DCM的NRC仲裁模块里实现,我建议大家在配置工具里仔细核对这个优先级表。
嗯,诊断请求处理流程就讲到这里。从接收路由到SID解析,再到子功能处理和响应生成,每一步都有它的设计逻辑。实际项目中,我建议大家先画一张完整的流程图,把每个检查点的NRC都标出来——这样调试时能省不少时间。