CAN总线是汽车控制器中最常用的总线之一,其他常见的数据通信方式还有UART、I2C等。这些协议都使用两根线进行通信,但为什么CAN总线通信时会出现节点冲突,需要仲裁机制,而UART却没有这个问题呢?另外,I2C总线到底需不需要仲裁?让我们从通信的基本原理入手,一步步解析。
1. 全双工与半双工
“双工”是与“单工”相对应的概念。单工指的是单向通信,一方只能发送,另一方只能接收,任何一方只能在一个方向上工作。
而“双工”则意味着任何一方都既能发送,也能接收数据,可以在两个方向上工作。
双工又细分为全双工和半双工。全双工允许同时进行发送和接收操作,而半双工则不能同时收发,但可以分时进行收发。
UART (通用异步收发器) 是一种常用的串行通信协议,在汽车嵌入式系统中常用于主芯片之间或主芯片与外设的数据通信。UART仅需两根线即可实现互连:串行数据发送线 TX 和串行数据接收线 RX。

从接口名称就能看出,一根 TX 线负责发送,另一根 RX 线负责接收。两根线相互独立,互不干扰,可以同时进行发送和接收,因此 UART 是一种典型的全双工通信方式。
这里需要注意,UART 的信号线必须交叉连接,即一方的 TX 与另一方的 RX 相连。
CAN总线同样仅需两根线实现通信,分别称为 CAN_H 和 CAN_L。

虽然也是两根线,但 CAN 并非一根发送、一根接收。其最终的发送信号是由这两根线的信号之差 (CAN_H - CAN_L) 决定的,这就是差分传输。因此,它不能同时进行收发,只能分时进行,属于半双工通信方式。
在这种半双工通信中,如果多个节点同时发送信息,就会发生冲突,此时就需要仲裁机制来解决。例如,节点1和节点2同时发送 CAN 报文,应该让谁先发?这个处理过程就是仲裁。
这时你可能会问:I2C 总线不也是半双工通信吗?为什么它不需要仲裁呢?这就要说到通信模式的差异了。
2. 多主模式与主从模式
在 CAN 总线中,各个节点是平等的,任何节点都可以主动发送报文。这意味着所有节点都可以充当主节点,这种架构称为多主模式。

多主模式的优点在于可以提升系统的并发处理能力,但缺点显而易见:多个主节点同时发送数据必然导致冲突,必须依赖其他机制来解决。
I2C 虽然也是半双工通信,但它通常采用主从模式。

在通信时,每个设备(包括主设备)都有一个唯一的地址。如上图所示,SOC 作为主设备,EEPROM 和 LCD Driver 作为从设备。主设备通过 SDA 线发送地址来选择对应的从设备,并通过 SCL 线为所有从设备提供统一的时钟。整个通信的收发时序完全由主设备指挥,因此各个节点不会出现同时并发发送的情况,自然也就不会产生总线冲突。
那么,结论是不是 I2C 不需要仲裁呢?别急,情况还有变化。
3. 多主从模式与仲裁
一个主节点与多个从节点构成的主从模式确实没有冲突,也就不需要仲裁。SPI、LIN 等总线采用的就是这种模式。
但 I2C 的特殊之处在于,它还支持多主从模式。这意味着总线上可以连接不止一个主设备,这些主设备都有权发起对总线的控制。

如上图所示,EEPROM 和 LCD Driver 作为从设备不变,但 SOC 和 MCU 都可以是主设备。可能一段时间内 SOC 是主设备,MCU 是从设备;而另一段时间内,角色可能互换。主从关系在通信过程中可以根据功能需要动态变化。
那么问题来了:如果两个主设备在同一时刻都想要获得总线控制权,该怎么办?这时候,仲裁机制就派上用场了。
I2C 的仲裁机制基于“线与”逻辑。如果两个或多个主机同时开始发送数据,当它们发送的位出现不同时(例如一个发“0”,一个发“1”),发送“0”(即输出低电平)的主机将赢得总线控制权,而发送“1”的主机检测到总线电平与自己输出的不符,便会失去仲裁并自动切换到接收模式。

4. CAN总线的冲突与仲裁
在开发和测试 CAN 总线时,我们看到每个报文都由 ID 和数据域构成。例如下面的周期性报文:

这个报文的 ID 是 0x201。在应用层,我们通常将报文 ID 作为功能或节点标识来识别。例如,看到这个 ID 就知道它是车速信号,或者知道它来自 ABS 节点。
然而,报文 ID 还有一个更根本的作用——总线仲裁。这个作用发生在底层物理层和数据链路层,应用层和普通的测试工具是感知不到的。
4.1. 仲裁场
CAN 数据帧的帧结构由 7 个不同的位场组成,分别是:帧起始、仲裁场、控制场、数据场、CRC 场、ACK 场和帧结束。

在 CAN 总线中,隐性位对应逻辑“1”,显性位对应逻辑“0”。总线空闲时处于隐性状态(逻辑“1”)。
标准帧的仲裁场包括 11 位的标识符 ID 和 1 位的 RTR 位。

总线仲裁的规则是“显性”位优先于“隐性”位。由于显性位对应逻辑 0,因此反映到实际的 ID 数值上,就是 ID 值越小,优先级越高。
例如,ID 0x390 与 0x398 同时发送。从最高位(第11位)开始逐位比较,到第4位时,0x390 为 0(显性),0x398 为 1(隐性)。因此,0x390 优先级更高,获得总线控制权。

通过合理分配 ID 数值,就可以为不同的报文定义优先级,从而解决总线冲突。如图所示,低优先级的报文 0x398 在发送时会回读总线上的电平。当检测到第4位是 0(显性)而不是自己要发送的 1(隐性)时,它就意识到有更高优先级的报文正在发送,随即停止发送并进入等待状态,直到总线空闲后再尝试重发。
除了 ID,仲裁场中的 RTR 位也参与仲裁。RTR 位用于区分数据帧和远程帧:数据帧中为“显性”(逻辑0),远程帧中为“隐性”(逻辑1)。
你可能会疑惑:RTR 只是一个帧类型标识,为什么也归入仲裁场?这是因为远程帧和它请求的数据帧具有相同的标识符 ID。当两者同时在总线上发送时,仅靠 ID 无法仲裁。根据“显性位优先”规则,数据帧(RTR=显性)的优先级高于远程帧(RTR=隐性),因此 RTR 位也被纳入仲裁的逻辑范畴。

5. 小结
UART、I2C 和 CAN 总线都是采用两根线的通信方式,但因工作模式不同,对仲裁的需求也不同:
- UART:全双工通信,发送与接收通道物理独立,不存在冲突,因此不需要仲裁。
- I2C:半双工通信。在单主从模式下,由主设备统一调度,不需要仲裁;在多主从模式下,可能存在多个主设备竞争总线,此时需要仲裁,其机制是基于“线与”逻辑的位仲裁。
- CAN总线:采用差分信号、半双工通信及多主模式,节点冲突是其固有特点,因此必须有仲裁机制。它通过报文ID和RTR位进行逐位比较的“非破坏性仲裁”,合理设置ID优先级即可有效管理总线访问。
理解这些底层通信机制的差异,有助于我们在不同的网络和系统场景中选择合适的通信协议,并进行正确的配置与调试。如果你想了解更多计算机系统底层的原理与设计,欢迎访问 云栈社区 进行交流和探索。