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 非破坏性仲裁过程详解

整个仲裁过程可以分为三个阶段:

  1. 同步阶段:所有节点在SOF(帧起始)的下降沿同步。
  2. 仲裁阶段:逐位发送ID,同时监听总线。如果发现总线电平与自己发送的不一致,立即退出。
  3. 胜出阶段:胜出的节点继续发送剩余帧(控制场、数据场、CRC等)。

这里有个细节:仲裁只在ID场和RTR位进行。一旦进入控制场,仲裁就结束了。所以数据场里的内容不会影响仲裁结果。

非破坏性的本质:退出的节点只是停止发送,并没有破坏总线上的数据。胜出的节点可以完整地发完整个帧。这就是“非破坏性”的含义。

下面这张图展示了三个节点同时发送时的仲裁过程:

CAN总线逐位仲裁过程 CAN总线逐位仲裁过程 节点A (ID=0x7F0) 节点B (ID=0x7E8) 节点C (ID=0x7F4) CAN总线 位0 位1 位2 位3 位4 位5 位6 仲裁过程说明: 1. 三个节点同时发送SOF,总线同步 2. 逐位比较ID:位0~6相同,位7时B发送显性位(0) 3. A和C检测到总线电平与自己发送不一致,退出 4. B胜出,继续发送剩余帧

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的仲裁机制,核心就三点:

  1. CSMA/CA:先听后发,避免冲突。
  2. 逐位仲裁:谁先发显性位谁赢。
  3. 非破坏性:输的节点自动退出,数据不损坏。

这个机制让CAN总线在实时性和可靠性上远超其他现场总线。你想想看,一个系统里几十个节点,随时可能同时发数据,但CAN能保证最高优先级的消息在微秒级内送达。这就是它能在汽车和工业领域屹立几十年的原因。