2、CAN总线基础回顾:CAN协议帧结构、ID与仲裁、位填充与CRC校验、物理层
各位同学,咱们今天聊点硬核的。在开始动手搭建仿真节点之前,我建议咱们先把CAN总线的基础再过一遍。你想想看,如果连报文长什么样都不清楚,那后面调试起来肯定抓瞎。我在项目里见过太多人,上来就拖个CAN报文发出去,结果总线上一片混乱,最后发现连帧类型都选错了。
好,咱们直接进入正题。
2.1 CAN协议帧结构:四种帧类型
CAN总线上跑的数据,说白了就四种格式。我习惯把它们分成两类:一类是干活的(数据帧和远程帧),另一类是管秩序的(错误帧和过载帧)。
2.1.1 数据帧
这是最常用的帧。它负责把数据从一个节点发到另一个节点。数据帧的结构我建议你死记硬背下来,因为后面用CANalyzer抓报文时,你看到的每一段都对应着这里的一个字段。
| 字段 | 长度(标准帧) | 说明 |
|---|---|---|
| SOF | 1 bit | 帧起始,显性电平,告诉总线“我要发数据了” |
| 仲裁场 | 12 bits | 包含11位ID + RTR位(远程帧请求位) |
| 控制场 | 6 bits | IDE位、保留位、DLC(数据长度码) |
| 数据场 | 0~64 bits | 实际要传输的数据,最多8字节 |
| CRC场 | 16 bits | 15位CRC校验码 + 1位CRC界定符 |
| ACK场 | 2 bits | 接收节点确认收到,拉低总线电平 |
| EOF | 7 bits | 帧结束,隐性电平 |
嗯,这里要注意:数据场最多8个字节。为什么是8?因为CAN总线最早是为汽车设计的,当时觉得控制信号8个字节足够了。现在虽然有些应用觉得不够用,但CAN FD(灵活数据速率)已经扩展到了64字节。不过咱们课程主要讲经典CAN,8字节够用。
2.1.2 远程帧
远程帧这东西,说白了就是“请求数据”。节点A发一个远程帧,告诉节点B:“嘿,把你那个ID为0x123的数据发给我”。
远程帧和数据帧长得几乎一样,唯一的区别是RTR位。数据帧的RTR是显性(0),远程帧的RTR是隐性(1)。
2.1.3 错误帧
错误帧是CAN总线自愈能力的体现。当任何一个节点检测到总线错误时,它会主动发送错误帧。错误帧由两部分组成:
- 错误标志: 6个连续的显性位(主动错误)或6个连续的隐性位(被动错误)
- 错误界定符: 8个连续的隐性位
为什么会这样设计?你想想看,6个连续的显性位在CAN总线协议里是违法的(因为位填充规则不允许连续5个相同电平)。所以一旦出现6个显性位,所有节点都知道“出事了”。
2.1.4 过载帧
过载帧用得很少。它表示节点“忙不过来,请稍等”。过载帧的结构和错误帧类似,但触发条件不同。我在实际项目中几乎没见过过载帧,因为现在的CAN控制器处理速度都很快。不过如果你在做一些老旧的ECU仿真,可能会遇到。
2.2 CAN ID与仲裁机制
这是CAN总线最精彩的部分。为什么多个节点同时发数据不会冲突?因为CAN总线用ID来决定谁有发言权。
仲裁规则很简单:ID越小,优先级越高。
具体怎么仲裁?总线电平是“线与”逻辑。显性电平(0)会覆盖隐性电平(1)。当两个节点同时发送时,它们逐位比较ID。谁先发出隐性位(1)而对方发出显性位(0),谁就输了,自动转为接收模式。
举个例子:
节点A发送ID = 0x100(二进制:001 0000 0000)
节点B发送ID = 0x200(二进制:010 0000 0000)
从高位开始比较:
- 第1位:A发0,B发0 → 平局
- 第2位:A发0,B发1 → A赢了,B退出
最终节点A的数据成功发送。
我记得有一次调试,客户说他的节点总是发不出数据。我一看,好家伙,他把自己的ID设成了0x7FF(标准帧最大ID)。这相当于在高速公路上开着一辆拖拉机,谁都比你快。后来改成0x100,问题解决。
2.3 位填充与CRC校验
2.3.1 位填充
位填充是CAN总线保证同步的机制。规则很简单:连续发送5个相同电平后,必须插入一个相反电平。
为什么要这么做?因为CAN节点靠电平跳变来同步时钟。如果长时间没有跳变,节点之间的时钟误差会累积,导致采样错误。
举个例子:
原始数据:11111 00000 11111
填充后: 111110 000001 111110
注意:填充位是自动插入的,接收端会自动移除。你在CANalyzer里看到的报文数据是不包含填充位的。
2.3.2 CRC校验
CRC(循环冗余校验)是CAN总线保证数据完整性的最后一道防线。CAN协议使用15位CRC,生成多项式是:
x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1
计算范围是从SOF到数据场结束。接收节点会重新计算CRC,如果和发送的CRC不一致,就发送错误帧。
CRC的误检率极低。我在项目中几乎没见过CRC校验失败的情况——除非硬件坏了。但话说回来,如果你在CANalyzer里看到CRC错误,别急着怀疑硬件,先检查一下你的仿真节点是不是把DLC设错了。
2.4 CAN总线物理层
物理层决定了信号怎么在线上传输。CAN总线使用差分信号,两条线:CAN_H和CAN_L。
| 状态 | CAN_H电压 | CAN_L电压 | 差分电压 |
|---|---|---|---|
| 显性(0) | 3.5V | 1.5V | 2.0V |
| 隐性(1) | 2.5V | 2.5V | 0V |
差分信号的好处是抗干扰能力强。你想想看,如果外界有电磁干扰,两条线上受到的干扰基本一样,差分电压不变。这就是为什么CAN总线能在汽车这种恶劣环境中稳定工作。
另外,总线两端需要各接一个120欧姆的终端电阻。为什么是120欧姆?因为CAN总线的特性阻抗大约是120欧姆,匹配电阻可以防止信号反射。我见过有人忘了接终端电阻,结果总线波形乱七八糟,通信时好时坏。
好了,CAN总线的基础就回顾到这里。这些内容虽然基础,但非常重要。后面我们搭建仿真节点时,会反复用到这些知识。下一章,我们开始动手——在CANalyzer里创建第一个仿真节点。