2. CAN数据帧结构:标准帧与扩展帧、ID仲裁机制、数据场与CRC校验

各位同学,今天我们来啃一块硬骨头——CAN数据帧结构。说实话,我刚入行那会儿,觉得CAN协议就是发发数据嘛,有啥好研究的?直到有一次在BMS项目中,整车通讯突然乱套,我拿着逻辑分析仪抓了一整天波形,才发现是扩展帧和标准帧混用导致的ID冲突。嗯,从那以后,我再也不敢小看帧结构了。

2.1 标准帧 vs 扩展帧:到底差在哪?

CAN总线有两种帧格式:标准帧(CAN 2.0A)和扩展帧(CAN 2.0B)。说白了,它们最大的区别就是——ID的位数不同。

  • 标准帧:11位ID,帧头短,传输效率高。适合节点少、优先级明确的系统。
  • 扩展帧:29位ID,帧头长,但能容纳更多节点和更复杂的优先级分配。

我个人习惯在BMS项目中这样选:如果整车节点不超过20个,用标准帧就够了。但像商用车、储能系统这种动辄几十上百个节点的场景,必须上扩展帧。为什么?你想想看,11位ID最多只能有2048个不同的标识符,去掉保留位,实际能用的也就1000多个。而29位ID能支持5亿多个,基本不愁不够用。

关键区别表:

特性 标准帧 扩展帧
ID位数 11位 29位
帧头长度 47位 67位
最大节点数 约2048 约5.3亿
传输效率 较高 较低(多20位开销)
IDE位 0(显性) 1(隐性)

这里有个坑:标准帧和扩展帧可以在同一条总线上共存,但它们的ID仲裁机制是分开的。我曾经在项目里看到有人把标准帧ID设成0x123,扩展帧ID也设成0x123,结果两个节点同时发送时,标准帧永远优先——因为IDE位是显性(0),扩展帧的IDE是隐性(1)。仲裁时显性位赢,所以标准帧总是抢到总线。这不是bug,是协议设计如此。

2.2 ID仲裁机制:谁说了算?

CAN总线的仲裁机制,说白了就是「谁的数字小,谁先走」。为什么?因为CAN总线是「线与」逻辑:显性位(0)会覆盖隐性位(1)。

我画个图你就明白了:

CAN总线ID仲裁过程示意图 节点A (ID=0x123): ID位: 0 0 0 1 0 0 1 0 0 0 1 1 节点B (ID=0x124): ID位: 0 0 0 1 0 0 1 0 0 1 0 0 总线仲裁结果: 总线位: 0 0 0 1 0 0 1 0 0 0 1 1 ← 节点A获胜 第10位冲突,A为0,B为1 → A赢

看到没?节点A的ID是0x123(二进制...00100011),节点B是0x124(二进制...00100100)。在第10位(从高位算起),A是0,B是1。A发送显性位0,B发送隐性位1,总线被拉成0。B检测到总线位和自己发送的不一致,立刻退出仲裁,转为接收模式。

避坑指南:我曾经在BMS项目中把电池包过温报警的ID设成0x001,把电池包欠压报警设成0x002。结果过温和欠压同时发生时,过温永远先发。后来想想也对——过温比欠压更危险,优先级高是合理的。所以设计ID时,一定要把最紧急的消息放在最小的ID上。

2.3 数据场:你到底能带多少货?

CAN数据帧的数据场最多8个字节。为什么是8?不是16、不是32?我记得当年学CAN时也问过这个问题。答案是:为了满足汽车电子的实时性要求。8字节的数据,在500kbps的波特率下,传输时间不到0.2ms,足够快。

在BMS中,我们通常这样分配数据场:

  • 字节0-1:总电压(16位,精度0.01V)
  • 字节2-3:总电流(16位,有符号,精度0.1A)
  • 字节4:SOC(8位,精度0.4%)
  • 字节5:SOH(8位,精度0.4%)
  • 字节6:最高单体电压(8位,精度0.02V)
  • 字节7:最低单体电压(8位,精度0.02V)

你看,8个字节刚好够用。如果数据量超过8字节怎么办?那就拆成多帧发送,或者用CAN FD(CAN Flexible Data-rate),它支持最多64字节的数据场。不过那是后话了。

2.4 CRC校验:别让数据「带病上岗」

CAN帧的尾部有一个15位的CRC校验码。它覆盖的范围包括:帧起始、仲裁场、控制场、数据场。说白了,除了ACK场和帧结束,其他所有位都要被CRC保护。

CRC的生成多项式是:x¹⁵ + x¹⁴ + x¹⁰ + x⁸ + x⁷ + x⁴ + x³ + 1。嗯,你不用背这个多项式,但要知道它的检错能力:

  • 能检测所有单比特错误
  • 能检测所有双比特错误
  • 能检测所有奇数个错误
  • 能检测所有长度≤15的突发错误
  • 对长度16的突发错误,漏检率仅为1/2¹⁵ ≈ 0.003%

注意:CRC不是万能的。我曾经在实验室遇到一个诡异问题:电池包电压数据偶尔跳变,但CRC校验每次都通过。查了两天才发现,是CAN收发器的共模电压出了问题,导致数据位被「拉偏」了,但CRC计算时用的是同样的错误数据,所以校验通过了。嗯,硬件问题有时候比协议问题更难排查。

最后,给大家看一个完整的CAN数据帧结构图:

CAN标准帧完整结构(位序列) SOF 仲裁场(12位) 控制场 数据场(0-64位) CRC场(16位) ACK EOF 1位 12位 6位 0-64位 16位 2位 7位 SOF:帧起始 | 仲裁场:ID+RTR | 控制场:IDE+r0+DLC | CRC:15位CRC+1位分隔符 | ACK:应答+分隔符 | EOF:帧结束 扩展帧仲裁场为32位(29位ID+SRR+IDE+RTR),其他场相同

好了,这一章的内容就到这里。记住:标准帧和扩展帧的选择要看系统规模,ID仲裁靠的是「数字小优先」,数据场8字节要精打细算,CRC校验是最后一道防线但别迷信它。下一章我们聊聊CAN的位时序和同步机制——嗯,那是另一个有意思的话题。


专注资料整理