2. UDS协议栈基础:UDS协议栈架构、应用层、会话层、网络层、数据链路层、物理层
好,咱们进入第二章。这一章,我打算把UDS协议栈的骨架给你拆开看看。
很多人一上来就啃ISO 14229-1,结果被那一堆状态机、定时器、服务ID搞得晕头转向。其实没必要。你想想看,UDS协议栈说白了就是一套“汽车ECU的沟通规则”。它规定了:谁先说话、说什么、怎么说、说错了怎么办。
我个人习惯,把UDS协议栈分成五层来理解。从下往上分别是:物理层、数据链路层、网络层、会话层、应用层。嗯,咱们一层一层剥开它。
2.1 协议栈整体架构
先给你看个总览图,心里有个谱。
| OSI七层模型 | UDS协议栈对应层 | 核心协议/标准 | 我眼中的职责 |
|---|---|---|---|
| 应用层 (Layer 7) | UDS应用层 | ISO 14229-1 | 定义诊断服务(读数据、写数据、例程等) |
| 表示层 (Layer 6) | (合并到应用层) | - | 数据编码格式(比如Intel/Motorola格式) |
| 会话层 (Layer 5) | UDS会话层 | ISO 14229-2 | 管理诊断会话(默认、扩展、编程)和定时参数 |
| 传输层 (Layer 4) | (由网络层承载) | - | 分段传输的大数据包(比如刷写文件) |
| 网络层 (Layer 3) | UDS网络层 | ISO 15765-2 (DoCAN) | 单帧/多帧传输、流控制、地址寻址 |
| 数据链路层 (Layer 2) | CAN数据链路层 | ISO 11898-1 | CAN帧的封装、仲裁、错误检测 |
| 物理层 (Layer 1) | CAN物理层 | ISO 11898-2 | 差分信号、电平转换、总线拓扑 |
这张表,我建议你收藏一下。每次调试遇到问题,先定位是哪一层出的问题,能省不少时间。
2.2 物理层:信号怎么跑
物理层,就是最底层的“电线”。在车载诊断里,最常见的就是CAN总线物理层。
说白了,就是两根线:CAN_H和CAN_L。通过差分电压来传递0和1。为什么用差分?抗干扰能力强。你想想看,发动机舱里电磁干扰那么大,单端信号早被干废了。
关键参数:
- 波特率: 诊断常用250kbps或500kbps。我遇到过一些老车型,只能用125kbps,慢得让人抓狂。
- 终端电阻: 120Ω,必须加在总线两端。有一次我在台架上调试,忘了接终端电阻,波形乱七八糟,查了半天才发现。
- 隐性/显性: 隐性=1(CAN_H≈2.5V,CAN_L≈2.5V),显性=0(CAN_H≈3.5V,CAN_L≈1.5V)。显性会覆盖隐性。
2.3 数据链路层:帧怎么传
数据链路层,负责把物理层的比特流,组装成有意义的“帧”。在CAN总线里,就是CAN帧。
一个标准的CAN数据帧长这样:
| SOF | 仲裁场(11/29bit ID) | 控制场(IDE, DLC) | 数据场(0-8字节) | CRC场 | ACK场 | EOF |
这里我只强调几个对UDS重要的点:
- CAN ID: 诊断请求和响应使用不同的ID。比如请求ID 0x7DF,响应ID 0x7E8。这是物理寻址。
- DLC(数据长度码): 表示数据场有多少字节。UDS的CAN帧,DLC最大是8(经典CAN)或64(CAN FD)。
- 数据场: 这才是UDS协议真正关心的内容。网络层的数据,就塞在这里面。
嗯,这里要注意:CAN数据链路层只保证一帧数据不出错。但如果UDS报文超过8字节,就需要网络层来拆包和重组了。
2.4 网络层:数据太大怎么办
网络层,这是UDS协议栈里最“烧脑”的一层,也是ISO 15765-2的核心内容。
为什么需要网络层?因为UDS的一个诊断请求,可能包含几十甚至几百字节(比如刷写ECU的bin文件)。但CAN一帧最多只能发8字节。怎么办?拆!
网络层定义了四种帧类型:
| 帧类型 | PCI字节(协议控制信息) | 作用 |
|---|---|---|
| 单帧 (SF) | 0x0 + 数据长度 | 报文长度 ≤ 7字节时使用 |
| 首帧 (FF) | 0x1 + 数据长度(高4位+低8位) | 多帧传输的第一帧,告知总长度 |
| 连续帧 (CF) | 0x2 + 序列号(SN) | 后续数据帧,SN从1开始循环 |
| 流控制帧 (FC) | 0x3 + 流状态(FS) + 块大小(BS) + 最小间隔时间(STmin) | 接收方告诉发送方:慢点发/继续发/别发了 |
我举个例子,你马上就懂了。假设你要发送一个20字节的诊断请求:
- 发送方: 先发一个首帧(FF),告诉接收方“我要发20字节”。
- 接收方: 收到FF后,回复一个流控制帧(FC),说“我知道了,你一次发2帧,每帧间隔5ms”。
- 发送方: 按照FC的要求,发送连续帧(CF),每帧带2字节数据,直到发完。
2.5 会话层:ECU在什么状态
会话层,负责管理ECU的“诊断会话状态”。说白了,就是ECU现在愿不愿意理你。
UDS定义了三种默认会话:
- 默认会话 (Default Session): 上电后的初始状态。只能执行一些“安全”的服务,比如读故障码。不能刷写。
- 扩展会话 (Extended Session): 允许执行一些“非安全”但非破坏性的服务,比如读写参数、调整配置。
- 编程会话 (Programming Session): 最高权限。可以刷写ECU固件。进入此会话前,通常需要安全访问解锁。
会话切换是通过10 02(进入扩展)或10 03(进入编程)服务实现的。ECU会回复一个50 02或50 03表示成功。
2.6 应用层:真正干活的地方
应用层,就是ISO 14229-1定义的那些诊断服务。这是咱们最终要打交道的地方。
应用层的报文结构很简单:
| 服务ID (SID) | 子功能 (Sub-function) | 数据参数 (Data) |
比如:
22 F1 90:读取DID(数据标识符)F190的值。SID=0x22,子功能=0xF190(其实是数据参数)。2E F1 90 01 02 03 04:向DID F190写入4个字节的数据。31 01 FF 00:启动例程ID为FF00的例程。
应用层还定义了“否定响应码”(NRC)。比如:
| NRC | 含义 | 常见场景 |
|---|---|---|
| 0x10 | 一般拒绝 | 请求格式不对 |
| 0x22 | 条件不满足 | 没切到正确会话就发请求 |
| 0x31 | 请求超出范围 | DID或RID不存在 |
| 0x33 | 安全访问拒绝 | 没解锁就尝试刷写 |
| 0x78 | 请求正确接收,正在处理 | ECU需要时间处理,让你等着 |
我个人习惯,在写代码前,先把所有可能用到的NRC列个表。这样调试时,看到ECU回了个0x33,我马上就知道是安全访问没通过。
2.7 各层之间的协作
最后,咱们串一下。一个完整的UDS请求,从诊断仪到ECU,是怎么走的?
- 应用层: 诊断仪构造一个请求,比如
22 F1 90(读数据)。 - 会话层: 检查当前会话是否允许执行0x22服务。如果不允许,直接返回NRC 0x22。
- 网络层: 如果请求长度≤7字节,封装成单帧(SF)。如果超过,拆成多帧。
- 数据链路层: 把网络层的帧,塞进CAN帧的数据场,加上CAN ID和CRC。
- 物理层: 通过CAN_H和CAN_L,把比特流发到总线上。
ECU收到后,反向解析:物理层→数据链路层→网络层→会话层→应用层,然后执行服务,再按同样的路径返回响应。
下一章,咱们会深入应用层,把那些常用的诊断服务一个一个讲透。到时候,你就可以自己动手写诊断请求了。