4、CAN帧结构详解(下):数据场、CRC场、ACK场、帧结束
上一讲我们把CAN帧的前半部分拆了个干净。今天接着聊剩下的四个场:数据场、CRC场、ACK场和帧结束。
这几个场,说白了就是“你到底要传什么”、“传得对不对”、“别人收到了没”以及“收工”。看起来简单,但坑不少。我这些年调试CAN总线,至少有一半的疑难杂症都出在CRC和ACK这两个环节上。
4.1 数据场:你要传的真东西
数据场是CAN帧里唯一一个由用户完全控制的区域。标准帧最多8字节,扩展帧也一样——8字节,没得商量。
有人问我:“为什么非得是8字节?我传个9字节不行吗?”
不行。这是CAN协议定死的。当年博世设计CAN时,考虑到实时性和总线负载,8字节是个折中方案。你想想看,如果允许传几百字节,一个节点占着总线不放,别的节点就别玩了。
| 帧类型 | 数据场长度 | DLC编码(4位) |
|---|---|---|
| 数据帧 | 0~8字节 | 0000~1000 |
| 远程帧 | 无数据场 | DLC仅表示期望的数据长度 |
数据场的字节顺序呢?CAN协议本身没规定是大端还是小端。这完全取决于你的应用层协议。我在做J1939协议栈时,遇到过两个ECU因为字节序不一致,导致车速显示翻倍——一个认为是0x1234,另一个读成0x3412。
嗯,这里要注意:CAN协议只保证帧的完整性,不保证数据的解释方式。字节序、数据类型、物理单位,这些都是应用层的事。
4.2 CRC场:15位CRC的硬核计算
CRC场是CAN帧的“体检医生”。它负责检查帧在传输过程中有没有被干扰。
CAN用的是15位CRC,生成多项式是:
x¹⁵ + x¹⁴ + x¹⁰ + x⁸ + x⁷ + x⁴ + x³ + 1
写成二进制就是:
1 1000 1001 1001 1001
这个多项式可不是随便选的。我查过资料,博世当年做了大量仿真,确保这个多项式在CAN总线常见的噪声模型下,漏检率最低。
计算过程是这样的:
- 发送节点把待校验的位序列左移15位
- 用生成多项式做模2除法(其实就是异或)
- 余数就是15位CRC
- CRC后面加一个隐性位(CRC delimiter)
接收节点收到帧后,用同样的多项式对同样的位序列做计算。如果算出来的余数是0,说明帧没问题。如果不是0——嗯,那就说明帧被破坏了。
15位CRC的检错能力有多强?
- 能检测所有≤5位的突发错误
- 能检测所有奇数个错误
- 对更长的突发错误,漏检率只有2⁻¹⁵ ≈ 0.003%
说白了,在汽车电子这种高噪声环境里,15位CRC已经够用了。CAN FD后来升级到17位或21位CRC,那是后话。
4.3 ACK场:你到底收到了没?
ACK场只有2位:ACK Slot(应答槽)和ACK Delimiter(应答分隔符)。
但就是这2位,实现了CAN总线最巧妙的设计之一——多节点同时应答。
工作流程是这样的:
- 发送节点在ACK Slot位输出隐性位(1)
- 所有接收节点如果正确收到帧,就在ACK Slot位输出显性位(0)
- 发送节点读到显性位,就知道至少有一个节点收到了
这里的关键是:多个节点可以同时拉低总线。因为CAN总线是“线与”机制,只要有一个节点输出显性位,总线就是显性。发送节点不需要知道具体是谁应答的,只需要知道“有人收到了”。
如果发送节点在ACK Slot读到的是隐性位(没人应答),它会怎么做?
它会认为帧发送失败,然后自动重发。重发次数不限,直到成功或总线关闭。
我在实际项目中遇到过一种情况:某个节点只发不收,导致总线上没人应答它的帧。结果那个节点不停地重发,把总线带宽全占满了。排查时发现,是它的接收中断被关掉了。
ACK Delimiter固定为隐性位。它的作用是给ACK Slot一个明确的结束边界。如果ACK Delimiter被检测到显性位,就会触发格式错误。
4.4 帧结束:7个隐性位收尾
帧结束(EOF)由7个连续的隐性位组成。
为什么是7个?不是8个,也不是6个?
因为CAN协议需要保证帧结束的位模式不会和错误帧(6个显性位)混淆。7个隐性位,足够让所有节点确认帧已经结束。
帧结束之后,总线会进入间歇场(Intermission),持续3个隐性位。然后总线才能开始下一帧的传输。
这里有个细节:帧结束期间,如果有节点检测到位错误(比如读到显性位),它会发送错误帧。但这种情况很少见,因为帧结束是隐性位,总线自然就是隐性状态。
4.5 完整帧结构一览
把四个场串起来,一个完整的数据帧长这样:
SOF + 仲裁场 + 控制场 + 数据场 + CRC场 + ACK场 + EOF
1 12/32 6 0~64 16 2 7 (位)
标准帧总位数:44~108位(不含位填充)
扩展帧总位数:64~128位(不含位填充)
加上位填充后,实际长度会多一些。位填充的规则是:连续5个相同位后插入一个相反位。这个我们后面专门讲。
下面这张图把整个帧结构串起来了:
这张图把整个帧结构串起来了。你可以看到,每个场都有明确的职责边界。CAN协议的设计哲学就是:简单、可靠、实时。每个位都有它的用途,没有浪费。