2. CAN数据帧结构:标准帧与扩展帧、ID仲裁机制、数据场与CRC校验
CAN总线上的数据,说白了就是靠一个个“帧”来传递的。帧的结构长什么样,直接决定了你能不能把数据发出去、别人能不能收到、收到的是不是对的。我刚开始接触CAN的时候,总觉得帧结构就是一堆二进制位,背下来就行了。后来在项目里踩了几次坑才明白——不理解帧结构,你连示波器上的波形都看不懂。
这一节,咱们就把CAN数据帧掰开揉碎了讲。重点看三个东西:标准帧和扩展帧的区别、ID怎么决定谁先说话、数据场和CRC怎么保证数据靠谱。
2.1 标准帧 vs 扩展帧:差的不只是位数
CAN 2.0规范定义了两种帧格式:标准帧(CAN 2.0A)和扩展帧(CAN 2.0B)。很多人以为区别就是ID位数不同——标准帧11位,扩展帧29位。对,但不全对。
我个人的习惯是,先看帧的“骨架”。一个完整的数据帧,从SOF(帧起始)到EOF(帧结束),总共包含以下几个段:
| 段名称 | 标准帧 | 扩展帧 | 说明 |
|---|---|---|---|
| SOF | 1 bit | 1 bit | 显性位,同步所有节点 |
| 仲裁场 | 12 bits | 32 bits | ID + RTR + IDE + 扩展ID |
| 控制场 | 6 bits | 6 bits | IDE + r0 + DLC |
| 数据场 | 0~64 bits | 0~64 bits | 实际载荷 |
| CRC场 | 16 bits | 16 bits | 15位CRC + 1位定界符 |
| ACK场 | 2 bits | 2 bits | 应答槽 + 定界符 |
| EOF | 7 bits | 7 bits | 隐性位,帧结束 |
你看,标准帧和扩展帧最大的差异就在仲裁场。标准帧的仲裁场只有12位(11位ID + 1位RTR),扩展帧的仲裁场有32位(11位基础ID + SRR + IDE + 18位扩展ID + 1位RTR)。
这里有个容易搞混的地方:IDE位。标准帧的IDE位在控制场,是显性(0);扩展帧的IDE位在仲裁场,是隐性(1)。接收节点就是靠IDE位来判断当前帧是标准还是扩展的。
2.2 ID仲裁机制:谁的数字小,谁先走
CAN总线是“多主”架构——任何节点都可以随时发数据。那问题来了:如果两个节点同时发,谁说了算?
答案是:ID仲裁。
仲裁的规则特别简单:ID值越小,优先级越高。发送的时候,所有节点同时往总线上送ID位。如果某个节点送的是隐性位(1),但总线上被别的节点拉成了显性位(0),那这个节点就知道自己输了,立刻停止发送,转为接收。
你想想看,这就像一群人同时喊话,谁嗓门大谁先说完。在CAN里,“嗓门大”就是显性位(0)压倒隐性位(1)。
标准帧的ID是11位,取值范围0x000~0x7FF。扩展帧的ID是29位,取值范围0x00000000~0x1FFFFFFF。数值越小,优先级越高。所以0x000是最高优先级,0x7FF是最低优先级。
我在项目中遇到过一个问题:两个节点同时发送,ID分别是0x100和0x101。按理说0x100优先级更高,但实际测试发现0x101先发了。查了半天,原来是0x100节点的发送电路有延迟,导致显性位没及时拉低。嗯,硬件问题也会影响仲裁,别光看协议。
2.3 数据场:最多8字节,别嫌少
CAN数据帧的数据场长度是0~8字节。为什么是8?因为CAN总线最早是为汽车设计的,汽车上的控制信号(转速、车速、油门位置)每个信号也就几个字节,8字节完全够用。
数据场的长度由控制场里的DLC(Data Length Code)决定。DLC是4位,理论上可以表示0~15,但CAN协议规定DLC > 8时,数据场长度按8算。也就是说,你DLC设成9,实际也只发8字节。
| DLC值 | 数据场长度(字节) | 备注 |
|---|---|---|
| 0 | 0 | 远程帧常用 |
| 1~8 | 1~8 | 正常数据帧 |
| 9~15 | 8 | 协议规定截断 |
数据场的字节顺序,CAN协议没有强制规定。但行业内有个不成文的规矩:小端序(Little-Endian)。也就是低地址存低位数据。比如你要发一个16位的值0x1234,Byte0存0x34,Byte1存0x12。
2.4 CRC校验:15位多项式,误检率极低
CAN总线的物理环境其实挺恶劣的——电磁干扰、线束老化、连接器松动,都可能让数据出错。CRC(循环冗余校验)就是用来检测这些错误的。
CAN数据帧的CRC场包含15位CRC序列和1位CRC定界符(隐性位)。生成多项式是:
x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1
这个多项式是CAN协议规定的,硬件自动计算,你不需要自己实现。但理解它的原理有助于排查问题。
CRC的计算范围包括:SOF、仲裁场、控制场和数据场。接收节点收到帧后,会用同样的多项式重新计算CRC,然后跟发送节点附带的CRC值对比。如果不一样,说明帧在传输过程中被破坏了,接收节点会发送错误帧,要求发送节点重传。
我个人的经验是:CRC校验的误检率极低,但也不是100%。在极端情况下(比如多个位同时翻转),CRC可能检测不出来。不过对于汽车级应用,这个概率已经足够小了。如果你做的是安全关键系统(比如刹车、转向),建议在应用层再加一层校验,比如和校验或更高级的CRC。
2.5 知识结构图:CAN数据帧全景
下面这张图把标准帧和扩展帧的结构、仲裁流程、CRC校验范围串在了一起。你可以把它当作一个快速参考。
2.6 小结:记住这三句话
- 标准帧和扩展帧——差在ID位数,IDE位决定格式,别混用。
- ID仲裁——谁的数字小谁先走,显性位压倒隐性位。
- 数据场和CRC——最多8字节,CRC硬件算,出错就重传。