3、诊断请求与响应机制:服务标识符(SID)与子功能、诊断请求格式(单帧/多帧)、诊断正响应与负响应码(NRC)

各位同行,今天我们聊点实在的。诊断请求与响应,说白了就是ECU和诊断仪之间的“对话规则”。你发一句,它回一句,但怎么发、怎么回,这里面门道不少。我个人习惯把这一章看作是诊断栈的“通信协议层”,搞懂了它,你写配置代码时心里就有底了。

3.1 服务标识符(SID)与子功能

先说说SID。SID就是一个字节,范围0x00到0x3E,每个值代表一个服务。比如0x10是诊断会话控制,0x22是读取数据,0x2E是写入数据。你想想看,ECU收到一个请求,第一件事就是看SID,判断你要干嘛。

但光有SID还不够。很多服务需要更细的控制,这就引出了子功能(SubFunction)。子功能是请求字节的第二个字节,比如0x10服务下的子功能0x01代表“默认会话”,0x02代表“编程会话”,0x03代表“扩展会话”。

关键点:SID决定“做什么”,子功能决定“怎么做”。

我在项目中遇到过一个问题:某个ECU对0x22服务(读取数据)不支持子功能,但测试用例里却发了带子功能的请求。结果ECU直接回了NRC 0x12(子功能不支持)。嗯,这里要注意:不是所有服务都支持子功能。UDS协议里明确规定了哪些服务支持子功能,哪些不支持。配置诊断栈时,一定要对照协议确认。

SID 服务名称 是否支持子功能
0x10 诊断会话控制 是
0x22 读取数据 否
0x2E 写入数据 否
0x31 例程控制 是

3.2 诊断请求格式:单帧与多帧

请求格式这块,我建议你重点理解。CAN总线一帧最多传8个字节,但诊断请求可能很长,比如写入一个DID(数据标识符)包含几十个字节。怎么办?分帧传输。

单帧(SF):请求数据长度 ≤ 7字节(如果使用CAN扩展帧,可能更少)。第一个字节的高四位是0,低四位表示数据长度。比如0x03 0x22 0xF1 0x90,第一个字节0x03表示后面有3个字节数据。

多帧(FF + CF):请求数据长度 > 7字节。先发一个首帧(FF),告诉对方总长度;然后发连续帧(CF),把剩下的数据传完。首帧第一个字节的高四位是1,低四位和第二个字节组成总长度(最多4095字节)。

避坑指南:我曾经在配置多帧传输时,把首帧的流控制参数设错了。结果ECU一直收不到后续帧,超时后回了NRC 0x78(请求正确接收,但响应待定)。后来查了半天,发现是CF的间隔时间设得太短,ECU处理不过来。建议你把间隔时间设得宽松一点,比如10ms以上。

为什么会这样?因为ECU的接收缓冲区有限。多帧传输时,发送方必须等接收方发流控制帧(FC)才能继续发。流控制帧里有个参数叫“块大小”(BlockSize),告诉发送方一次能收几帧。我习惯把块大小设为1,这样每发一帧都等确认,虽然慢但稳定。

// 单帧示例:读取 DID 0xF190
请求:03 22 F1 90
// 03 = 单帧,数据长度3
// 22 = 读取数据服务
// F1 90 = DID

// 多帧示例:写入 DID 0xF190,数据为 01 02 03 04 05 06 07 08
首帧:10 0E 2E F1 90 01 02 03 04
// 10 = 首帧,0E = 总长度14字节
// 2E = 写入数据服务
// F1 90 = DID
// 01 02 03 04 = 前4个数据字节

连续帧1:21 05 06 07 08
// 21 = 连续帧,序列号1
// 05 06 07 08 = 后4个数据字节

3.3 诊断正响应与负响应码(NRC)

ECU收到请求后,要么回正响应,要么回负响应。正响应的格式是:SID + 0x40 + 数据。比如请求0x22 F1 90,正响应就是0x62 + 数据。注意,SID加了0x40,这是协议规定的,别搞错。

负响应就复杂了。格式是:0x7F + 请求SID + NRC。NRC是一个字节,范围0x00到0xFF,但常用的就十几个。我整理了一张表,你保存一下:

NRC 含义 常见原因
0x10 一般拒绝 请求格式错误,或ECU无法处理
0x11 服务不支持 SID不在支持的列表里
0x12 子功能不支持 子功能值无效
0x13 消息长度错误 请求数据长度不对
0x22 条件不满足 当前会话或安全等级不允许
0x31 请求超出范围 DID或数据值无效
0x78 请求正确接收,但响应待定 ECU需要时间处理,稍后重试

注意:NRC 0x78是个特殊码。它告诉诊断仪“我收到了,但还没处理完,你等会儿再问”。我见过不少工程师在配置诊断栈时,把0x78当成错误码处理,直接终止了通信。其实0x78不是错误,是“请稍候”。正确的做法是:收到0x78后,过一段时间再发一次请求,直到收到正响应或其他NRC。

我个人习惯在诊断栈配置中,把NRC的处理逻辑单独写成一个模块。每个NRC对应一个回调函数,这样调试时一目了然。比如收到0x22(条件不满足),我就知道是当前会话不对,或者安全等级不够。

3.4 知识体系图

下面这张图是我自己画的,把本章的核心逻辑串起来了。你仔细看看,能帮你理清思路。

诊断请求与响应机制 诊断请求 SID + 子功能(可选) 单帧(SF)或 多帧(FF+CF) ECU处理 解析SID和子功能 检查条件(会话、安全等) 执行服务 诊断响应 正响应:SID+0x40+数据 负响应:0x7F+SID+NRC 常见NRC码速查 0x10 - 一般拒绝 0x11 - 服务不支持 0x12 - 子功能不支持 0x13 - 消息长度错误 0x22 - 条件不满足 0x31 - 请求超出范围 0x78 - 请求正确接收,响应待定 注意:0x78不是错误,是“请稍候”

好了,这一章的内容就这些。SID、子功能、单帧多帧、正负响应,这几个概念你搞清楚了,诊断请求与响应的机制就掌握了八成。剩下的两成,靠实战去补。

可可精品资料库