Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第二章 UDS协议深度解析 —— 基于ISO 14229-1:2013

2.1 UDS服务全景——26个SID的地图

ISO 14229-1:2013 被你翻开第一页

你面前是这本ISO标准。如果你按传统读法——从第1页读起,第6页开始读到应用层服务定义、第9章开始逐个SID按字母序排列——不到第9章的1/3你就会昏睡过去。

这不是因为内容不精深——而是因为标准按照抽象层级组织,不按使用场景组织。你读完0x10的详细语义,接下去是0x11 ECU复位——两者的使用频率、关联场景、在诊断流程中的位置完全不同,但标准把它们按SID数值顺序排列。这就像一本字典把“挂号“和“截肢“紧接着编排——它们字序相邻,在现实世界里隔着门诊、检查、确诊、麻醉整整一条流程。

这一节的目标不是教你每个SID的报文细节(后面17节会帮你做这件事),而是给你画一张全景地图——让你在进入每一个SID的细节之前,知道自己在这个巨大的26格棋盘上站在哪个位置。


SID的地图:四大功能单元

ISO 14229-1:2013定义的功能单元是六类,但从诊断仪-ECU交互的认知流程出发,可以被更自然地合并为四层:

:本图的“层“表示诊断流程中的调用顺序,并非OSI七层模型中的层。

                  SID范围
                  ────────
┌────────────────────────────────────────────────────┐
│  第四层:诊断和通信管理(会话、权限、连接)               │
│  0x10 会话控制  0x11 ECU复位   0x27 安全访问          │
│  0x28 通信控制  0x3E 诊断仪保活 0x85 控制DTC设置       │
│  0x83 访问时序  0x84 安全传输  0x86 事件响应 0x87 链路 │
├────────────────────────────────────────────────────┤
│  第三层:数据传输(读取和写入运行参数)                   │
│  0x22 按DID读   0x2E 按DID写    0x23 按地址读内存      │
│  0x3D 按地址写  0x2A 周期读取   0x2C 动态定义DID        │
├─────────────────────────────────────────────────────┤
│  第二层:存储的数据(故障码的读写)                       │
│  0x19 读DTC     0x14 清除DTC                         │
├─────────────────────────────────────────────────────┤
│  第一层:主动控制与固件操作(对ECU做手术)                │
│  0x2F IO控制    0x31 例行控制                         │
│  0x34 请求下载  0x35 请求上传  0x36 传输数据  0x37 退出  │
└──────────────────────────────────────────────────────┘

  所有SID的正响应码 = 请求SID + 0x40
  负响应的SID固定为 0x7F

第四层在最上面——因为它是最先被调用的(你连会话都没建立,就不能读DTC、不能写DID、不能下载)。第一层在最下面——因为它是最“重“的操作(刷写固件是整个诊断流程的终点,不是起点)。

核心洞察:这四层不是标准的文本顺序——是诊断认知的依赖顺序。你不能在没挂号(建立会话)之前就开药(写DID、下载固件)。你也不能在没看症状(读DTC)之前就决定做什么手术(刷写固件)。UDS的服务编排不是随机的——它是一棵树,根是会话控制,叶是固件下载。


主谓宾结构:C/S模型的固定语法

在UDS通信里,这两句话永远成立:

  1. 诊断仪发起请求,ECU返回响应。 没有例外。ECU永远不会主动发起一个UDS请求——它只答复。
  2. 每一个请求对应至多一个响应。 要么正响应(成功+数据),要么负响应(失败+原因码),要么(在功能寻址+suppressPosRsp条件下)无响应。

这在形式上非常类似HTTP的Request-Response模型——但UDS更加严格地遵守“一请求、一响应“。HTTP有Server-Sent Events、WebSocket升级、100 Continue中间响应的概念——UDS没有任何“流式响应“或“推送“机制。ResponseOnEvent(0x86)是ECU“主动发送数据“的唯一方式,但这也严格绑定到诊断仪先在0x86请求里注册事件——是准主动


全部26个SID一览

