4. CAN数据链路层(二):位填充、CRC、ACK与帧间距
上一章我们把CAN帧的结构拆了个底朝天。但光有结构还不够,总线上的信号得扛得住干扰,得能自检错误,还得让收发双方握手确认。今天聊的这四个机制——位填充、CRC校验、ACK应答、帧间距——就是干这些脏活累活的。
我个人习惯把这四个东西看成CAN的“免疫系统”。没有它们,CAN就是一具裸奔的骨架。
4.1 位填充机制:为什么CAN要硬塞比特?
先问一个问题:如果总线上连续发5个、10个、甚至20个相同的电平,会发生什么?
接收端的时钟是靠自己晶振估算的,没有外部同步信号。长时间没有跳变沿,接收端就会“跑偏”,采样点逐渐偏离正确位置。这就是时钟漂移。
CAN的解决办法很粗暴——强制插入跳变沿。
位填充规则:发送端在连续发送5个相同位后,自动插入一个相反电平的位。接收端收到5个相同位后,自动把第6位丢弃,恢复原始数据。
举个例子:
原始数据:11111 00000 1
填充后: 111110 000001 1
↑ ↑
填充位 填充位
填充位只出现在SOF到CRC段。ACK段、EOF、帧间距不参与填充。
我的一点经验:位填充对实时性有影响。极端情况下,如果数据全是0x00或0xFF,填充率接近20%。设计系统时,如果报文周期很紧,记得把填充开销算进去。我曾经在一个电机控制项目里,就因为没算填充位,导致高优先级报文偶尔超时——后来把数据域改成了随机种子,填充率降下来了,问题才解决。
4.2 CRC校验原理与计算:15位冗余码怎么来的?
CAN的CRC是15位,生成多项式固定为:
x¹⁵ + x¹⁴ + x¹⁰ + x⁸ + x⁷ + x⁴ + x³ + 1
对应的二进制是:1100010110011001(16位,最高位隐含)。
计算范围:从SOF到数据域最后一个字节,包括填充位。
计算步骤:
- 把待校验数据看作一个二进制多项式M(x)
- M(x)左移15位,得到M(x)·x¹⁵
- 用生成多项式G(x)做模2除法(异或运算)
- 余数就是15位CRC,取反后填入CRC段
接收端做同样的计算,如果余数为0,CRC通过。
注意:CAN的CRC计算包含填充位!这意味着发送端和接收端的填充逻辑必须完全一致。如果填充位插错了,CRC一定过不了。我调试时遇到过一种情况:发送端填充逻辑有bug,偶尔少插一位,结果接收端CRC校验失败率高达30%。查了三天才定位到是填充位计数器的边界条件写错了。
4.3 ACK应答机制:谁在说“我收到了”?
CAN的ACK非常巧妙——它不需要专门的应答帧,而是在当前帧里留了一个槽位。
ACK段只有2位:
- ACK Slot(1位):发送端发隐性位(1),接收端发显性位(0)表示确认
- ACK Delimiter(1位):固定隐性位(1),作为分隔
工作流程:
- 发送端在ACK Slot输出隐性电平
- 所有正确接收到帧的节点,在ACK Slot输出显性电平
- 发送端检测到总线为显性,就知道至少有一个节点收到了
- 如果发送端读到的是隐性,说明没有节点确认,立即重发
关键点:ACK是“线与”逻辑。只要有一个节点应答,总线就是显性。发送端不关心具体是谁应答的,只关心有没有人应答。
你想想看,如果总线上只有一个节点(比如诊断工具单独接一个ECU),那这个ECU必须应答,否则发送端会一直重发。
4.4 帧间距:总线也需要喘口气
帧与帧之间不能无缝衔接,必须留一段空闲时间。这就是帧间距(Interframe Space, IFS)。
帧间距分两种情况:
| 节点类型 | IFS组成 | 说明 |
|---|---|---|
| 主动错误节点 | 3个隐性位 | 正常通信时的帧间距 |
| 被动错误节点 | 3个隐性位 + 8个隐性位(挂起传输) | 被动错误节点发送完一帧后,必须多等8位才能开始下一帧 |
为什么被动错误节点要多等?
因为被动错误节点只能发隐性位,不能主动拉低总线。如果它连续发帧,可能会干扰其他节点的正常通信。多等8位,相当于给它一个“冷静期”。
避坑指南:我曾经在一个多节点项目中,发现某个ECU偶尔丢帧。抓波形一看,那个ECU进入了被动错误状态,帧间距从3位变成了11位。但发送端没等它,直接发了下一帧,结果那个ECU的接收缓冲区还没准备好,帧就丢了。后来我们在发送端加了一个帧间距超时重传机制,问题才解决。
4.5 本章知识体系
下面这张图把四个机制的关系画清楚了:
4.6 小结
这一章的内容偏底层,但非常重要。我总结几个关键点:
- 位填充:强制插入跳变沿,防止时钟漂移。代价是带宽损失,极端情况接近20%
- CRC:15位多项式校验,覆盖SOF到数据域(含填充位)。余数为0则通过
- ACK:单槽位线与应答,发送端只关心有没有人应答,不关心是谁
- 帧间距:正常3位,被动错误节点11位。这是CAN的“交通规则”
这些机制在CAN控制器硬件里自动完成,但作为工程师,你必须理解它们的工作原理。否则,遇到总线错误、丢帧、重发等问题时,你会无从下手。
最后提醒一句:不要完全依赖硬件。有些低端CAN控制器在位填充和CRC处理上有bug。我遇到过一款芯片,在特定数据模式下CRC计算错误,导致误码率飙升。解决方案是换芯片,或者软件层面做二次校验。嗯,选型时多留个心眼。