3. CAN FD帧结构详解:标准帧与扩展帧格式、SOF/仲裁场/控制场/数据场/CRC场/ACK场/EOF的位级解析
各位同学,今天我们来啃一块硬骨头——CAN FD的帧结构。说实话,我刚接触CAN FD时,也被那一堆场、段、位给绕晕过。但后来我发现,只要你把帧结构拆开来看,每个场都有它存在的道理。就像拆一块手表,齿轮虽多,各司其职。
CAN FD的帧,说白了就是一条消息在总线上的完整形态。它从起始位开始,到结束位收尾,中间包含了地址、控制、数据、校验、应答等所有信息。我们今天就把它从里到外扒一遍。
核心要点:CAN FD帧 = 标准帧格式 + 扩展帧格式,两者在仲裁场和控制场的长度上有差异,其余场结构基本一致。
3.1 帧结构总览
先看一张总图,把帧的骨架搭起来。CAN FD帧由以下7个场组成:
这张图我建议你保存下来。每次调试CAN FD通信时,对照着看,哪里出问题一眼就能定位到哪个场。
3.2 SOF——帧起始
SOF(Start of Frame)只有1个位,但它的作用非常关键。它由显性位(Dominant,逻辑0)构成,用来同步总线上所有节点的时钟。
你想想看,总线上可能有十几个节点,大家各自跑各自的晶振。没有SOF这个同步信号,后面的数据根本没法对齐。我在一个项目中遇到过,某个节点的晶振偏差稍微大了点,结果SOF之后的采样点全偏了,整个网络直接瘫痪。后来换了高精度晶振才解决。
小技巧:SOF的显性位也起到了“唤醒总线”的作用。如果总线处于空闲状态(隐性),SOF的下降沿就是所有节点重新同步的起点。
3.3 仲裁场——谁先说话?
仲裁场是CAN协议最巧妙的设计之一。它解决了“多个节点同时发送时,谁先发”的问题。
仲裁场包含两部分:
- 标识符(ID):标准帧11位,扩展帧29位
- RTR位(Remote Transmission Request):1位,决定是数据帧还是远程帧
标准帧和扩展帧在仲裁场的区别,我用表格给你对比一下:
| 特性 | 标准帧(Base Frame) | 扩展帧(Extended Frame) |
|---|---|---|
| ID长度 | 11位(ID.28 ~ ID.18) | 29位(ID.28 ~ ID.0) |
| 仲裁场总长 | 12位 | 32位 |
| IDE位 | 位于控制场,显性 | 位于仲裁场,隐性 |
| SRR位 | 无 | 替代RTR,隐性 |
| 优先级 | ID值越小,优先级越高 | ID值越小,优先级越高 |
仲裁的原理其实很简单:谁先发隐性位(1),谁就输了。因为显性位(0)会覆盖隐性位。所以ID值越小的节点,优先级越高。我习惯把ID小的节点称为“VIP通道”,它们总能抢到总线。
注意:扩展帧的SRR位必须为隐性,否则会被标准帧的RTR显性位覆盖,导致仲裁失败。这是CAN协议规定的硬性要求。
3.4 控制场——数据怎么传?
控制场是CAN FD与经典CAN差异最大的地方。经典CAN的控制场只有6位,而CAN FD扩展到了8位(标准帧)或9位(扩展帧)。
控制场的位分布如下:
- IDE位(Identifier Extension):1位,显性表示标准帧,隐性表示扩展帧
- r0/r1位:保留位,必须为显性
- BRS位(Bit Rate Switch):1位,CAN FD特有。隐性表示切换到高速数据段
- ESI位(Error State Indicator):1位,CAN FD特有。隐性表示发送节点处于被动错误状态
- DLC位(Data Length Code):4位,表示数据场的字节数
这里有个坑,我当年踩过。DLC在经典CAN中只能表示0~8字节,但在CAN FD中,DLC的编码方式变了。比如DLC=9表示12字节,DLC=10表示16字节,以此类推。如果你用经典CAN的解析方式去读CAN FD的DLC,数据长度会完全对不上。
DLC编码对照表:
| DLC值 | 经典CAN数据长度 | CAN FD数据长度 |
|---|---|---|
| 0~8 | 0~8字节 | 0~8字节 |
| 9 | 8字节 | 12字节 |
| 10 | 8字节 | 16字节 |
| 11 | 8字节 | 20字节 |
| 12 | 8字节 | 24字节 |
| 13 | 8字节 | 32字节 |
| 14 | 8字节 | 48字节 |
| 15 | 8字节 | 64字节 |
重点:BRS位是CAN FD速率切换的关键。当BRS为隐性时,从BRS位之后的数据段和CRC段会切换到高速模式(最高8Mbps)。仲裁段和控制段前半部分仍然使用标准速率(最高1Mbps)。
3.5 数据场——真正的内容
数据场就是你要发送的实际数据。经典CAN最多8字节,CAN FD最多64字节。别小看这个提升,我在做车载网关项目时,一个ECU升级固件包动辄几百KB。用经典CAN传,一个包要拆成几十帧,效率极低。换成CAN FD后,一帧就能塞64字节,传输时间直接砍半。
数据场的排列方式很简单:高位在前,低位在后。比如你要发送0x12345678,在数据场中的顺序是:0x12, 0x34, 0x56, 0x78。
3.6 CRC场——数据完整性保障
CRC场是CAN FD的另一个重大升级。经典CAN使用15位CRC,CAN FD根据数据长度使用17位或21位CRC。
- 数据长度 ≤ 16字节:使用17位CRC(CRC_17)
- 数据长度 > 16字节:使用21位CRC(CRC_21)
为什么这么设计?说白了,数据越长,出错的概率越大,需要的校验能力就越强。17位CRC的汉明距离是4,21位CRC的汉明距离是6。我在一个工业控制项目中,现场电磁干扰特别强,经典CAN的15位CRC偶尔会漏检。换成CAN FD的21位CRC后,再也没出现过校验错误。
CRC场还包含一个CRC分隔符(1位隐性),用来和ACK场隔开。
经验之谈:CRC计算是硬件自动完成的,但你要注意,CAN FD的CRC计算范围包括了SOF、仲裁场、控制场和数据场。如果某个位在传输中被干扰,CRC校验会失败,接收节点会丢弃该帧。
3.7 ACK场——确认收到
ACK场只有2位:ACK Slot(1位)和ACK Delimiter(1位)。
发送节点在ACK Slot发送隐性位。如果接收节点正确收到了帧,它会在ACK Slot发送显性位,覆盖发送节点的隐性位。这样发送节点就知道“嗯,有人收到了”。
如果ACK Slot仍然是隐性,说明没有节点接收成功,发送节点会重发该帧。
我曾经调试过一个多节点网络,发现某个节点总是收不到ACK。查了半天,原来是该节点的接收中断优先级设置太低,导致CPU来不及响应,错过了ACK Slot的发送窗口。嗯,这种问题最坑人。
3.8 EOF——帧结束
EOF(End of Frame)由7个隐性位组成。它的作用很简单:告诉总线上所有节点,这一帧结束了,大家可以准备接收下一帧了。
EOF之后,总线进入间歇场(Intermission),至少3个隐性位。然后总线恢复空闲状态,等待下一帧的SOF。
注意:如果EOF期间检测到显性位,说明发生了填充错误(Stuff Error)。CAN控制器会自动发送错误帧,并请求重传。所以EOF的7个隐性位必须保持干净,不能被干扰。
3.9 标准帧 vs 扩展帧:怎么选?
很多初学者会问:到底用标准帧还是扩展帧?我的建议是:
- 标准帧:ID范围0x000~0x7FF(2048个ID),适合节点数量少、ID分配简单的场景
- 扩展帧:ID范围0x00000000~0x1FFFFFFF(约5.3亿个ID),适合复杂网络、多ECU、需要大量ID的场景
但要注意,扩展帧的仲裁场更长,总线利用率会低一些。如果你只有十几个节点,用标准帧完全够用。我在一个车载项目中,整车有50多个ECU,标准帧的ID空间根本不够用,最后全部切到了扩展帧。