3. 汽车诊断协议基础

在 S32K 这类车规 MCU 上做诊断系统,最容易犯的错误是把“诊断”当成一个软件模块来理解。实际上,诊断是一条从物理线束一直贯穿到应用服务的完整协议栈:CAN 收发器把差分电平变成位流,CAN 控制器把位流组织成帧,ISO 15765-2 把帧拼成诊断报文,ISO 14229 再把报文解释为服务请求与响应。任何一层理解错位,都会表现为“诊断仪连不上”或“服务返回 0x7F”。本节按这条链路自下而上梳理,并给出可落地的参数与判断依据。

一、ISO 11898:CAN 物理层与位定时

ISO 11898-2 定义的是高速 CAN 的物理层,采用差分信号:CAN_H 与 CAN_L 之间的电压差决定显性(Dominant,逻辑 0)与隐性(Recessive,逻辑 1)。显性状态下差分电压约 2V,隐性状态下接近 0V。总线两端各需一个 120Ω 终端电阻,并联后等效 60Ω,这是用万用表断电测量 CAN_H–CAN_L 时应看到的典型值。若测得 120Ω 或 40Ω 左右,通常意味着只接了一个终端或接了三个,属于常见接线故障。

位定时是物理层与数据链路层的交界参数。以 S32K 常见的 500kbps 为例,标称位时间 2μs,通常划分为同步段、传播段、相位缓冲段 1 和相位缓冲段 2。采样点一般设置在位时间的 75%~87.5% 之间,500kbps 下常取 80%,即采样点位于 1.6μs 处。采样点过早会放大振铃影响,过晚则压缩相位缓冲余量。S32K 的 FlexCAN 模块通过 CTRL1 寄存器的 PRESDIV、PROPSEG、PSEG1、PSEG2 配置,例如 8MHz 时钟下取 PRESDIV=0、PROPSEG=2、PSEG1=4、PSEG2=1,可得到 1+2+4+1=8 个时间份额,每份额 250ns,位时间 2μs,采样点位于第 7 份额即 87.5%。实际取值需结合收发器环路延迟与总线长度核算。

二、ISO 15765-2:DoCAN 的分帧与流控

CAN 单帧数据场最多 8 字节(经典 CAN),而 UDS 请求往往远超 8 字节,ISO 15765-2 负责把长报文切分并重组。它定义了四种帧类型,由首字节高 4 位 PCI 标识:

  • 单帧 SF:PCI 为 0,低 4 位表示数据长度(0~7),数据直接跟在后面。
  • 首帧 FF:PCI 为 1,低 4 位与第二字节共 12 位表示总长度,最多 4095 字节,后 6 字节为数据。
  • 连续帧 CF:PCI 为 2,低 4 位为序号,从 1 开始循环 0~15,接收方据此检测丢帧。
  • 流控帧 FC:PCI 为 3,包含流状态 FS、块大小 BS 和最小间隔 STmin。

以读取 17 字节的 VIN(服务 0x22,DID 0xF190)为例,请求本身只有 3 字节,可用单帧发出;响应 17 字节则需首帧加两帧连续帧。接收方收到首帧后,应回复流控帧,例如 FS=0(继续发送)、BS=0(不再要求后续流控)、STmin=0x0A(10ms 间隔)。发送方按 STmin 节流连续帧,接收方按序号校验。若序号跳变,应中止接收并向上层报告。S32K 上通常用 FlexCAN 的邮箱中断配合状态机实现,注意 FC 超时 N_Bs 与连续帧超时 N_Cr 的定时器必须独立维护。

UDS 诊断协议栈与 DoCAN 分帧示意 ISO 14229 UDS 服务 / 子功能 / DID ISO 15765-2 DoCAN SF / FF / CF / FC ISO 11898-1 数据链路 帧格式 / 仲裁 / CRC ISO 11898-2 物理层 差分电平 / 120Ω 终端 示例:0x22 F190 读取 VIN(响应 17 字节) 请求 SF 03 22 F1 90 响应 FF 10 11 62 F1 90 ... 流控 FC 30 00 0A 连续帧 CF #1 21 ... 连续帧 CF #2 22 ... 关键参数与判断依据 • 流控帧:FS=0 继续发送,BS=0 表示无需再等流控,STmin=0x0A 即 10ms • 连续帧序号:1→2→…→15→0→1,跳变即丢帧,应中止接收 • 超时:N_Bs(等待流控)与 N_Cr(等待连续帧)需独立定时 • 物理层:500kbps 位时间 2μs,采样点建议 75%~87.5% • 终端电阻:断电测 CAN_H–CAN_L 应约 60Ω

