4. CAN协议详解:数据帧、远程帧、错误帧、过载帧结构,仲裁机制与位填充规则

各位同学,今天我们来啃一块硬骨头——CAN协议的核心帧结构。说实话,我刚入行那会儿,看着CAN总线上那些0101的波形,也是一头雾水。但后来我发现,只要把四种帧结构搞明白,CAN总线基本就通了八成。

CAN总线上一共就四种帧:数据帧、远程帧、错误帧、过载帧。咱们一个一个来拆解。

4.1 数据帧——最常用的那个

数据帧,说白了就是“谁有话要说,就发一包数据出去”。我做过一个项目,车上十几个ECU,大部分时间都在发数据帧。数据帧的结构,我习惯把它分成七段:

段名称 位数 说明
帧起始(SOF) 1 bit 显性电平,同步信号
仲裁段 12或32 bit ID + RTR + IDE + r0
控制段 6 bit DLC + 保留位
数据段 0~64 bit 实际数据内容
CRC段 16 bit CRC校验 + 界定符
ACK段 2 bit 应答槽 + 界定符
帧结束(EOF) 7 bit 隐性电平

嗯,这里要注意:标准帧和扩展帧的区别就在仲裁段。标准帧ID是11位,扩展帧是29位。我个人习惯,能用标准帧就别用扩展帧,省带宽。但有些项目非要29位ID,那就得硬着头皮上。

4.2 远程帧——只问不拿

远程帧很有意思。它就像你对着对讲机喊:“谁有数据?发给我!”但自己不带数据。远程帧的结构和数据帧几乎一样,唯一的区别是RTR位:数据帧的RTR是显性(0),远程帧的RTR是隐性(1)。

关键点:远程帧没有数据段。DLC字段表示请求的数据长度,但实际不发数据。

我曾经踩过一个坑:某个ECU发了远程帧请求车速数据,结果另一个ECU没响应。查了半天,发现是DLC对不上。你请求8字节,但对方只发4字节,那就对不上了。所以,DLC一定要约定好。

4.3 错误帧——总线上的警报器

错误帧,说白了就是“有人发现数据错了,赶紧喊停”。错误帧由两部分组成:

  • 错误标志:6个连续的显性位(主动错误)或6个连续的隐性位(被动错误)
  • 错误界定符:8个连续的隐性位

这里有个细节:主动错误节点会发送6个显性位,这会把总线上的其他节点也拉进错误状态。被动错误节点只能发6个隐性位,不会干扰总线。我遇到过一台ECU频繁进入被动错误状态,结果总线上一堆错误帧,整个网络都快瘫痪了。后来发现是它的晶振漂移了,导致位时序不对。

避坑指南:我曾经调试过一个项目,错误帧满天飞。用示波器一看,发现是终端电阻没焊好。CAN总线两端必须各有一个120Ω电阻,少一个都不行。

4.4 过载帧——我忙,别发

过载帧,说白了就是“我处理不过来了,等等再发”。它和错误帧结构很像,也是6个显性位+8个隐性位。但触发条件不同:

  • 接收节点还没准备好接收下一帧
  • 检测到位填充错误(这个后面讲)

过载帧在实际项目中不常见。我做了这么多年,也就碰到过两三次。一般是因为某个ECU的接收缓冲区太小,或者CPU负载太高。

4.5 仲裁机制——谁ID小谁先走

CAN总线的仲裁机制,我觉得是它最巧妙的设计。多个节点同时发送时,谁先抢到总线?答案是:ID最小的那个。

为什么?因为CAN总线是“线与”逻辑:显性(0)会覆盖隐性(1)。仲裁时,每个节点逐位发送自己的ID。如果某个节点发送了隐性位,但总线上是显性位,它就输了,乖乖退出发送。

个人经验:我习惯把高优先级消息(比如刹车、安全气囊)分配小ID,低优先级消息(比如车窗、空调)分配大ID。这样紧急消息总能抢到总线。

举个例子:节点A的ID是0x100,节点B的ID是0x200。同时发送时,A的ID第一位是0,B的第一位是1。A的显性位把B的隐性位覆盖了,B检测到总线电平和自己发的不一致,就退出了。最后A成功发送。

4.6 位填充规则——防止同步丢失

位填充,说白了就是“连续5个相同位,就插一个相反位”。为什么要有这个规则?因为CAN节点靠电平跳变来同步时钟。如果连续太多相同的位,节点就会失去同步。

规则很简单:

  • 发送方:连续发送5个相同位后,自动插入一个相反位
  • 接收方:检测到5个相同位后,自动删除下一个位(填充位)

但要注意:CRC界定符、ACK界定符、EOF这些固定格式的段,不进行位填充。我刚开始做CAN驱动时,就因为这个踩过坑——自己写的位填充逻辑把EOF也给填充了,结果接收方一直报错。

位填充范围:从SOF到CRC段(包括CRC段的数据,但不包括CRC界定符)。

4.7 本章知识体系

下面这张图,是我自己画的CAN帧结构关系图。你看一眼,基本就全串起来了:

CAN协议帧结构关系图 数据帧 远程帧 错误帧 过载帧 SOF | 仲裁段(11/29bit ID+RTR) | 控制段(6bit) | 数据段(0-64bit) | CRC段(16bit) | ACK段(2bit) | EOF(7bit) 无数据段,RTR=1 6显性/隐性 + 8隐性 6显性 + 8隐性 仲裁机制:ID越小优先级越高 显性位(0)覆盖隐性位(1),发送隐性位但读到显性位则退出 位填充规则:连续5个相同位 → 插入1个相反位 范围:SOF ~ CRC段(不含界定符) 四种帧通过仲裁机制竞争总线,位填充保证同步 关键点:数据帧和远程帧的RTR位不同,错误帧和过载帧结构相似但触发条件不同

这张图把四种帧的关系、结构、仲裁和位填充都串起来了。你保存下来,以后调试CAN总线时拿出来对照着看,会很有帮助。

我的建议:初学者可以先从数据帧入手,把它的七段结构背下来。然后对比远程帧,记住RTR位的区别。错误帧和过载帧先了解触发条件,遇到问题再回头查。

好了,CAN协议的帧结构就讲到这里。下一章我们聊聊CAN的位时序和同步机制,那个更烧脑,但搞懂了就能自己调波特率了。


可可精品资料库