2、CAN网络基础:CAN报文结构详解

各位工程师朋友,今天我们来聊聊CAN报文的结构。说实话,我刚入行那会儿,觉得CAN报文就是一串二进制数据,没什么好看的。直到有一次,我在调试一个ECU通信故障时,拿着示波器一帧一帧地看波形,才真正体会到——报文里的每一个bit,都有它的使命

CAN报文的标准结构,我习惯把它拆成7个部分:SOF、仲裁场、控制场、数据场、CRC场、ACK场、EOF。咱们一个一个来啃。

2.1 SOF(帧起始)

SOF就是一个显性位(逻辑0)。它告诉总线上的所有节点:“嘿,我要开始发数据了!”

你想想看,总线在空闲时是隐性电平(逻辑1)。SOF这个下降沿,就是整个报文的发令枪。我在项目中遇到过一个问题:某个节点发送的SOF信号上升沿不够陡,导致其他节点同步失败。嗯,这里要注意——SOF的边沿质量,直接影响整个网络的同步精度

2.2 仲裁场

仲裁场是CAN协议最巧妙的设计之一。它包含两部分:11位标识符(标准帧)或29位标识符(扩展帧),再加上一个RTR位(远程传输请求位)。

说白了,仲裁场就是用来抢总线的。多个节点同时发送时,谁发的标识符数值小(显性位多),谁就赢。我刚开始做CAN开发时,总觉得仲裁是个很复杂的过程。后来用示波器抓了几次波形,发现其实就是“谁先发0,谁就赢”——简单粗暴,但极其高效。

关键点:标识符越小,优先级越高。0x000是最高优先级,0x7FF是最低优先级(标准帧)。

2.3 控制场

控制场有6个位,结构如下:

位位置 名称 说明
Bit 0-3 DLC(数据长度码) 表示数据场有多少个字节(0-8)
Bit 4 IDE(标识符扩展位) 0=标准帧,1=扩展帧
Bit 5 r0(保留位) 显性位,固定为0

我个人习惯在解析报文时,先看DLC。为什么?因为DLC错了,后面的数据场、CRC全都会解析错。我曾经遇到一个案例:某个ECU发送的DLC明明是8,但实际数据只有4个字节有效。结果接收方按照8个字节去解析,把后面的CRC和ACK都当成了数据——整个通信就乱套了。

避坑指南:DLC必须与实际数据长度严格一致。我曾经因为DLC设置错误,导致整个CAN网络出现大量错误帧。排查了整整两天才发现问题。

2.4 数据场

数据场就是报文的“肉”。最多8个字节,最少0个字节。你想想看,一个报文总共也就100多个bit,数据场占了64个bit,超过一半。

数据场的排列方式,我建议遵循Intel格式(小端序)Motorola格式(大端序)。举个例子:

// 假设要发送一个16位数值 0x1234
// Intel格式(小端序):
Byte0 = 0x34  // 低字节在前
Byte1 = 0x12  // 高字节在后

// Motorola格式(大端序):
Byte0 = 0x12  // 高字节在前
Byte1 = 0x34  // 低字节在后

我在项目中遇到过最坑的事:两个ECU来自不同供应商,一个用Intel格式,一个用Motorola格式。结果车速信号解析出来差了256倍。嗯,从那以后,我每次做系统集成,第一件事就是确认字节序

2.5 CRC场

CRC场包含15位CRC校验码和1位CRC界定符(隐性位)。CRC算法用的是CRC-15-CAN,生成多项式是:

x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1

说白了,CRC就是给报文加了一把“锁”。接收方收到报文后,用同样的算法算一遍CRC。如果算出来的结果和发送方的不一致,说明数据在传输过程中被干扰了。

我建议大家在测试时,可以故意制造一些CRC错误,看看ECU的容错机制是否正常。我曾经在实验室里用CANstress工具注入CRC错误,结果发现某个ECU连续收到3个CRC错误帧后,直接进入了Bus-Off状态——这其实是不合理的,因为CAN协议本身有重发机制。

小技巧:CRC校验覆盖的范围是从SOF到数据场的所有bit。不包括CRC场本身和后面的ACK场。

2.6 ACK场

ACK场只有2个位:ACK Slot(应答槽)ACK界定符

ACK Slot的设计很有意思:发送方发送隐性位(1),接收方如果正确收到报文,就把这个位拉成显性(0)。你想想看,这相当于所有接收节点一起举手说:“我收到了!”

如果没有任何节点应答,ACK Slot就会保持隐性。发送方就知道——没人理我。我在调试时经常用这个特性来判断总线连接是否正常。如果某个节点发送报文后,ACK Slot一直是隐性,那多半是总线断开了,或者终端电阻出了问题。

注意:ACK界定符必须是隐性位(1)。如果接收方错误地把界定符也拉成显性,就会产生填充错误。

2.7 EOF(帧结束)

EOF是7个连续的隐性位(1)。它告诉总线:“报文发完了,大家该干嘛干嘛。”

为什么是7个?因为CAN协议规定,连续6个相同位就会触发位填充机制。7个隐性位可以确保EOF不会被误判为填充错误。嗯,这里要注意——EOF之后还有3个ITM(帧间空间)的隐性位,才算真正的总线空闲。

2.8 完整报文结构一览

我把标准帧的完整结构整理成了一张表,方便大家查阅:

字段 位数 说明
SOF 1 帧起始,显性位
标识符 11 标准帧ID,决定优先级
RTR 1 远程帧标志,0=数据帧,1=远程帧
IDE 1 扩展标志,0=标准帧
r0 1 保留位
DLC 4 数据长度(0-8)
数据场 0-64 实际数据,最多8字节
CRC 15 CRC校验码
CRC界定符 1 隐性位
ACK Slot 1 应答位,接收方拉低
ACK界定符 1 隐性位
EOF 7 帧结束,隐性位
ITM 3 帧间空间

最后说一句:CAN报文的结构,是经过几十年验证的经典设计。每一个字段都有它的历史背景和工程考量。我建议大家不要死记硬背,而是拿着示波器去抓几帧实际波形,对照着看一遍——比看十遍书都管用。

下一章,我们会聊CAN的位填充机制和错误处理。到时候见。