4. CAN总线仲裁机制:CSMA/CA与逐位仲裁原理
说到CAN总线,有个问题我经常被问到:多个节点同时发数据,总线会不会打架?
答案是:会抢,但不会坏。这就是CAN总线最巧妙的地方——非破坏性仲裁。
我刚开始接触CAN时,总觉得这玩意儿有点反直觉。你想想看,多个设备同时往一根线上丢数据,按理说早就乱套了。但CAN偏偏能做到“谁优先级高谁先发,优先级低的自动退让”,而且整个过程不破坏任何数据。嗯,今天我们就来拆解这个机制。
4.1 CSMA/CA:先听再说
CAN总线用的是CSMA/CA(载波监听多路访问/冲突避免)。
说白了就是:每个节点在发数据前,先听听总线是不是空闲。
- 空闲:直接发。
- 忙:等,直到空闲再发。
这和以太网的CSMA/CD(冲突检测)不一样。以太网是“先发,撞了再重传”。CAN是“先听,尽量别撞”。
关键区别:CSMA/CD是破坏性的——冲突发生后数据已经坏了,必须重传。CSMA/CA是非破坏性的——仲裁过程中数据完好无损。
我在一个项目里见过有人把CAN当以太网用,结果总线利用率一高就丢帧。后来查了半天,发现是节点没做监听就直接发了。记住:CAN的“先听后发”是硬规则,不是建议。
4.2 逐位仲裁:谁“显性”谁赢
如果两个节点同时开始发送,怎么办?
CAN的仲裁是逐位进行的。每个节点在发送ID的每一位时,都会同时监听总线电平。
这里有个核心规则:
- 显性位(逻辑0):覆盖隐性位(逻辑1)。
- 谁先发出显性位,谁就“赢”了。
举个例子:
节点A ID:0x7F0(二进制:111 1111 0000)
节点B ID:0x7E8(二进制:111 1110 1000)
逐位对比:
位0:A=1, B=1 → 相同,继续
位1:A=1, B=1 → 相同,继续
位2:A=1, B=1 → 相同,继续
位3:A=1, B=1 → 相同,继续
位4:A=1, B=1 → 相同,继续
位5:A=1, B=1 → 相同,继续
位6:A=1, B=1 → 相同,继续
位7:A=1, B=0 → A发1(隐性),B发0(显性)
→ B的显性位覆盖了A的隐性位
→ A检测到总线电平与自己发送的不一致
→ A立即退出,转为接收模式
→ B继续发送剩余位
你看,整个过程在一个位时间内就完成了仲裁。没有数据损坏,没有重传,胜出的节点继续发完整个帧。
个人经验:我调试过一个多节点系统,发现某个节点总是“抢不过”别人。后来用示波器一看,它的CAN控制器输出驱动能力偏弱,显性位没把总线拉到位。换了个批次芯片就好了。硬件上的“显性强度”有时候也会影响仲裁结果。
4.3 ID优先级决定机制
CAN的ID决定了节点的优先级。ID越小,优先级越高。
为什么?因为ID的高位先发送,而显性位(0)优先级高于隐性位(1)。
| ID(二进制) | 十进制 | 优先级 |
|---|---|---|
| 000 0000 0000 | 0 | 最高 |
| 000 0000 0001 | 1 | 次高 |
| 111 1111 1111 | 2047 | 最低 |
标准帧ID是11位,范围0~2047。扩展帧ID是29位,范围更大,但仲裁逻辑一样。
避坑指南:我曾经在一个项目里把紧急制动消息的ID设成了0x7FF(2047),结果刹车指令总是被其他消息挤掉。后来改成0x001,问题解决。记住:越紧急的消息,ID越小。
4.4 非破坏性仲裁过程详解
整个仲裁过程可以分为三个阶段:
- 同步阶段:所有节点在SOF(帧起始)的下降沿同步。
- 仲裁阶段:逐位发送ID,同时监听总线。如果发现总线电平与自己发送的不一致,立即退出。
- 胜出阶段:胜出的节点继续发送剩余帧(控制场、数据场、CRC等)。
这里有个细节:仲裁只在ID场和RTR位进行。一旦进入控制场,仲裁就结束了。所以数据场里的内容不会影响仲裁结果。
非破坏性的本质:退出的节点只是停止发送,并没有破坏总线上的数据。胜出的节点可以完整地发完整个帧。这就是“非破坏性”的含义。
下面这张图展示了三个节点同时发送时的仲裁过程:
4.5 仲裁的边界情况
有些情况值得注意:
- 相同ID:如果两个节点ID完全相同,仲裁会进入数据场。但标准CAN不允许相同ID的节点同时发送,否则会出错。所以设计时一定要保证ID唯一。
- RTR位:远程帧的RTR位是隐性(1),数据帧的RTR位是显性(0)。所以数据帧优先级高于远程帧。
- 扩展帧:扩展帧的SRR位是隐性,替代标准帧的RTR位。如果标准帧和扩展帧同时发送,标准帧会赢。
小技巧:我习惯在系统设计阶段就画一张ID分配表,把紧急消息、周期消息、事件消息分开。紧急消息用0x000~0x0FF,周期消息用0x100~0x7FF。这样仲裁时紧急消息永远优先。
4.6 仲裁的物理层基础
仲裁能实现,靠的是CAN总线的物理层特性:
- 显性位:CAN_H高,CAN_L低,差分电压约2V。
- 隐性位:CAN_H和CAN_L都是2.5V,差分电压0V。
- 线与逻辑:多个节点同时驱动总线时,显性位覆盖隐性位。
说白了,就是“谁拉得低谁说了算”。
硬件坑:我曾经遇到过总线终端电阻没接好,导致隐性电平漂移。结果仲裁时显性位拉不下去,节点误判总线空闲,疯狂重发。最后总线直接瘫痪。所以终端电阻一定要焊牢。
4.7 小结
CAN的仲裁机制,核心就三点:
- CSMA/CA:先听后发,避免冲突。
- 逐位仲裁:谁先发显性位谁赢。
- 非破坏性:输的节点自动退出,数据不损坏。
这个机制让CAN总线在实时性和可靠性上远超其他现场总线。你想想看,一个系统里几十个节点,随时可能同时发数据,但CAN能保证最高优先级的消息在微秒级内送达。这就是它能在汽车和工业领域屹立几十年的原因。