第四章:CAN总线仲裁——CSMA/CA机制、位仲裁原理、优先级判定、非破坏性仲裁

大家好,欢迎来到第四章。

上一章我们聊了CAN的帧结构,你可能会想:这么多节点挂在同一条总线上,要是两个节点同时发数据,不就打架了吗?

没错,这就是总线冲突问题。但CAN总线有个绝活——它不会像以太网那样把数据撞没了再重发。CAN用的是非破坏性仲裁,说白了就是:大家同时说话,谁优先级高谁继续说,优先级低的自动闭嘴。

这一章,我们就来拆解这个机制。

4.1 CSMA/CA:先听再说,边听边说

CAN总线采用的介质访问控制机制叫CSMA/CA,全称是Carrier Sense Multiple Access with Collision Avoidance。

翻译成人话就是:载波监听,多路访问,冲突避免

我刚开始学的时候,总把它和以太网的CSMA/CD搞混。CD是Collision Detection,检测到冲突就停;CA是Collision Avoidance,想办法避免冲突。CAN用的是CA,不是CD。

CSMA/CA的核心行为分三步:

  1. 监听总线:每个节点在发送前,先看看总线上有没有信号。如果有,就等总线空闲再发。
  2. 多路访问:多个节点可以同时尝试发送,谁先抢到总线谁先发。
  3. 冲突避免:如果多个节点同时开始发送,通过位仲裁机制决定谁继续,谁退出。

关键点:CAN的CSMA/CA不是完全避免冲突,而是把冲突的解决过程变成了优先级判定过程。冲突本身不会破坏数据,这就是非破坏性仲裁的精髓。

我在项目中遇到过一个问题:有个节点总是发不出数据,后来发现它一直在监听总线,但总线其实一直有信号。查了半天,原来是它的CAN控制器配置成了只听模式,根本没参与仲裁。嗯,这种低级错误,犯过一次就记住了。

4.2 位仲裁原理:谁先发0,谁赢

位仲裁是CAN总线最精彩的设计之一。它利用了CAN总线的显性位(0)和隐性位(1)特性。

简单说:显性位覆盖隐性位

如果A节点发0,B节点发1,总线上实际看到的是0。因为0的电平更强。

仲裁过程是这样的:

  1. 多个节点同时开始发送仲裁段(也就是ID段)。
  2. 每个节点逐位发送自己的ID,同时监听总线电平。
  3. 如果自己发的是1(隐性),但总线上读到的是0(显性),说明有更高优先级的节点在发0。
  4. 这个节点立刻退出仲裁,转为接收模式。
  5. 剩下的节点继续逐位比较,直到只剩一个节点胜出。

个人经验:我建议你在调试时用示波器同时抓CAN_H和CAN_L的差分信号,再配合CAN协议分析仪看仲裁过程。你会看到仲裁失败的节点在ID段中间突然停止发送,总线波形上只剩一个节点的信号继续。那个画面,很直观。

4.3 优先级判定:ID越小,优先级越高

优先级判定规则只有一句话:标识符(ID)数值越小,优先级越高

为什么?因为ID的高位先发送。ID数值小,意味着高位有更多的0。0是显性位,能压住1。

举个例子:

节点 ID(二进制) ID(十进制) 优先级
节点A 0000 1010 10 最高
节点B 0001 0011 19 中等
节点C 0010 0101 37 最低

你看,节点A的ID是10,节点C的ID是37。A的ID更小,所以A赢。

从二进制角度看:A的第5位是0,C的第5位是1。仲裁到这一位时,A的0直接覆盖了C的1,C立刻退出。

避坑指南:我曾经在项目里把两个节点的ID设成了0x100和0x0FF。你想想看,0x0FF比0x100小,按理说0x0FF优先级更高。但实际测试时发现0x100总是抢不过0x0FF。后来一查,原来0x0FF是扩展帧ID,0x100是标准帧ID。标准帧和扩展帧的仲裁规则不一样,标准帧的优先级默认高于扩展帧。嗯,这个坑,我替你们踩过了。

4.4 非破坏性仲裁:赢了继续,输了闭嘴

非破坏性仲裁,是CAN总线最引以为傲的特性。

什么叫非破坏性?

传统总线(比如以太网)发生冲突时,数据会被破坏,所有节点都得重发。这叫破坏性仲裁。

CAN总线不一样。仲裁过程中,胜出的节点继续发送完整的数据帧,没有任何数据丢失。失败的节点只是停止发送,但不会破坏总线上已有的数据。

为什么能做到?因为仲裁发生在仲裁段,数据还没开始传呢。仲裁段只包含ID和RTR位,不包含数据。等仲裁结束,只有一个节点在发,后面的数据段、CRC段都是它一个人说了算。

非破坏性仲裁的好处很明显:

  • 实时性好:高优先级消息不会被低优先级消息阻塞太久。
  • 带宽利用率高:没有数据被浪费,每次仲裁都有有效数据被传输。
  • 确定性:你可以精确计算出最坏情况下的响应时间。

核心理解:非破坏性仲裁的本质,是把总线冲突从「物理层问题」变成了「数据链路层的优先级调度」。你想想看,这相当于在硬件层面实现了一个实时调度器。很多实时操作系统还在软件层面做优先级调度呢,CAN直接在硬件层面就搞定了。

我记得有一次调试一个多节点系统,总线上挂了12个节点,数据量很大。我用CAN分析仪抓包,发现总线利用率到了80%以上,但高优先级的消息延迟始终在1ms以内。这就是非破坏性仲裁的威力——高优先级消息永远插队成功。

4.5 仲裁失败的节点怎么办?

仲裁失败的节点,不会一直沉默。它会:

  1. 立刻停止发送,转为接收模式。
  2. 接收当前正在传输的完整帧。
  3. 等总线空闲后,重新尝试发送。

注意:仲裁失败的节点不会立即重发。它要等当前帧传输结束,总线回到空闲状态,然后重新参与下一次仲裁。

如果多个低优先级节点同时等待,它们会在下一次仲裁中再次竞争。优先级高的那个会再次胜出。这就是为什么低优先级消息可能会被多次推迟——但不会被无限推迟,因为高优先级消息总有发完的时候。

个人建议:设计系统时,不要把关键消息的ID设得太大。我一般把最紧急的消息放在ID 0x001到0x07F之间,中等紧急的放在0x080到0x1FF,非紧急的放在0x200以上。这样能保证关键消息的实时性。

4.6 本章小结

这一章我们聊了CAN总线仲裁的核心机制:

  • CSMA/CA:先监听,再发送,冲突靠仲裁解决。
  • 位仲裁:逐位比较ID,谁先发0谁赢。
  • 优先级判定:ID数值越小,优先级越高。
  • 非破坏性仲裁:仲裁过程不破坏数据,胜者继续,败者闭嘴。

下一章,我们会深入CAN的位时序和同步机制。你会知道为什么CAN总线能在没有统一时钟的情况下,让所有节点步调一致地收发数据。那个机制,比仲裁还巧妙。

好,这一章就到这儿。有问题欢迎留言讨论。