2、CAN数据帧结构:SOF、仲裁场、控制场、数据场、CRC场、ACK场、EOF详解

说实话,搞CAN诊断这么多年,我最怕的就是有人一上来就背帧结构。背得滚瓜烂熟,真到抓波形的时候,连SOF在哪都找不到。我个人习惯是——把帧结构当成一条公路,每个字段就是一个路段。你只要知道每个路段是干嘛的,出问题就知道去哪查。

好,咱们今天就一条一条捋清楚。

2.1 SOF(Start of Frame)——帧起始

SOF就是一个显性位(逻辑0)。它告诉总线上所有节点:我要开始说话了。

你想想看,总线平时是隐性电平(逻辑1),突然拉低,大家就知道有数据要来了。这个动作很简单,但非常重要。我记得有一次调试,发现某个节点老是丢帧,抓波形一看,SOF后面紧跟着一个毛刺,把同步给破坏了。嗯,这种问题往往跟硬件设计有关,终端电阻没配好。

关键点:SOF是同步的起点,所有节点从这里开始对齐时钟。

2.2 仲裁场(Arbitration Field)——谁说了算

仲裁场包含两部分:ID(标识符)RTR(远程传输请求位)

ID就是消息的身份证。标准帧是11位,扩展帧是29位。ID越小,优先级越高。为什么?因为显性位(0)会覆盖隐性位(1)。

举个例子:

  • 节点A发ID=0x123(二进制:0001 0010 0011)
  • 节点B发ID=0x124(二进制:0001 0010 0100)

当它们同时发送时,从高位开始比。比到第8位,A是0,B是1。A赢了,B乖乖退出发送,转为接收。

RTR位呢?平时数据帧是显性(0),远程帧是隐性(1)。说白了,远程帧就是“你发个数据给我看看”,但实际项目中远程帧用得很少。我建议你直接忽略它,先把数据帧搞明白。

避坑指南:我曾经遇到一个项目,两个节点ID设反了,高优先级的节点一直抢不到总线。后来发现是ID分配没按功能重要性来排。记住:关键信号(如刹车、转向)用低ID,非关键信号(如车窗、空调)用高ID。

2.3 控制场(Control Field)——数据有多长

控制场有6位:

  • IDE位(1位):0表示标准帧,1表示扩展帧
  • 保留位(1位):标准帧叫r0,扩展帧叫r1,必须发显性(0)
  • DLC(4位):数据长度代码,范围0~8

DLC这玩意儿我吃过亏。有一次客户报故障,说某个节点发出来的数据长度不对。我抓波形一看,DLC=8,但实际数据场只有4个字节有效,后面4个字节全是垃圾。后来发现是代码里DLC写死了8,但数据只填了4个。

记住:DLC必须跟实际数据长度一致。多出来的字节,接收方会当成有效数据来处理,容易引发逻辑错误。

DLC值 数据长度(字节) 常见用途
0 0 远程帧、心跳信号
1~7 1~7 单信号、小数据包
8 8 UDS诊断、多信号打包

2.4 数据场(Data Field)——真正的干货

数据场就是你要传的实际数据,0~8个字节。CAN FD可以到64字节,但那是后话了。

数据怎么放?有两种方式:

  • Motorola格式(大端):高字节在前,低字节在后。比如0x1234,先发0x12,再发0x34。
  • Intel格式(小端):低字节在前,高字节在后。比如0x1234,先发0x34,再发0x12。

我见过最坑的事,就是整车厂和供应商对信号格式理解不一致。一个用Motorola,一个用Intel,结果车速显示300km/h。嗯,车没跑,数据先飞了。

注意:数据场里的位序和字节序,必须在DBC文件里明确约定。否则,你解析出来的数据就是一堆乱码。

2.5 CRC场(Cyclic Redundancy Check)——数据对不对

CRC场包含15位CRC序列和1位CRC界定符(隐性)。

CRC的作用很简单:接收方算一遍,跟发送方算的对比。不一样?说明数据被干扰了,直接丢帧。

CAN的CRC算法是固定的,多项式是:x¹⁵ + x¹⁴ + x¹⁰ + x⁸ + x⁷ + x⁴ + x³ + 1。你不用背,工具会算。但你要知道,CRC覆盖的范围是从SOF到数据场结束。

我曾经遇到一个奇葩问题:CRC每次都错,但波形看着没问题。后来发现是晶振偏差太大,导致采样点偏移,CRC算出来就不对了。换了个高精度晶振,问题解决。

经验之谈:CRC错误率如果超过1%,先查物理层——终端电阻、线缆长度、共模电压。别一上来就怀疑软件。

2.6 ACK场(Acknowledge)——收到了没

ACK场就2位:

  • ACK Slot(1位):发送方发隐性(1),接收方拉显性(0)表示确认
  • ACK界定符(1位):必须隐性(1)

这里有个细节:只要总线上有一个节点正确接收了帧,ACK Slot就会被拉低。所以发送方看到ACK Slot是显性,就知道至少有一个节点收到了。

如果发送方发现ACK Slot还是隐性?说明没人理它。这时候发送方会重发。重发次数超过上限,就报Bus Off。

我记得有一次,一个节点老是报Bus Off。抓波形发现,它发完数据后ACK Slot一直是隐性。查了半天,原来是这个节点的CAN控制器配置成了只听模式(Listen Only),不会发ACK。嗯,配置错了。

小技巧:调试时,可以用示波器抓ACK Slot。如果每次都是隐性,说明总线上没有其他节点在监听,或者接收方有问题。

2.7 EOF(End of Frame)——说完了

EOF是7个连续的隐性位(1)。它告诉总线:这帧结束了,大家可以抢下一帧了。

为什么是7位?因为位填充机制最多连续5个相同位,7个隐性位足够让所有节点识别出帧结束。如果EOF被破坏(比如出现显性位),接收方会认为帧不完整,直接丢弃。

EOF后面还有3位ITM(Intermission),也就是帧间隔。这3位也是隐性,用来让总线喘口气。

注意:EOF的7个隐性位不能有任何干扰。我曾经见过一个案例,电机启动时产生强电磁干扰,把EOF的第5位打成了显性。结果接收方一直等帧结束,等不到,最后超时报错。解决方案是在电机线上加磁环。

2.8 完整帧结构一览

把上面所有字段串起来,一个标准数据帧长这样:

SOF | ID(11位) | RTR | IDE | r0 | DLC(4位) | Data(0~8字节) | CRC(15位) | CRC界定符 | ACK Slot | ACK界定符 | EOF(7位)
 1      11        1      1     1      4         0~64           15           1           1          1          7

总位数:1 + 11 + 1 + 1 + 1 + 4 + (0~64) + 15 + 1 + 1 + 1 + 7 = 44~108位(不含位填充)。

加上位填充后,实际长度会略长。但别担心,CAN控制器会自动处理这些。

2.9 我的调试建议

如果你刚开始学CAN,我建议你这么做:

  1. 拿一个CAN分析仪,抓一段真实的总线数据
  2. 对照帧结构,把每个字段标出来
  3. 重点关注SOF和EOF,看它们是否完整
  4. 检查CRC,看有没有错误帧
  5. 看ACK Slot,确认节点间通信正常

等你亲手抓过几十帧波形,这些字段就刻在脑子里了。比死记硬背强一百倍。

好,这一章就到这儿。下一章咱们聊聊CAN的位时序和同步机制——说白了就是,为什么总线上那么多节点,数据还能不乱套。