2、UDS协议栈:从物理层到应用层的完整拆解

做诊断开发这些年,我见过不少工程师一上来就盯着应用层的DID和DTC,结果遇到通信问题就抓瞎。说白了,UDS能跑起来,靠的是下面几层协议栈的默契配合。今天我就带你把这五层结构拆开看看。

核心认知:UDS协议栈不是凭空存在的,它寄生在CAN、LIN、以太网等底层总线上。理解分层,才能精准定位问题。

2.1 协议栈全景:五层架构

UDS协议栈遵循OSI七层模型的简化版,在汽车领域我们通常只看五层。我习惯把它比作一个快递系统——物理层是公路,数据链路层是交通规则,网络层是分拣中心,会话层是客服,应用层才是你填的快递单。

UDS协议栈五层架构 应用层(Application Layer) UDS服务:诊断会话控制、读取DID、写入数据、例程控制、DTC操作 会话层(Session Layer) 定时管理、地址管理、会话状态机(默认/扩展/编程) 网络层(Network Layer) ISO 15765-2:单帧/多帧传输、流控制、分段重组 数据链路层(Data Link Layer) CAN控制器:帧格式、仲裁、错误检测、位填充 物理层(Physical Layer) ISO 14229-1 ISO 11898 / 15765

这张图我建议你存下来。每次遇到诊断通信问题,先定位是哪一层出的问题,比瞎猜高效得多。

2.2 物理层:信号的基础

物理层负责把0和1变成电信号。在CAN总线里,就是CAN_H和CAN_L两根线的差分电压。说白了,这一层不关心你传的是什么数据,只关心信号能不能从A点完整到B点。

参数高速CAN(ISO 11898-2)低速CAN(ISO 11898-3)
最大速率1 Mbps125 kbps
总线长度≤ 40 m @ 1 Mbps≤ 500 m
显性电平CAN_H ≈ 3.5V, CAN_L ≈ 1.5VCAN_H ≈ 3.6V, CAN_L ≈ 1.4V
隐性电平CAN_H ≈ 2.5V, CAN_L ≈ 2.5VCAN_H ≈ 1.5V, CAN_L ≈ 3.6V
终端电阻120 Ω(两端)无固定终端
我曾经踩过的坑:有一次台架测试,诊断仪总是间歇性超时。查了两天,最后发现是CAN_H线在连接器处有0.3Ω的接触电阻。0.3Ω啊,平时根本不会在意,但在1Mbps下就是致命问题。物理层的故障往往最隐蔽。

2.3 数据链路层:CAN帧的规矩

数据链路层负责把物理层的比特流组织成有意义的帧。CAN 2.0标准定义了两种帧格式:标准帧(11位ID)和扩展帧(29位ID)。UDS诊断通常使用扩展帧,因为需要更多的地址空间。

一个CAN数据帧的结构是这样的:

SOF | 仲裁场(11/29位ID + RTR + IDE) | 控制场(4位DLC) | 数据场(0-8字节) | CRC场(15位) | ACK场 | EOF

嗯,这里要注意:UDS的请求和响应,就是塞在数据场这0-8个字节里的。如果诊断数据超过8字节,就得靠网络层来分包了。

我的习惯:在项目初期,我会用CANoe或PCAN抓一下总线上的原始CAN帧,确认ID、DLC和数据场格式对不对。这一步能省掉后面80%的通信层调试时间。

2.4 网络层:ISO 15765-2的核心

网络层是UDS协议栈里最容易被忽视、但也是最容易出问题的一层。它负责把超过8字节的诊断消息拆成多个CAN帧发送,再在接收端重组。这个机制叫多帧传输。

ISO 15765-2定义了四种协议数据单元(PDU)类型:

  • 单帧(SF):数据长度 ≤ 7字节,一帧搞定
  • 首帧(FF):多帧传输的第一帧,包含总数据长度
  • 连续帧(CF):后续的数据帧,带序列号
  • 流控制帧(FC):接收方告诉发送方“慢点发”或“继续发”

