第2章:ISO 14229-1标准解读:协议文档结构、服务ID定义、子功能参数、数据格式与编码规则
好,咱们直接进入正题。ISO 14229-1,也就是UDS诊断协议的核心标准。说实话,我刚入行那会儿,看到这份标准文档,第一反应是——这也太厚了吧?几百页的PDF,全是英文,密密麻麻的表格。但你别怕,今天我就带你把它拆开揉碎,讲清楚。
2.1 协议文档的整体结构
ISO 14229-1这份标准,说白了就是一本「诊断服务字典」。它规定了ECU和诊断仪之间该怎么说话,说什么话,以及话里的每个字是什么意思。
整份文档的结构,我习惯把它分成三大块:
- 第一部分:基础框架(第1章到第4章)—— 讲范围、引用、术语、缩略语。这部分你大概扫一眼就行,知道UDS是干啥的,以及它和ISO 11898(CAN总线)是什么关系。
- 第二部分:核心机制(第5章到第9章)—— 讲诊断服务的通用规则,比如定时参数、数据格式、安全访问、会话控制。这部分是重点,我建议你反复看。
- 第三部分:服务定义(第10章到第18章)—— 这才是真正的干货。每个服务ID(SID)、每个子功能参数、每个数据格式,全在这里。
2.2 服务ID(SID)的定义与分类
服务ID,就是诊断请求报文里的第一个字节。它告诉ECU:「嘿,我要干啥?」
举个例子,0x10 表示「诊断会话控制」,0x22 表示「读取数据通过标识符」,0x2E 表示「写入数据通过标识符」。每个SID都是一个8位的数值,范围从 0x00 到 0xFF。
标准里把SID分成了几类:
| SID范围 | 类别 | 典型服务 |
|---|---|---|
| 0x10 - 0x3E | 诊断与通信管理 | 0x10(会话控制)、0x11(ECU复位)、0x28(通信控制) |
| 0x22 - 0x2E | 数据读取与写入 | 0x22(读取数据)、0x2E(写入数据) |
| 0x31 - 0x3D | 输入输出控制 | 0x31(例程控制)、0x2F(输入输出控制) |
| 0x34 - 0x37 | 上传下载 | 0x34(请求下载)、0x35(请求上传) |
嗯,这里要注意:SID的分配是有规律的。比如 0x10 到 0x3E 是「诊断与通信管理」类,0x22 到 0x2E 是「数据读取与写入」类。你记住这个规律,以后看到SID就能猜出它大概属于哪一类。
避坑指南: 我曾经在项目里遇到过一个坑——ECU对某个SID的响应,和标准文档里写的格式不一样。后来查了半天,发现是供应商自己扩展了SID的定义。所以,拿到ECU的A2L文件或ODX文件后,一定要先确认它支持哪些SID,别完全依赖标准文档。
2.3 子功能参数(SubFunction)
有些服务,光靠SID还不够。比如 0x10(诊断会话控制),你得告诉ECU:「我要切换到哪个会话?」是默认会话(0x01),还是编程会话(0x02),还是扩展会话(0x03)?
这个额外的信息,就是子功能参数。它通常放在SID后面的第二个字节。
子功能参数的结构是这样的:
字节0: SID (0x10)
字节1: 子功能参数 (0x01 表示默认会话, 0x02 表示编程会话, 0x03 表示扩展会话)
字节2...: 其他数据(如果有的话)
子功能参数的最高位(bit 7)有一个特殊含义——它表示「是否需要正响应」。如果bit 7 = 1,ECU不会发送正响应;如果bit 7 = 0,ECU会发送正响应。
举个例子:
0x10 0x01:切换到默认会话,并且ECU要给我回一个正响应。0x10 0x81:切换到默认会话,但ECU别回正响应(这叫「抑制正响应」)。
2.4 数据格式与编码规则
UDS里的数据格式,说白了就是「怎么把数据塞进报文里」。标准里定义了几种基本的数据类型:
- uint8 / uint16 / uint32:无符号整数,分别占1、2、4个字节。比如读取ECU的软件版本号,通常用uint8数组表示。
- int8 / int16 / int32:有符号整数,用补码表示。比如读取温度值,可能是int16。
- ASCII字符串:比如读取VIN码(车辆识别号),就是17个字节的ASCII字符串。
- 原始字节数组:比如读取诊断故障码(DTC),就是一组原始字节。
编码规则方面,UDS用的是「大端序」(Big-Endian)。也就是说,高位字节在前,低位字节在后。
举个例子,如果我要发送一个uint16的值 0x1234:
大端序:0x12 0x34
小端序:0x34 0x12
UDS标准明确要求用大端序。这一点你一定要注意,因为有些MCU(比如ARM Cortex-M系列)默认是小端序,你在代码里需要做字节序转换。
2.5 实际报文示例
光说不练假把式。咱们来看一个实际的诊断请求和响应报文。
请求: 读取ECU的软件版本号(假设DID = 0xF190)
请求报文:0x22 0xF1 0x90
解释:
0x22 = SID(读取数据通过标识符)
0xF1 0x90 = DID(数据标识符,占2个字节)
响应: ECU返回软件版本号(假设版本号是 "V1.2.3")
响应报文:0x62 0xF1 0x90 0x56 0x31 0x2E 0x32 0x2E 0x33
解释:
0x62 = 正响应SID(请求SID + 0x40)
0xF1 0x90 = DID(和请求里的DID一致)
0x56 0x31 0x2E 0x32 0x2E 0x33 = 数据("V1.2.3"的ASCII编码)
你看,正响应的SID是请求SID加上 0x40。这是UDS的一个固定规则——正响应SID = 请求SID + 0x40。比如 0x22 + 0x40 = 0x62。
核心要点: 正响应SID = 请求SID + 0x40。这个规则适用于所有UDS服务。你写代码的时候,可以直接用这个公式来判断收到的报文是正响应还是负响应。
2.6 负响应码(NRC)
如果ECU处理不了你的请求,它会返回一个负响应。负响应的格式是:
0x7F + 请求SID + NRC
比如,你发了一个 0x22 0xF1 0x90,但ECU不支持这个DID,它可能会回:
0x7F 0x22 0x12
这里的 0x12 就是NRC,表示「子功能不支持」或「请求超出范围」。常见的NRC有:
| NRC | 含义 | 常见场景 |
|---|---|---|
| 0x10 | 一般拒绝 | ECU正忙,无法处理请求 |
| 0x11 | 服务不支持 | ECU不支持这个SID |
| 0x12 | 子功能不支持 | ECU不支持这个子功能参数 |
| 0x13 | 请求长度错误或格式错误 | 报文长度不对,或者数据格式不对 |
| 0x22 | 条件不满足 | 比如安全访问没通过,就尝试写入数据 |
| 0x31 | 请求超出范围 | DID或RID不在支持的范围内 |
| 0x33 | 安全访问被拒绝 | 安全访问的种子和密钥不匹配 |
2.7 总结
好,这一章的内容就到这里。咱们回顾一下:
- ISO 14229-1标准分三大部分:基础框架、核心机制、服务定义。
- SID是诊断请求的第一个字节,范围从0x00到0xFF,分成了几大类。
- 子功能参数放在SID后面,最高位控制是否抑制正响应。
- 数据格式用大端序,uint8/uint16/uint32是基础。
- 正响应SID = 请求SID + 0x40,负响应以0x7F开头。
下一章,咱们会深入讲「诊断会话控制」这个服务。到时候我会带你手写一个会话切换的代码示例。嗯,敬请期待。