文章目录
- 一、为什么说 0x22 是 UDS 最重要的服务?
- 二、0x22 服务基础:它到底读什么?
- 三个关键特性
- 三、报文格式详解:逐字节拆解
- 3.1 请求报文
- 常用 DID 定义表
- 3.2 肯定响应报文
- 3.3 否定响应报文
- 四、实战示例:读取 ECU 软硬件版本号
- 第一步:诊断仪发送请求
- 第二步:ECU 返回肯定响应
- 第三步:解析数据
- 五、NRC 错误处理:7 种错误码全解析
- NRC 错误码一览表
- NRC 检查优先级
- 六、0x22 服务测试六大关注点
- 1、ECU 版本正确性问题
- 2、无效 DID 处理问题
- 3、会话模式问题
- 4、安全依赖问题
- 5、数据一致性问题
- 6、ECU 处理性能问题
- 七、总结:一张表回顾 0x22 核心
UDS 诊断协议系列 · 核心必读
从报文格式到实战测试,一篇文章讲透 UDS 中使用频率最高的服务
一、为什么说 0x22 是 UDS 最重要的服务?
做车载测试的同学注意了——如果你只能学一个 UDS 服务,那必须是0x22 ReadDataByIdentifier。为什么?因为它是整个 UDS 诊断体系中使用频率最高、覆盖场景最广的核心服务。无论是读取 ECU 软硬件版本号、查询标定参数、还是获取系统运行状态,都离不开它。
UDS(Unified Diagnostic Services,统一诊断服务)协议定义了 26 种服务,覆盖诊断管理、数据传输、故障诊断、输入输出控制、例程控制和上传下载六大类。而0x22 ReadDataByIdentifier属于"数据传输"大类,是其中最核心的数据读取服务。
图 1:0x22 在 UDS 服务家族中的位置——数据传输大类中的核心服务
为什么说它最重要?三个原因:
1. 使用频率最高:几乎每次诊断会话的第一步都是用 0x22 读取 ECU 版本信息,确认通信对象正确。它是所有测试的"起手式"。
2. 覆盖数据最广:从软硬件版本号、零件编号、序列号,到标定参数、传感器值、运行状态——ECU 里几乎所有可读数据都通过 0x22 获取。
3. 学习价值最大:0x22 涉及 DID 概念、报文格式、多帧传输、NRC 错误处理、会话权限、安全解锁等 UDS 核心机制,掌握它等于掌握了 UDS 的半壁江山。
二、0x22 服务基础:它到底读什么?
0x22 服务全称ReadDataByIdentifier——按标识符读取数据,也就是我们常说的读 DID 信息。DID(Data Identifier,数据标识符)是一个 2 字节的编号,相当于每个数据的"门牌号":诊断仪告诉 ECU “我要读 0xF190”,ECU 就把 0xF190 对应的数据返回来。
图 2:0x22 ReadDataByIdentifier 服务全景——三大数据类型一览
0x22 能读取的数据(dataRecord)主要分为三大类:
| 数据类型 | 典型 DID 示例 | 说明 |
|---|---|---|
| 内部数据 | 0xF190 零件编号、0xF187 序列号、0xF195 Boot软件版本、0xF196 应用软件版本 | ECU 的"身份证信息",软硬件版本号、序列号等 |
| 标定参数 | 各 OEM 自定义 | ECU 内部的标定值、配置参数、阈值设定等 |
| 系统状态 | 各 OEM 自定义 | 诊断结果、传感器值、ECU 运行状态等动态数据 |
三个关键特性
特性一:支持一次请求多个 DID
22 服务允许诊断仪在一条请求报文中同时携带多个 DID,ECU 会依次返回每个 DID 的数据,大大提高读取效率。
特性二:DID 允许重复请求
如果请求中出现了重复的 DID,ECU 也会重复响应该 DID 的数据内容。协议层面不做去重。
特性三:DID 数量有限制
协议提到 ECU 可限制同时请求的 DID 数量,但未给出具体值。一般 OEM 会限制为 3 或 5 个。如果请求出错,可能收到两种 NRC:
- NRC 0x13:请求报文长度超过 ECU 处理能力
- NRC 0x14:ECU 响应数据过长(所有 DID 数据加起来超过 ECU 能力)
三、报文格式详解:逐字节拆解
0x22 的报文分为请求报文、肯定响应报文和否定响应报文三种。下面我们逐字节拆解。
图 3:0x22 服务三种报文格式总览——请求、肯定响应、否定响应
3.1 请求报文
诊断仪向 ECU 发送的请求报文格式如下:
| byte 0 | byte 1 | byte 2 | byte 3 | byte 4-5 | byte 6-7 |
|---|---|---|---|---|---|
| PCI | 22 | DID_H | DID_L | DID_2(H+L) | Padding |
| 单帧标识 | SID = 0x22 | 数据标识符 DID(2字节/组,可多组) | 填充 FF |
关键点说明:
- byte 0(PCI):CAN 总线协议控制信息。如果是单帧,高 4 位为 0,低 4 位为数据长度(如
02表示 2 字节数据)。 - byte 1(SID):固定为
0x22,标识这是 ReadDataByIdentifier 服务。 - byte 2-3(DID):数据标识符的高字节和低字节。例如
F1 90表示 DID = 0xF190(零件编号)。 - 多 DID:如果要一次读多个 DID,就接着写
DID2_H DID2_L DID3_H DID3_L ...。 - Padding:CAN 报文不足 8 字节时用
0xFF填充。
常用 DID 定义表
| DID | 名称 | 说明 |
|---|---|---|
0xF190 | 零件编号 | Part Number,ECU 的零件标识 |
0xF187 | ECU 序列号 | 每个 ECU 的唯一序列号 |
0xF191 | 供应商编号 | ECU 制造商标识 |
0xF195 | Boot 软件版本号 | Bootloader 版本信息 |
0xF196 | 应用软件版本号 | Application Software 版本信息 |
0xF197 | 应用软件版本号名称 | 版本号的字符串表示 |
0xF198 | Boot 软件版本号名称 | Bootloader 版本号字符串 |
3.2 肯定响应报文
ECU 成功读取到 DID 数据后,返回肯定响应:
| byte 0 | byte 1 | byte 2 | byte 3 | byte 4-5 | byte 6~N |
|---|---|---|---|---|---|
| PCI | 62 | DID_H | DID_L | DID回显 | DataRecord |
| 单帧/多帧 | 0x22 + 0x40 | 请求DID回显 | (多DID时) | DID指向的数据 |
关键点说明:
- byte 1(响应 SID):肯定响应 SID = 请求 SID + 0x40,所以
0x22 + 0x40 = 0x62。这是 UDS 协议的通用规则,所有服务都遵循。 - byte 2-3(DID 回显):ECU 会把请求中的 DID 原样回显,告诉你"我返回的是这个 DID 的数据"。
- byte 6~N(DataRecord):DID 对应的实际数据内容,长度由 DID 定义决定。如果是多 DID 请求,则
DID1数据 + DID2数据 + ...依次排列。
多帧传输:数据超过 8 字节怎么办?
CAN 总线单帧最多传 8 字节数据。如果 ECU 响应数据超过 8 字节(比如读取零件编号字符串),就需要使用 ISO-TP 多帧传输:首帧(First Frame)+ 流控帧(Flow Control)+ 连续帧(Consecutive Frame)。这个过程对诊断仪是透明的,但抓包时你会看到多帧交互。
3.3 否定响应报文
当 ECU 无法处理请求时,返回否定响应(NRC,Negative Response Code):
| byte 0 | byte 1 | byte 2 | byte 3 | byte 4-7 |
|---|---|---|---|---|
| PCI | 7F | 22 | NRC | Padding |
| 单帧标识 | 否定响应SID | 原服务SID | 错误码 | 填充FF |
关键点说明:
- byte 1:固定
0x7F,标识这是否定响应。 - byte 2:原服务 SID,告诉你"是哪个服务出错了",这里是
0x22。 - byte 3(NRC):具体的错误码,告诉你"为什么出错"。这是排查问题的关键。
四、实战示例:读取 ECU 软硬件版本号
说了这么多格式,不如来一个真实案例。假设我们要读取 ECU 的零件编号(DID = 0xF190),整个交互过程如下:
图 4:0x22 实战示例——从请求发起到数据解析的完整流程
第一步:诊断仪发送请求
Tx: 03 22 F1 90 FF FF FF FF解读:03= 单帧,3 字节数据 →22= SID →F1 90= DID 0xF190(零件编号)→ 剩余填充FF。
第二步:ECU 返回肯定响应
Rx: 10 0E 62 F1 90 34 31 54 ← 首帧 21 42 2D 30 30 31 32 33 ← 连续帧 1 22 34 00 00 00 00 00 00 ← 连续帧 2解读:
10 0E= 首帧,总数据长度 14 字节62= 肯定响应 SID(0x22 + 0x40)F1 90= DID 回显34 31 54 42 2D 30 30 31 32 33 34= ASCII 编码的零件编号 “41TB-001234”
第三步:解析数据
将响应中的 DataRecord 部分(34 31 54 42 2D 30 30 31 32 33 34)按 ASCII 解码,得到零件编号字符串:“41TB-001234”。
同理可以读取更多 DID:
- DID 0xF187 → 序列号 = “SN202401150001”
- DID 0xF195 → Boot 软件版本 = “V1.2.0”
- DID 0xF196 → 应用软件版本 = “V2.3.1”
测试时建议一次性读取这些版本信息,确认 ECU 版本正确后再进行后续测试。
五、NRC 错误处理:7 种错误码全解析
0x22 服务支持 7 种 NRC(否定响应码)。ECU 在收到请求后,会按照固定的优先级顺序进行检查,一旦某项检查不通过,就立即返回对应的 NRC。
图 5:0x22 服务 NRC 错误处理流程——ECU 的 7 步检查链
NRC 错误码一览表
| NRC | 名称 | 含义 | 触发场景 |
|---|---|---|---|
0x11 | serviceNotSupported | 服务不支持 | ECU 根本不支持 0x22 服务 |
0x7F | serviceNotSupportedInActiveSession | 当前会话不支持 | 0x22 仅在特定会话模式下可用 |
0x13 | incorrectMessageLengthOrInvalidFormat | 报文长度或格式错误 | 请求报文长度不正确、DID 不是偶数对等 |
0x14 | responseTooLong | 响应数据过长 | 请求的多个 DID 数据总量超过 ECU 响应能力 |
0x22 | conditionsNotCorrect | 条件不满足 | ECU 当前运行状态不允许读取该 DID(如正在刷写中) |
0x31 | requestOutOfRange | DID 不支持 | 请求的 DID 未定义或超出 ECU 支持范围 |
0x33 | securityAccessDenied | 安全访问被拒 | 该 DID 需要先通过 0x27 安全解锁才能读取 |
NRC 检查优先级
ECU 收到 0x22 请求后,会按照以下优先级依次检查(图 5 详细流程):
- 优先级 1-2(协议层校验):先检查 ECU 是否支持 0x22 服务(NRC 0x11),再检查当前会话是否支持(NRC 0x7F)。
- 优先级 3-4(格式/数量校验):检查报文长度是否正确(NRC 0x13),再检查 DID 数量是否超限(NRC 0x14)。
- 优先级 5-7(功能/运行时校验):检查安全解锁状态(NRC 0x33),检查 DID 是否支持(NRC 0x31),最后检查执行条件(NRC 0x22)。
NRC 优先级的重要性
理解 NRC 优先级对测试至关重要。例如,如果某个 DID 既需要在非默认会话下读取,又需要安全解锁,那么在默认会话且未解锁时发送请求,ECU 会优先返回 NRC 0x7F(会话不支持),而不是 NRC 0x33(安全访问被拒)。测试时需要逐级满足前置条件,才能测到后续的 NRC。
六、0x22 服务测试六大关注点
22 服务对照项目的诊断规范用起来很简单,但实际测试中还是会遇到一些典型问题。以下六大测试关注点是实战经验的总结,每个都是容易踩坑的地方。
图 6:0x22 服务测试六大关注点——实战踩坑经验总结
1、ECU 版本正确性问题
不论是功能测试、协议测试还是诊断本身的测试,测试前用 22 服务读取 ECU 软硬件版本号是一个必要习惯。别等问题查了一圈,最后发现是版本不对导致的。一句话:先读版本,再开测。
2、无效 DID 处理问题
注意验证 DID 的边界值0x0000和0xFFFF,以及 ECU 不支持的 DID 编号。预期行为是返回 NRC 0x31(requestOutOfRange),而不是挂死或返回错误数据。
3、会话模式问题
某些 DID 只能在非默认会话(如扩展会话、编程会话)下读取。测试时需要在默认会话和非默认会话下分别测试,验证 DID 的读取权限是否符合诊断规范定义。
4、安全依赖问题
某些 DID 需要先通过 0x27 安全访问(SecurityAccess)解锁后才能读取。测试时需要在未解锁和解锁两种状态下都执行测试:未解锁时应返回 NRC 0x33,解锁后应正常返回数据。
5、数据一致性问题
对于 ECU 内部的变化数据(如传感器值、运行状态),需要先做仿真输入,再通过 0x22 读取,验证返回数据与仿真输入的实时一致性。防止出现"读了但数据不对"的隐蔽问题。
6、ECU 处理性能问题
当同时请求多个 DID 时,注意验证 ECU 的响应时间参数 P2server(服务端响应时间)。确保 ECU 的处理性能满足规范要求,不会因为多 DID 请求导致超时。一般要求 P2server 不超过 50ms(具体值参照 OEM 规范)。
七、总结:一张表回顾 0x22 核心
| 维度 | 核心要点 |
|---|---|
| 服务定位 | UDS 中使用频率最高的数据读取服务,按 DID 标识符读取 ECU 数据 |
| 数据类型 | 内部数据(版本号/序列号)+ 标定参数 + 系统状态 |
| 请求格式 | SID(0x22) + DID_H + DID_L + [DID2_H + DID2_L + …] |
| 肯定响应 | SID(0x62) + DID回显 + DataRecord |
| 否定响应 | 0x7F + 0x22 + NRC(7种错误码) |
| 测试要点 | 版本验证、DID边界值、会话权限、安全解锁、数据一致性、响应性能 |
个人理解,有误指正
本文基于 ISO 14229-1 协议和实际测试经验整理,部分内容为个人理解。如有错误,欢迎指正。更多协议细节,请查阅 ISO 14229-1 协议原文。
本文基于 ISO 14229-1 协议整理,仅供学习交流