2. CAN数据帧结构:标准帧与扩展帧、ID仲裁机制、数据场、CRC校验
好,咱们今天聊聊CAN数据帧的结构。说实话,我刚接触CAN协议那会儿,看着那一堆位域定义,头都大了。但后来在项目里调过几次通信故障,才真正体会到——不理解帧结构,你连问题出在哪都找不到。
CAN总线上的数据,是以“帧”为单位传输的。最常见的,就是数据帧。它负责把一包数据从发送节点送到接收节点。咱们今天就把它的五脏六腑拆开看看。
2.1 标准帧 vs 扩展帧:11位还是29位?
CAN协议有两个版本:CAN 2.0A 和 CAN 2.0B。前者定义了标准帧,后者引入了扩展帧。区别在哪?说白了,就是ID的长度不同。
- 标准帧:ID是11位。范围0x000 ~ 0x7FF。够用吗?早期够,后来车上的ECU越来越多,就不够了。
- 扩展帧:ID是29位。范围0x00000000 ~ 0x1FFFFFFF。基本用不完。
你可能会问:我怎么区分收到的是标准帧还是扩展帧?看帧头里的IDE位(Identifier Extension Bit)。IDE=0,标准帧;IDE=1,扩展帧。嗯,就这么简单。
我个人习惯:在Zephyr里配置CAN时,我会用CAN_STANDARD_ID和CAN_EXTENDED_ID这两个宏。别搞混了,否则仲裁会出问题。
2.2 ID仲裁机制:谁优先级高谁先走
CAN总线是多主总线。什么意思?就是所有节点都能同时发数据。那冲突了怎么办?靠ID仲裁。
仲裁的原理,我简单说一下:
- 每个节点在发送帧起始(SOF)后,逐位输出ID。
- 总线是“线与”逻辑:显性位(0)会覆盖隐性位(1)。
- 如果某个节点发送了隐性位(1),但总线上是显性位(0),它就自动退出,转为接收状态。
所以,ID值越小,优先级越高。0x000是最高优先级,0x7FF是最低。
避坑指南:我曾经在一个项目中,把两个ECU的ID设成了0x100和0x101。结果发现0x100的报文总是先发,0x101的经常被延迟。后来才意识到,这就是仲裁在起作用。所以,关键信号(比如刹车、安全气囊)一定要用低ID。
2.3 数据场:最多8字节,够用吗?
CAN数据帧的数据场,长度是0~8字节。你可能会觉得:8字节也太少了吧?
其实,这是CAN协议设计时的权衡。8字节对于汽车上的大多数信号(车速、转速、温度、开关状态)来说,完全够用。而且,短帧的好处是实时性好,出错重传的成本也低。
在Zephyr里,发送数据时,你需要填充struct can_frame的data数组:
struct can_frame frame;
frame.flags = CAN_FRAME_IDE; // 扩展帧
frame.id = 0x12345678;
frame.dlc = 4; // 数据长度4字节
frame.data[0] = 0xAA;
frame.data[1] = 0xBB;
frame.data[2] = 0xCC;
frame.data[3] = 0xDD;
注意dlc字段。它表示数据长度码,范围0~8。如果你设成5,但只填了3个字节,接收方会读到5个字节,后两个是未定义值。嗯,这容易踩坑。
注意:CAN FD(灵活数据速率)协议把数据场扩展到了64字节。但咱们这门课主要讲经典CAN,先打好基础。
2.4 CRC校验:15位,保你数据不出错
CAN帧里有个CRC段,15位。它覆盖了帧起始、仲裁场、控制场、数据场。接收方收到后,会重新计算CRC,跟收到的CRC比对。不一致?那就发错误帧,要求重传。
你可能会想:15位够安全吗?我告诉你,CAN的CRC算法是精心设计的。它能检测出:
- 所有单比特错误
- 所有双比特错误
- 所有奇数个错误
- 大部分突发错误(长度≤15位)
我在实际项目中,很少遇到CRC校验失败的情况。除非总线干扰特别大,或者线缆有问题。
小技巧:在Zephyr里调试CAN通信时,可以用can_get_core_stats()查看CRC错误计数。如果这个数一直在涨,赶紧检查你的物理层——终端电阻、线缆屏蔽、接地,一个都不能少。
2.5 完整数据帧结构一览
咱们把整个数据帧串起来,看看它长什么样:
| 段名称 | 位数(标准帧) | 位数(扩展帧) | 说明 |
|---|---|---|---|
| 帧起始 (SOF) | 1 | 1 | 显性位,同步所有节点 |
| 仲裁场 (ID + RTR + IDE) | 12 | 32 | ID决定优先级 |
| 控制场 (DLC + 保留位) | 6 | 6 | 数据长度码 |
| 数据场 | 0~64 | 0~64 | 实际数据,最多8字节 |
| CRC场 | 16 | 16 | 15位CRC + 1位定界符 |
| ACK场 | 2 | 2 | 接收节点确认 |
| 帧结束 (EOF) | 7 | 7 | 隐性位,表示帧结束 |
你看,整个帧加起来也就几十位。在500kbps的波特率下,一个标准帧传输时间不到200微秒。这就是CAN为什么能用在实时控制里的原因。
2.6 小结
今天咱们把CAN数据帧的骨架搭起来了。标准帧和扩展帧的区别,ID仲裁的“越小越优先”,数据场的8字节限制,还有CRC的15位保护。这些是后续所有通信协议的基础。
下一章,我会带你看看CAN的远程帧和错误帧。嗯,那些才是真正让你头疼的东西。不过别怕,咱们一步一步来。