3、车载网络通信协议(上):CAN总线详解——物理层、数据链路层、报文格式、仲裁机制、错误处理

CAN总线,全称Controller Area Network。说实话,这玩意儿在汽车电子里太重要了。我入行那会儿,第一件事就是啃CAN协议。你想想看,一辆车上几十个ECU,要是没有个靠谱的通信方式,那不乱套了?

CAN总线是德国Bosch公司在80年代搞出来的。初衷很简单——让车上各个电子模块能高效、可靠地交换数据。到今天,它依然是车载网络的中流砥柱。

3.1 物理层:差分信号与总线电平

CAN的物理层,说白了就是两根线——CAN_H和CAN_L。它用差分信号传输,抗干扰能力很强。

为什么用差分?我举个例子。你在车里,发动机点火、空调压缩机启动,电磁干扰到处都是。单端信号很容易被干扰,但差分信号不一样——两根线受到的干扰基本一样,接收端一相减,干扰就抵消了。

信号状态 CAN_H电压 CAN_L电压 差分电压
显性(Dominant) 3.5V 1.5V 2.0V
隐性(Recessive) 2.5V 2.5V 0V

显性电平代表逻辑0,隐性电平代表逻辑1。这里有个关键点——显性电平会覆盖隐性电平。这个特性,就是后面仲裁机制的基础。

个人经验: 我在做某款BMS项目时,遇到过CAN通信偶尔丢帧的问题。查了半天,发现是终端电阻没焊好。CAN总线两端必须各接一个120Ω电阻,少了它,信号反射会导致通信不稳定。

3.2 数据链路层:帧结构与位填充

CAN的数据链路层,核心就是帧结构。标准CAN(CAN 2.0A)的帧ID是11位,扩展CAN(CAN 2.0B)是29位。我个人习惯,只要不是老平台,都用扩展帧——兼容性更好。

先看标准数据帧的结构:

SOF + 11位ID + RTR + IDE + r0 + DLC + 数据段(0-8字节) + CRC + ACK + EOF

每个字段都有它的作用。SOF(Start of Frame)是帧起始,一个显性位。ID段决定了消息的优先级。DLC(Data Length Code)告诉接收方数据有多少字节。

嗯,这里要注意位填充(Bit Stuffing)。CAN协议规定,连续发送5个相同电平后,必须插入一个相反电平。为什么?为了保证接收方能从信号边沿提取时钟。我见过有工程师写CAN驱动时忘了处理位填充,结果高速通信时老是同步失败。

3.3 报文格式:标准帧 vs 扩展帧

标准帧和扩展帧的区别,主要在ID长度和格式控制位上。

对比项 标准帧(CAN 2.0A) 扩展帧(CAN 2.0B)
ID长度 11位 29位
最大节点数 2048 5.36亿
IDE位 显性(0) 隐性(1)
数据长度 0-8字节 0-8字节

你可能会问,什么时候用标准帧,什么时候用扩展帧?我的建议是:如果网络简单,节点少,标准帧够用。但现在的车,动辄几十个ECU,还是用扩展帧吧,ID分配起来灵活得多。

避坑指南: 我曾经在一个项目中,标准帧和扩展帧混用,结果仲裁逻辑出了bug。记住,同一个CAN网络上,所有节点必须使用同一种帧格式,否则ID比较会乱套。

3.4 仲裁机制:非破坏性逐位仲裁

CAN的仲裁机制,是我觉得最巧妙的设计之一。多个节点同时发送时,谁优先级高谁先发,而且不会破坏高优先级帧的数据。

原理很简单:总线是线与逻辑。显性位(0)会覆盖隐性位(1)。每个节点在发送ID位时,同时监听总线电平。如果自己发的是隐性位,但总线上是显性位,说明有更高优先级的节点在发,自己就乖乖退出发送。

举个例子:

  • 节点A:ID = 0x100(二进制:001 0000 0000)
  • 节点B:ID = 0x200(二进制:010 0000 0000)

从最高位开始比较。第1位都是0,没问题。第2位,A发0(显性),B发1(隐性)。总线被A拉成显性,B检测到总线电平与自己发送的不一致,立刻退出。A继续发送,不受影响。

关键点: 仲裁不丢数据,只丢节点。高优先级的帧完整发送,低优先级的节点自动重试。这就是非破坏性仲裁的含义。

3.5 错误处理:5种错误类型与状态机

CAN的错误处理机制,说实话,挺复杂的。但搞懂了,你就知道为什么CAN这么可靠。

CAN定义了5种错误类型:

  1. 位错误(Bit Error):发送节点发送的电平与总线电平不一致。
  2. 填充错误(Stuff Error):连续6个相同电平,违反位填充规则。
  3. CRC错误:接收方计算的CRC与发送方不一致。
  4. 形式错误(Form Error):帧格式中固定位段出现非法电平。
  5. 应答错误(ACK Error):发送方没有收到ACK应答。

每个节点内部有两个计数器:发送错误计数器(TEC)和接收错误计数器(REC)。根据计数值,节点处于三种状态之一:

状态 条件 行为
主动错误(Error Active) TEC < 128 且 REC < 128 发送主动错误标志(6个显性位)
被动错误(Error Passive) TEC > 127 或 REC > 127 发送被动错误标志(6个隐性位)
总线关闭(Bus Off) TEC > 255 完全断开总线,不参与任何通信
我曾经踩过的坑: 有次调试,发现一个ECU时不时就不响应了。查TEC寄存器,发现它已经进入总线关闭状态。原因是CAN收发器的共模电压出了问题,导致位错误不断累积。后来加了共模扼流圈,问题解决。记住,硬件设计不好,软件再牛也白搭。

3.6 CAN知识体系总览

下面这张图,是我自己梳理的CAN知识体系。你可以把它当作学习地图。

CAN总线知识体系总览 CAN总线 物理层 数据链路层 应用层 错误处理 差分信号 终端电阻 帧结构 位填充 标准帧/扩展帧 仲裁机制 5种错误类型 TEC/REC计数器 主动错误 被动错误 总线关闭 非破坏性仲裁 💡 学习建议 先掌握物理层和数据链路层,再理解仲裁和错误处理。

这张图把CAN的知识点串起来了。从物理层的差分信号,到数据链路层的帧结构,再到应用层的仲裁机制,最后是错误处理的状态机。你顺着这个脉络学,不会乱。

总结一下: CAN总线的核心优势在于它的实时性、可靠性和非破坏性仲裁。搞懂物理层的电平逻辑、数据链路层的帧格式、仲裁的逐位比较、错误处理的状态机,你就掌握了CAN的精华。下一章,我们会深入CAN FD和CAN XL,看看它们怎么在经典CAN的基础上做改进。