三、ISO 14229:UDS 服务与响应规则

UDS 的核心是“请求—响应”模型。请求由 SID(服务标识符)加参数构成,肯定响应为 SID+0x40,否定响应固定为 0x7F 加原 SID 加 NRC(否定响应码)。常用服务包括:0x10 诊断会话控制、0x11 ECU 复位、0x14 清除诊断信息、0x19 读取 DTC 信息、0x22 按 DID 读数据、0x27 安全访问、0x2E 按 DID 写数据、0x31 例程控制、0x3E 保持连接、0x85 控制 DTC 设置。

几个必须记住的 NRC:0x11 服务不支持、0x12 子功能不支持、0x13 报文长度或格式错误、0x22 条件不满足、0x31 请求超出范围、0x33 安全访问被拒、0x78 响应挂起。0x78 尤其重要:当 ECU 需要较长时间处理(如擦写 Flash)时,先回 0x7F xx 78,诊断仪需重置 P2 定时器继续等待,随后再给出最终响应。若 S32K 端忘记发 0x78 而直接超时,诊断仪会报“无响应”。

四、OBD-II 服务与 PID

OBD-II 是排放相关的法规诊断,服务号与 UDS 不同:0x01 读取当前数据(PID)、0x02 读取冻结帧、0x03 读取排放相关 DTC、0x04 清除 DTC、0x09 读取车辆信息(如 VIN、CALID)。PID 是 1 字节参数标识,例如 PID 0x0C 为发动机转速,返回 2 字节,计算公式为 ((A×256)+B)/4,单位 rpm;PID 0x0D 为车速,单字节,单位 km/h;PID 0x05 为冷却液温度,公式为 A−40,单位 ℃。OBD-II 使用 11 位标准帧,功能寻址 ID 为 0x7DF,物理响应通常为 0x7E8~0x7EF。

五、诊断会话与安全访问机制

UDS 默认会话(0x01)只开放只读类服务。要执行写入、例程或刷写,需先切到扩展会话(0x03)或编程会话(0x02),再通过 0x27 安全访问解锁。0x27 分奇数子功能“请求种子”和偶数子功能“发送密钥”。以子功能 0x01/0x02 为例:诊断仪发 27 01,ECU 返回 67 01 加若干字节种子;诊断仪用约定算法(常见为对种子做异或、移位或查表)算出密钥,发 27 02 加密钥;ECU 校验通过返回 67 02,否则返回 7F 27 35(密钥无效)。

安全访问有两个工程要点。第一,种子必须每次随机或伪随机生成,不能固定,否则重放攻击可绕过。第二,连续失败次数应计数,超过阈值(如 3 次)后进入延迟锁定,返回 NRC 0x36(超过尝试次数)或 0x37(所需时间延迟未到)。S32K 上可把失败计数与锁定时间放在受保护的 NVM 中,防止掉电复位清零。

会话与安全状态是联动的:从扩展会话退回默认会话、或 ECU 复位后,安全解锁状态通常自动清除。因此刷写流程中每次复位后都要重新执行 0x27,不能假设解锁状态一直有效。

六、一次完整交互的参数示例

假设诊断仪以 500kbps 连接 S32K,物理请求 ID 0x7E0、响应 ID 0x7E8。读取 VIN 的流程为:发 03 22 F1 90(单帧);ECU 回 10 11 62 F1 90 …(首帧,总长 0x011=17);诊断仪回 30 00 0A(流控);ECU 依次发 21 …、22 …(连续帧)。若中途诊断仪未在 P2 时间内收到下一帧,应发 3E 00 保持连接或重发请求。判断成功的依据是最终拼出的 17 字节以 62 F1 90 开头,且 VIN 字符符合可打印 ASCII。

把这条链路记牢,后续在 S32K 上配置 FlexCAN、实现 DoCAN 状态机、编写 UDS 服务分发时,就能清楚每个返回值对应哪一层的问题,而不是盲目改代码。