3. CAN数据链路层:帧结构与仲裁机制
数据链路层,说白了就是CAN协议最核心的“交通规则”。它规定了数据怎么打包、怎么抢路权、怎么纠错。我做了这么多年车身稳定系统,遇到的大部分通信问题,根源都在这一层。
3.1 标准帧与扩展帧
CAN总线上的报文,主要有两种格式:标准帧和扩展帧。它们的区别,关键就在ID的长度。
| 特性 | 标准帧 (CAN 2.0A) | 扩展帧 (CAN 2.0B) |
|---|---|---|
| ID长度 | 11位 | 29位 |
| 仲裁场结构 | ID + RTR + IDE + r0 | ID + SRR + IDE + 扩展ID + RTR + r1 + r0 |
| 数据场最大长度 | 8字节 | 8字节 |
| 帧间隔 | 3位 | 3位 |
| 应用场景 | 传统车身控制、简单传感器 | 多节点、复杂网络(如动力总成、ADAS) |
我个人习惯,在车身稳定系统(ESC)这类实时性要求高的场景,尽量用标准帧。为什么?因为11位ID足够区分ESC、转向、制动这些核心节点,而且帧短,传输快。扩展帧虽然地址空间大,但仲裁场多了SRR和IDE位,帧长度增加,会挤占总线带宽。
3.2 仲裁机制:CSMA/CR
CAN总线没有主节点,所有节点都能随时发数据。那冲突了怎么办?靠CSMA/CR——载波监听多路访问/冲突解决。
说白了,就是“先听后说,边说边听”。每个节点在发送前,先监听总线是否空闲。如果空闲,就开始发。发送的同时,还在监听总线上的电平。
关键来了:CAN总线是“线与”逻辑。显性电平(逻辑0)会覆盖隐性电平(逻辑1)。所以,如果两个节点同时发,谁的ID更小(显性位更多),谁就能继续发,另一个节点自动退出发送,转为接收。
你想想看,如果ESC和车窗同时发报文,ESC的ID是0x100(二进制:00100000000),车窗是0x500(二进制:10100000000)。在仲裁场的第一位,ESC发0,车窗发1,显性电平覆盖隐性,车窗立刻退出发送。整个过程,在几个微秒内完成,不会丢数据。
3.3 位填充机制
位填充,是为了保证时钟同步。CAN总线没有单独的时钟线,接收节点靠跳变沿来同步。如果连续出现5个相同的电平,接收节点就可能失步。
规则很简单:发送节点在连续发送5个相同位后,自动插入一个相反的电平位。接收节点收到后,自动把这个填充位去掉。
- 填充规则: 每5个连续相同位,插入1个相反位
- 填充范围: SOF、仲裁场、控制场、数据场、CRC场
- 不填充范围: ACK场、EOF、帧间隔
3.4 错误帧与错误处理
CAN总线有5种错误类型,每种都有对应的检测机制。我把它整理成一张表,方便你对照。
| 错误类型 | 检测机制 | 触发条件 |
|---|---|---|
| 位错误 | 发送节点比较发送电平与总线电平 | 发送的位与监听到的位不一致 |
| 填充错误 | 接收节点检测填充规则 | 连续6个相同位出现 |
| CRC错误 | 接收节点计算CRC并与发送CRC比较 | CRC校验不匹配 |
| 格式错误 | 接收节点检测固定格式位 | 固定位(如EOF、ACK)电平错误 |
| ACK错误 | 发送节点检测ACK槽 | ACK槽未被接收节点置为显性 |
一旦检测到错误,节点会立即发送错误帧。错误帧由6个显性位(主动错误)或6个隐性位(被动错误)组成,强制中断当前报文,通知所有节点丢弃该帧。
嗯,这里要注意:错误帧不是随便发的。每个节点有两个计数器:发送错误计数器(TEC)和接收错误计数器(REC)。错误越多,计数器越大。当TEC或REC超过127时,节点从“主动错误”状态变为“被动错误”状态,只能发隐性错误帧,不能主动干扰总线。如果TEC超过255,节点直接进入“总线关闭”状态,彻底退出通信。
3.5 本章知识结构图
下面这张图,把数据链路层的核心逻辑串起来了。你可以把它当作一个快速索引。
这张图把帧结构、仲裁、位填充、错误处理四个模块串起来了。你可以看到,标准帧和扩展帧是帧结构的两个分支,仲裁机制靠CSMA/CR实现,位填充保证时钟同步,错误处理则通过错误帧和计数器来维护总线健康。
在实际的车身稳定系统开发中,我建议你把这张图打印出来,贴在工位上。遇到通信问题,先定位是哪个模块出的问题,再深入排查。这样效率会高很多。