第2章:CAN数据帧结构——标准帧与扩展帧、仲裁场、控制场、数据场、CRC校验
各位同学,咱们接着聊CAN总线。上一章我们把CAN的物理层和基本概念捋了一遍,这一章要啃的,是CAN数据帧的“五脏六腑”。说白了,就是数据在总线上到底长什么样,每个比特位是干嘛用的。
我个人习惯,看任何协议都先看帧结构。因为帧结构就是协议的“骨架”,骨架搭起来了,血肉(协议细节)才好往上挂。CAN的帧结构,我当年刚接触时觉得挺绕,尤其是标准帧和扩展帧的区别。但后来在弹载项目里调过几次通信故障后,就彻底吃透了。嗯,咱们今天就把这块硬骨头啃下来。
2.1 标准帧 vs 扩展帧:11位ID与29位ID的抉择
CAN总线有两种帧格式:标准帧和扩展帧。它们的核心区别,就在仲裁场的ID长度上。
- 标准帧:11位标识符(ID)。这是CAN 2.0A规范定义的,也是最早期的格式。
- 扩展帧:29位标识符(ID)。这是CAN 2.0B规范引入的,为了兼容更多节点和更复杂的网络。
你想想看,为什么要有扩展帧?说白了,就是11位ID不够用了。11位最多只能表示2048个不同的ID(实际上还要去掉一些保留位)。在航空电子或弹载系统里,节点数量多,消息类型复杂,2048个ID根本不够分。我参与过一个导弹飞控系统,光传感器节点就上百个,每个节点还要发好几种不同优先级的数据。用标准帧?根本排不开。最后全换成了扩展帧,29位ID,5亿多个组合,随便用。
关键区别一览:
| 特性 | 标准帧 (CAN 2.0A) | 扩展帧 (CAN 2.0B) |
|---|---|---|
| ID长度 | 11位 | 29位 |
| 仲裁场结构 | 11位ID + RTR位 | 11位基础ID + SRR位 + IDE位 + 18位扩展ID + RTR位 |
| 最大ID数量 | 2048 (2^11) | 536,870,912 (2^29) |
| 兼容性 | 所有CAN控制器都支持 | 需要支持CAN 2.0B的控制器 |
| 总线利用率 | 较高(帧头短) | 较低(帧头长,额外开销) |
我的经验:在弹载系统中,我建议优先使用扩展帧。虽然它比标准帧多了20个比特的开销,但换来的是极大的灵活性。而且,现在的CAN控制器(比如SJA1000、MCP2515等)都原生支持扩展帧,性能上几乎没有差别。别为了省那点带宽给自己挖坑。
2.2 仲裁场:谁先说话,谁说了算
仲裁场是CAN总线最精妙的设计之一。它解决了“多个节点同时发送数据时,谁先发”的问题。说白了,就是一场“比特级的拔河比赛”。
标准帧的仲裁场很简单:11位ID + RTR位(远程传输请求位)。
扩展帧的仲裁场稍微复杂点:11位基础ID + SRR位(替代远程请求位)+ IDE位(标识符扩展位)+ 18位扩展ID + RTR位。
仲裁的规则就一句话:ID值越小,优先级越高。总线上的电平是“显性”(逻辑0)压倒“隐性”(逻辑1)。所以,谁的ID在逐位比较时先出现“0”,谁就赢了。
举个例子:节点A的ID是0x100(二进制0001 0000 0000),节点B的ID是0x200(二进制0010 0000 0000)。从最高位开始比,第1位都是0,平手;第2位,A是0,B是1。A的0是显性,B的1是隐性。显性电平覆盖了隐性电平,所以A胜出,B自动退出发送,转为接收。
避坑指南:我曾经在一个项目中,把两个关键节点的ID设得太接近了(比如0x101和0x102)。结果在总线负载高的时候,优先级低的节点(0x102)经常发不出数据,导致控制指令超时。后来我把关键消息的ID设成了0x001、0x002这种极小值,才解决问题。记住:ID分配是系统设计的第一步,一定要留足余量。
RTR位的作用:如果是数据帧,RTR=0(显性);如果是远程帧(请求数据),RTR=1(隐性)。所以,相同ID的数据帧优先级永远高于远程帧。
2.3 控制场:数据长度的“说明书”
控制场紧跟在仲裁场后面。它的结构很简单:IDE位(或保留位)+ r0保留位 + DLC(数据长度码,4位)。
- IDE位:在标准帧中,IDE位于控制场的第1位,固定为显性(0)。在扩展帧中,IDE已经在仲裁场里出现过了,所以控制场里的IDE位被替换为保留位r1。
- r0、r1:保留位,固定为显性(0)。
- DLC:4位,表示数据场有多少个字节。取值范围0~8。注意,DLC可以表示0~15,但CAN协议规定数据场最多8字节。所以DLC值9~15虽然合法,但实际数据场长度还是8字节。我建议你永远不要用9~15,因为不同厂商的控制器处理方式可能不一样,容易出兼容性问题。
警告:DLC的值必须与实际发送的数据字节数严格一致。我曾经见过一个同事,发送时DLC填了8,但数据场只填了4个有效字节。接收方按照8个字节去解析,结果把后面4个随机值当成了有效数据,导致系统误动作。这种bug极难排查,因为不是每次都复现。切记:DLC必须等于实际数据长度。
2.4 数据场:0~8字节的“快递包裹”
数据场就是你要发送的实际数据。最多8个字节,最少0个字节(比如远程帧就没有数据场)。
为什么CAN限制数据场只有8字节?这是历史原因。早期的CAN总线速率只有125kbps~1Mbps,8字节的帧长可以在短时间内完成传输,保证实时性。在弹载系统中,8字节其实够用。比如一个飞控指令,通常只需要4个字节(2个字节的指令码,2个字节的参数)。一个传感器数据,也只需要2~4个字节。
如果数据超过8字节怎么办?那就需要拆分成多个CAN帧发送。或者,你可以用CAN FD(CAN Flexible Data-rate),它支持最多64字节的数据场。但CAN FD是后话了,咱们这门课主要讲经典CAN。
我的习惯:在定义数据场格式时,我会把每个字节的用途写清楚,做成一个“数据字典”。比如:Byte0 = 消息类型,Byte1 = 源节点ID,Byte2~3 = 数据值,Byte4~5 = 时间戳,Byte6~7 = 校验和。这样,无论谁看代码,都能一目了然。别偷懒,数据字典能救你的命。
2.5 CRC校验:数据完整性的“守门员”
CRC(循环冗余校验)是CAN帧的最后一道防线。它用来检测数据在传输过程中是否被干扰(比如电磁噪声、信号反射等)。
CAN的CRC算法是:CRC-15。它覆盖了帧起始、仲裁场、控制场、数据场。生成多项式是:x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1。
计算出的15位CRC值,放在CRC场中。接收方收到帧后,会用同样的算法重新计算一遍CRC,然后与发送方附带的CRC值比较。如果一致,说明数据没问题;如果不一致,接收方会发送一个错误帧,要求发送方重传。
CRC校验的可靠性:CRC-15的汉明距离是6。什么意思?就是说,它最多能检测出任意5个比特的错误。如果错误比特数超过5个,有极小的概率会漏检(即错误帧被当成正确帧)。但这个概率非常低,在工业环境中完全可以接受。弹载系统对可靠性要求极高,但CAN的CRC-15已经足够用了。我做了这么多年,还没遇到过CRC漏检导致的事故。
CRC场的后面,还有CRC界定符(1个隐性位)、应答场(ACK Slot + ACK界定符)、帧结束(7个隐性位)。这些咱们下一章再细讲。
注意:CRC计算不包括填充位(Stuff Bits)。CAN总线在发送时,如果连续出现5个相同电平,会自动插入一个相反电平的填充位,以保证时钟同步。但填充位不参与CRC计算。这一点在硬件上由CAN控制器自动处理,软件开发者一般不用操心。但如果你在做底层驱动或FPGA实现,就一定要搞清楚填充位的处理逻辑。
小结
这一章我们拆解了CAN数据帧的各个部分:
- 标准帧 vs 扩展帧:11位ID还是29位ID,根据系统规模选。
- 仲裁场:ID越小优先级越高,RTR位区分数据帧和远程帧。
- 控制场:DLC告诉你有多少数据,别填错。
- 数据场:0~8字节,够用就好,记得做数据字典。
- CRC校验:CRC-15,数据完整性的保障。
下一章,咱们聊聊CAN的位时序和同步机制。这可是调通CAN总线的关键,很多坑都在那里等着你呢。到时候我给你们讲讲我当年调不通CAN总线,最后发现是采样点设置错了的故事。