多帧传输的流程,我画了个图:

多帧传输流程(ISO 15765-2) 诊断仪(发送方) ECU(接收方) ① 首帧(FF):总长度=20字节 ② 流控制帧(FC):BS=2, STmin=10ms ③ 连续帧(CF):SN=1 ④ 连续帧(CF):SN=2 ⑤ 连续帧(CF):SN=3(最后一帧) BS:块大小 STmin:最小间隔时间
关键参数:BS(Block Size)和STmin(Separation Time minimum)是流控制帧里的两个核心参数。BS告诉发送方一次最多发几帧,STmin要求帧间至少间隔多少毫秒。我见过有些ECU把STmin设成0,结果高速CAN上连续帧丢包率飙升。

2.5 会话层:状态机与定时器

会话层管理诊断会话的状态。UDS定义了三种会话:默认会话(Default Session)、扩展会话(Extended Session)和编程会话(Programming Session)。ECU上电后默认在默认会话,只有切换到扩展或编程会话才能执行某些敏感服务(比如写入数据、刷写固件)。

会话层还负责三个定时器:

定时器默认值作用
P2_Server50 msECU处理请求的最大时间(正常响应)
P2*_Server5000 msECU处理请求的最大时间(需要额外时间时,先发NRC 0x78)
S3_Server5000 ms会话超时时间,超时后自动回到默认会话
我曾经遇到的坑:有个项目,诊断仪发完请求后ECU总是回NRC 0x78(待处理),然后P2*计时器跑完才给响应。查了半天,发现是ECU的P2_Server设得太短,只有20ms,而实际处理需要30ms。每次都在超时边缘试探。后来把P2_Server改成80ms,世界清净了。

2.6 应用层:UDS服务

应用层就是我们最熟悉的UDS服务了。ISO 14229-1定义了六大类服务,每个服务用一个SID(Service Identifier)标识:

  • 诊断和通信管理(0x10~0x3E):会话控制、ECU复位、安全访问、通信控制等
  • 数据传输(0x22~0x2E):读取/写入DID、读取内存等
  • 存储数据传输(0x14~0x19):读取/清除DTC、读取DTC信息等
  • 输入输出控制(0x2F):控制外部输出信号
  • 例程(0x31):启动/停止/请求例程结果
  • 上传下载(0x34~0x37):固件刷写、数据上传下载

一个典型的UDS请求格式是这样的:

请求:SID + Sub-function + 数据参数
响应:SID+0x40 + 数据参数(肯定响应)
      0x7F + SID + NRC(否定响应)
我的建议:刚开始学UDS,别急着背所有SID。先把0x10(诊断会话控制)、0x22(读取DID)、0x2E(写入DID)、0x19(读取DTC)这四个搞熟,覆盖了日常80%的诊断场景。

2.7 各层之间的协作

你想想看,当诊断仪发送一个“读取VIN码”的请求时,数据是怎么从应用层一路走到物理层的?

  1. 应用层:构造0x22服务请求,VIN码的DID是0xF190,数据参数为空
  2. 会话层:检查当前会话是否允许执行0x22服务,更新定时器
  3. 网络层:如果请求长度≤7字节,封装成单帧;否则拆成多帧
  4. 数据链路层:加上CAN帧头(ID、DLC、CRC等),准备发送
  5. 物理层:把帧转换成差分电压信号,放到CAN总线上

ECU收到后,逆向走一遍:物理层收信号→数据链路层解帧→网络层重组→会话层检查→应用层执行服务→再原路返回响应。

一句话总结:UDS协议栈的每一层各司其职,上层只管业务逻辑,下层只管传输。这种分层设计让诊断开发变得模块化——你改应用层的服务逻辑,完全不用动网络层的分包代码。

好了,协议栈的骨架搭起来了。下一层一层地,我们后面会逐个深入。记住这个五层结构,它是你诊断开发的地基。