SID (十六进制)正响应SID服务名称子功能一句话概括
0x100x50诊断会话控制挂号——切换诊断会话(默认/编程/扩展/安全系统)
0x110x51ECU复位重启——hardReset/keyOffOnReset/softReset
0x140x54清除诊断信息删除病历——按groupOfDTC清DTC/快照/扩展数据
0x190x59读DTC信息查看症状——18种子功能覆盖DTC的所有查询维度
0x220x62按标识符读数据开化验单——读一个或多个DID的当前值
0x230x63按地址读内存按物理地址读内存,走地址+长度格式
0x240x64按标识符读缩放数据读DID的缩放定义(物理单位和范围)
0x270x67安全访问病历授权——Seed/Key解锁安全等级
0x280x68通信控制屏蔽噪音——关闭/开启ECU特定类型的通信
0x2A0x6A按标识符周期读取持续监控——让ECU定期自动上报DID值
0x2C0x6C动态定义DID自定义化验单——诊断仪临时定义DID的组成
0x2E0x6E按标识符写数据调整参数——写一个DID的值(覆盖当前值)
0x2F0x6F按标识符IO控制触诊——短期替代某个DID值以观察系统行为
0x310x71例行控制治疗——启动/停止/获取例行程序的结果
0x340x74请求下载手术准备——声明数据格式/地址/长度,获取下载授权
0x350x75请求上传上传准备——声明数据格式/地址/长度,获取上传授权
0x360x76传输数据手术传送——传输实际的数据块(下载或上传)
0x370x77请求传输终止手术结束——完成数据传输,验证并退出
0x380x78请求文件传输文件系统操作——传输文件。本书不展开,在实际量产项目中极少使用
0x3D0x7D按地址写内存按物理地址写内存,直接操作非易失存储
0x3E0x7E诊断仪保活有(子功能控制ECU是否回复)医生还在——诊断仪发心跳防会话超时
0x830xC3访问时序参数协商时序——动态修改P2/P2*超时
0x840xC4安全数据传输加密隧道——在逐服务基础上传输加密数据
0x850xC5控制DTC设置暂停记录——关闭/开启DTC状态位更新
0x860xC6事件响应事件驱动推送——让ECU在特定事件发生时主动发数据
0x870xC7链路控制波特率切换——将诊断仪的K-Line波特率(遗留功能)

“子功能“列说明:“有“表示报文包含子功能字节(SubFunction),用于进一步指定操作模式;“无“表示报文中没有子功能字节,而非子功能值为0x00。

:0x23、0x24、0x83、0x84、0x87这5个SID未设独立章节——它们在量产诊断场景中极少使用。0x23(按地址读)被0x22(按DID读,语义化寻址)替代;0x24(读缩放定义)依赖ODX文件而非在线查询;0x83(访问时序参数)P2/P2*值通常在0x10正响应中一次协商;0x84(安全数据传输)协议栈过于复杂且多数ECU未实现;0x87(链路控制)为K-Line波特率切换,在CAN/DoIP时代已基本废弃。


每一个SID都有“为什么存在“的故事

从历史发展的角度看,这26个SID不是一次性设计的——它们是逐层堆叠的:

第一波(OBD-II遗留,1996):0x22读数据、0x19读DTC、0x14清除DTC——这是OBD-II的Mode 0x01、0x03和0x04的UDS化。排放诊断必须得有这些。

第二波(KWP2000进化,2000):0x10会话控制、0x11 ECU复位、0x27安全访问——KWP2000把“修车不仅限于看故障码“的需求带了进来。你要执行主动治疗和安全操作——不能直接做,得先挂号、先授权、先确认你可以做。

第三波(CAN适配,2003-2006):0x34/0x35/0x36/0x37下载上传、0x28通信控制、0x3E保活——CAN总线带来了两个新需求:(1) 大块数据的分段传输;(2) 共享总线上通信的管理(刷写时要把应用报文关掉)。0x3E是应对“S3会话超时“的独立需求——诊断仪必须持续证明自己在线。

第四波(现代汽车电子,2013+):0x2F IO控制、0x31例行控制、0x2A周期读取、0x86事件响应——这些是控制功能的深化。现代车有几百个执行器、几十个例行程序(ABS自检、ADAS标定、电池平衡……),诊断已经不是“读故障码修车“,而是通过诊断接口重新标定、重新编程、重新校准整辆车的子系统。


为什么是26个而不是30个或15个

你可能会想:为什么不是把0x23(按地址读)和0x22(按DID读)合并?为什么还需要两个“读数据“的SID?为什么0x84(安全数据传输)独立而不是作为0x27的子功能?为什么0x86(事件响应)不和0x2A(周期读取)合并?

这些“为什么不合并“的问题,在标准文本里是找不到答案的——它们每一个都有一段真实的历史:

  • 0x22 vs 0x23(DID读取 vs 地址读取):0x22是面向应用层的——DID是对传感器、配置参数、标定数据集的语义化命名。0x23是面向存储层的——直接按物理地址读内存。前者是“给我发动机转速“,任何ECU的硬件都能支持(因为ECU自己维护DID到地址的映射)。后者是“给我0x40024000的内容“,只有调试和工厂编程才用到。两者面对的是两种不同角色——诊断技师和ECU标定/安全工程师。

  • 0x27 vs 0x84(安全访问 vs 安全数据传输):0x27是会话级的鉴权——你解锁之后,所有后续请求都拥有安全等级。0x84是消息级的加密——即使你的会话已被解锁,某些极其敏感的数据(比如密钥材料的交换)还需要端到端加密+MAC签名,防止中间人窃听。前者解决“你是谁“的身份问题,后者解决“你的消息在传输的路上会不会被偷看/篡改“。这是正交的两个维度。

  • 0x2A(周期读取)和0x86(事件响应):它们共享“让ECU主动发送数据“的性子——但触发机制完全不同。0x2A是定时器驱动——“每500ms把三个DID的值发给我”。0x86是事件驱动——“当DTC状态发生任何变化时发给我”。这是时间轴上的两种不同采样模式。

