第3章:UDS物理层与数据链路层——CAN总线基础回顾

各位同学,欢迎来到第三章。这一章我们聊聊UDS的根基——CAN总线。说实话,很多做UDS开发的朋友,代码写得飞起,但一问到CAN帧怎么跟UDS报文对应,就有点含糊了。我个人觉得,这块不搞清楚,后面调试起来会非常痛苦。

3.1 CAN总线基础:物理层与数据链路层

CAN总线,全称Controller Area Network,是汽车电子系统的"神经系统"。它工作在OSI模型的第一层(物理层)和第二层(数据链路层)。

物理层,说白了就是电信号怎么传。CAN总线用两根线——CAN_H和CAN_L,通过差分电压传输数据。为什么用差分?抗干扰能力强啊。我在项目中遇到过,某次台架测试时电机启动瞬间,单端信号全乱了,但CAN总线纹丝不动。

数据链路层,负责把数据打包成帧。CAN的帧结构是这样的:

| SOF | 仲裁域 | 控制域 | 数据域 | CRC | ACK | EOF |
|  1  |  12/32 |   6    | 0-64   |  16 |  2  |  7  |

这里有个关键点:仲裁域。CAN总线是广播式的,所有节点都能发。那冲突了怎么办?靠ID仲裁。ID越小,优先级越高。嗯,这个特性后面会用到。

核心要点:CAN物理层保证信号可靠传输,数据链路层保证帧的正确收发。UDS诊断栈就站在这个肩膀上。

3.2 CAN报文与UDS的映射关系

UDS报文怎么塞进CAN帧里?这是很多新手困惑的地方。其实很简单:UDS的服务ID(SID)和参数,全部放在CAN帧的数据域里

举个例子,一个UDS诊断请求"读取ECU序列号":

UDS请求:22 F1 90 (22是ReadDataByIdentifier,F190是数据标识符)
CAN帧: 0x7DF | 8 | 02 22 F1 90 00 00 00 00
        ID     DLC  数据域

你看,CAN帧的ID是0x7DF(功能寻址),DLC是8(数据长度),后面8个字节就是UDS报文。这里要注意:UDS报文长度不能超过CAN帧数据域的最大长度(8字节)。那超过8字节怎么办?这就是下一节要讲的ISO 15765-2网络层协议。

我的经验:刚开始做诊断时,我总把UDS和CAN帧割裂开看。后来发现,调试时直接看CAN报文比看UDS日志更直观。建议你学会用CAN工具(如PCAN、CANoe)直接解析CAN帧,一眼就能看出问题。

3.3 CAN ID分配策略:物理寻址与功能寻址

这是UDS诊断里最容易踩坑的地方。CAN ID怎么分配?两种方式:

寻址方式 特点 CAN ID示例 应用场景
物理寻址 点对点,一个ID对应一个ECU 0x7E0(诊断仪→ECU)
0x7E8(ECU→诊断仪)
单个ECU诊断、刷写
功能寻址 一对多,一个ID对应多个ECU 0x7DF(诊断仪→所有ECU) 广播请求、网络唤醒

物理寻址,说白了就是"指名道姓"。诊断仪发0x7E0,只有ID为0x7E0的ECU会响应。我建议在刷写ECU时用物理寻址,避免多个ECU同时响应造成总线冲突。

功能寻址,就是"喊一嗓子"。诊断仪发0x7DF,总线上所有支持诊断的ECU都会收到。但注意:功能寻址的响应,ECU通常不会回复,否则总线会炸。我曾经见过一个项目,功能寻址请求后所有ECU都回复,总线直接瘫痪。嗯,血的教训。

避坑指南:我曾经在量产项目中,因为功能寻址ID配置错误,导致诊断仪发请求时多个ECU同时响应,CAN总线负载率瞬间飙到90%以上。后来排查了两天才发现是ID分配表里写错了。所以,ID分配一定要用文档管理好,最好做成配置文件。

3.4 网络层协议(ISO 15765-2)详解

终于到了重头戏。ISO 15765-2,也叫CAN TP(Transport Protocol),它解决了一个核心问题:UDS报文超过8字节怎么办?

CAN TP把长报文拆成多个CAN帧发送,接收端再拼回去。它定义了四种帧类型:

  • 单帧(SF):报文长度≤8字节,直接发送
  • 首帧(FF):报文长度>8字节,第一个帧,包含总长度信息
  • 连续帧(CF):后续数据,带序列号
  • 流控帧(FC):接收端告诉发送端"慢点发"或"继续发"

举个例子,发送一个20字节的UDS报文:

发送端:FF(首帧)→ 包含总长度20字节
接收端:FC(流控帧)→ 告诉发送端"可以发,一次发3帧"
发送端:CF1(连续帧1)→ 第1-7字节
发送端:CF2(连续帧2)→ 第8-14字节
发送端:CF3(连续帧3)→ 第15-20字节

这里有个细节:流控机制。接收端通过FC帧的"块大小(BS)"和"最小间隔时间(STmin)"控制发送节奏。BS告诉发送端一次发几帧,STmin告诉发送端每帧间隔多久。

实战经验:我在做Bootloader刷写时,遇到过ECU处理速度跟不上,导致丢帧。后来调整了STmin参数,从0ms改成5ms,问题就解决了。所以,流控参数不是随便设的,要根据ECU的实际处理能力来调

3.5 本章小结

这一章我们走了一遍CAN总线的基础,重点讲了:

  • CAN物理层和数据链路层怎么保证可靠通信
  • UDS报文怎么映射到CAN帧的数据域
  • 物理寻址和功能寻址的区别与使用场景
  • ISO 15765-2网络层协议如何实现长报文传输

下一章,我们会进入UDS应用层,开始写真正的诊断代码。到时候你会发现,有了这一章的基础,理解起来会轻松很多。好了,今天就到这里,有问题随时交流。