3. CAN总线数据链路层:帧结构、仲裁、位填充与CRC校验
数据链路层,说白了就是CAN协议的核心战场。物理层只负责把0和1发出去,但怎么组帧、怎么抢总线、怎么保证数据不出错,全在这一层解决。我个人觉得,搞懂这一层,CAN通信就算入门一半了。
咱们直接切入正题,看看CAN帧到底长什么样。
3.1 CAN帧结构:标准帧 vs 扩展帧
CAN总线上一共就四种帧:数据帧、远程帧、错误帧、过载帧。平时打交道最多的就是数据帧。数据帧又分两种——标准帧和扩展帧。区别在哪?就在仲裁段的ID长度上。
| 对比项 | 标准帧 (CAN 2.0A) | 扩展帧 (CAN 2.0B) |
|---|---|---|
| ID长度 | 11位 | 29位 |
| IDE位 | 显性 (0) | 隐性 (1) |
| 帧头开销 | 较小 | 较大 |
| 应用场景 | 节点少、实时性高 | 多节点、复杂网络 |
标准帧的帧结构长这样:
SOF | 11位ID | RTR | IDE | r0 | DLC | 数据段(0-8字节) | CRC | ACK | EOF
扩展帧呢,多了一段18位的扩展ID:
SOF | 11位基础ID | SRR | IDE | 18位扩展ID | RTR | r1,r0 | DLC | 数据段 | CRC | ACK | EOF
关键点:标准帧和扩展帧可以在同一条总线上共存。但IDE位决定了帧类型——显性0表示标准帧,隐性1表示扩展帧。仲裁时,标准帧优先级永远高于扩展帧。
我在项目中遇到过一个问题:两个节点ID都是0x100,但一个是标准帧,一个是扩展帧。结果标准帧总是先发出去,扩展帧一直在等。后来查手册才发现,IDE位在仲裁时是显性优先,标准帧天生占便宜。
3.2 仲裁机制:CSMA/CA + AMP
CAN总线是多主从结构。任何节点都能随时发数据。那问题来了——两个节点同时发,谁先走?
答案是:谁ID小,谁先走。
CAN用的机制叫CSMA/CA + AMP(载波监听多路访问/冲突避免 + 逐位仲裁)。说白了就是:
- 先听后说:发之前先看看总线是不是空闲。
- 边说边听:发每一位的同时,监听总线电平。
- 输了就退:如果自己发的是隐性1,但总线上是显性0,说明有优先级更高的节点在发,自己立刻退出。
你想想看,这个过程有多快?逐位比较,11位ID比完,胜负已分。整个过程发生在微秒级别。
避坑指南:我曾经在一个项目中,把两个节点的ID设成了0x001和0x002。结果0x001的节点一直占着总线,0x002几乎发不出去。后来我把0x002的ID改成了0x100,才平衡了总线负载。记住:ID越小,优先级越高,别让一个节点把总线堵死。
仲裁的胜负规则很简单:
- 显性位(0) > 隐性位(1)
- ID数值越小,优先级越高
- RTR位:数据帧(RTR=0) > 远程帧(RTR=1)
- 标准帧(IDE=0) > 扩展帧(IDE=1)
3.3 位填充机制
嗯,这里要注意。CAN总线有个硬性要求:连续相同的位不能超过5个。
为什么?因为CAN节点是靠电平跳变来同步时钟的。如果连续发一堆相同的位,没有跳变,节点的时钟就会漂移,最后采样出错。
位填充的规则很简单:
- 发送方:每检测到连续5个相同位,自动插入一个相反位
- 接收方:收到连续5个相同位后,自动删除下一个位(填充位)
举个例子:
原始数据:11111 00000 11111
填充后: 111110 000001 111110
填充位用粗体标出来了。注意,填充位只在SOF到CRC段之间生效。ACK、EOF、IFS这些段不填充。
警告:位填充不是可选项,是强制要求。如果你用STM32的bxCAN外设,硬件会自动处理填充和去填充。但如果你用软件模拟CAN协议(比如用定时器+GPIO),位填充必须自己实现。我见过有人忘了做位填充,结果总线上一串0x00发出去,所有节点直接报错。
3.4 CRC校验
CAN帧的CRC段是15位,生成多项式是:
x¹⁵ + x¹⁴ + x¹⁰ + x⁸ + x⁷ + x⁴ + x³ + 1
CRC的计算范围包括:SOF、仲裁段、控制段、数据段。CRC段本身和后面的ACK、EOF不参与计算。
接收方收到帧后,用同样的多项式重新计算CRC。如果计算结果和收到的CRC一致,就发ACK;不一致,就发错误帧。
| CRC参数 | 值 |
|---|---|
| CRC长度 | 15位 |
| 生成多项式 | 0x4599 (x¹⁵+x¹⁴+x¹⁰+x⁸+x⁷+x⁴+x³+1) |
| 计算范围 | SOF ~ 数据段 |
| 检错能力 | 最多5位随机错误,或任意奇数位错误 |
实际经验:STM32的bxCAN外设,CRC计算是硬件自动完成的。你只需要把数据填进邮箱,硬件会算好CRC并附加到帧尾。但如果你用CAN FD或者自己写协议栈,CRC就得手算。我建议用查表法,别用逐位计算,效率差太多。
3.5 本章知识结构图
下面这张图把数据链路层的核心内容串起来了:
3.6 小结
数据链路层是CAN协议的灵魂。帧结构决定了数据怎么装,仲裁机制决定了谁先发,位填充保证了时钟同步,CRC校验保证了数据可靠。这四个东西加在一起,才让CAN总线在工业现场这么恶劣的环境下还能稳定工作。
我个人建议,学到这里先别急着写代码。拿逻辑分析仪抓一段CAN总线波形,对着帧结构图一个一个位去解析。我当年就是这么干的,抓了一下午波形,之后看CAN协议就跟看自己家冰箱说明书一样清楚。