核心洞察:每一个SID的“为什么不合并“背后都有一个两难权衡——合并可以简化接口面,但会混淆语义、导致一个SID承担太多不相关的职责。SID的粒度是ISO技术委员会经过长达数年的讨论确定的——最终这26个被认定是最小充分集合。少一个则不够(某些生产必需的功能没有标准接口),多一个则冗余(两个SID之间有重叠职责,增加实现的复杂度而几乎不增加新能力)。


哪些仅能在非默认会话中使用

UDS有一个严格的访问控制矩阵——不是所有SID都能在默认会话(0x01)中使用。这是为了确保普通的OBD-II扫描仪不能意外地触发敏感操作:

会话限制SID
任何会话都可用(包括默认)0x10 会话控制、0x11 复位、0x3E 保活、0x14 清除DTC、0x19 读DTC、0x22 读DID、0x23 读地址、0x24 读缩放、0x2E 写DID、0x3D 写地址、0x86 事件响应
仅非默认会话(扩展/编程/安全)0x27 安全访问、0x28 通信控制、0x2A 周期读、0x2C 动态DID、0x2F IO控制、0x31 例行控制(受安全限制)、0x34/35/36/37/38 上下传、0x83/0x84/0x85/0x87

核心洞察:这张表解释了UDS的“挂号“逻辑——默认会话是一个公共可读空间(可清除DTC,不可修改配置或执行控制)——你进入这个空间不需要任何权限,但要控制做手术——必须挂到其他号。这是服务粒度和安全策略之间的平衡:读数据门槛极低(不用解锁),写和控制必须显式进入专门会话。


SID地图的医院化映射

给你一张对照表,帮你把这些冰冷的SID数字翻译成你已经在第1.5节亲历过的诊断流程:

诊断阶段UDS服务医院映射什么时候调用
挂号0x10选择科室第一步——每次诊断会话的第一条请求
心跳0x3E医生巡视每一次“诊察“的每个周期——防止你的session过期
授权0x27获取病历权限敏感的读/写/控制操作之前
查病史0x19读病历收集DTC、锁定症状发生的背景数据
开化验0x22抽血/拍片实时读取发动机转速、传感器、配置参数
自定义化验0x2C自拟化验项目临时定义一个DID代表你关心的参数组合
持续监测0x2A24小时心电图让ECU自动周期性地发新数据
触诊0x2F按压、叩诊临时假写一个参数值观察系统反馈
治疗0x31执行治疗方案触发ABS自检、ADAS重标定
调参0x2E调整药量修改标定值、配置参数
手术准备0x34手术授权声明刷写地址和长度
手术进行0x36输血/移植传送每一块固件数据
手术结束0x37拆线/缝合校验下载完整性并退出传输模式
清除病历0x14病历更新修好后清除已完成的症状记录
重置病人0x11让病人重启刷写后复位到正常状态
暂停监控0x85暂停信号采集不让DTC在刷写过程中误报
屏蔽噪音0x28关掉多余的监护器刷写期间停掉应用报文防冲突
事件推送0x86护士按铃值监控到异常自动通知医生

你此刻可能会有点迷:这么多服务,它们的交互逻辑和依赖关系到底怎么理清楚?别急。先从最底层的报文格式开始——你先把“语言“的语法学会,后面每一句“话“的语义就容易了。


本篇小结

  1. UDS的26个SID不是按数值顺序排列的结果——它们是一棵依赖树,根是会话控制0x10,叶是0x34/36/37固件下载。理解SID的依赖层级比记住每个SID的数字更重要。
  2. 正响应SID = 请求SID + 0x40。这是UDS协议的核心编码约束——不是可选的模板,是固定规则。负响应统一走0x7F + 原SID + NRC。
  3. 从历史发展看,SID集合的每一波增长都对应一个实在的工程需求——OBD-II(1996)→KWP2000(2000)→CAN适配(2003-2006)→现代控制(2013+)。没有凭空设计的SID。
  4. 默认会话和非默认会话的访问控制矩阵是UDS安全体系的第一道墙——所有写/控制/下载操作都必须离开默认会话才能进行。

【下集预告】:地图归地图,你还要学会说第一句’话’——UDS报文到底由哪些字节组成?SID、SubFunction、DataParameter是怎么组的?正响应报文里为什么没有SID只有一个SID+0x40?负响应的三个字节里每个字节分别代表什么?我们拆报文——从人类语音到CAN帧里从左到右的每一个bit。