第2章 CAN帧结构:数据帧、远程帧、错误帧、过载帧、帧间隔详解
各位好,我是老周。今天咱们来啃CAN总线最核心的东西——帧结构。
很多人学CAN,上来就背ID、波特率,结果一上示波器,波形都认不全。我当年也吃过这个亏。有一次调试一个电机驱动器,总线莫名其妙挂掉,折腾了两天,最后发现是错误帧把总线塞爆了。从那以后,我养成了一个习惯:先搞懂帧结构,再动手写代码。
2.1 CAN总线的五种帧类型
CAN总线上一共就五种帧。不多,但每种都有它的脾气。我整理了一张表,你一看就明白:
| 帧类型 | 英文名 | 用途 | 谁发 |
|---|---|---|---|
| 数据帧 | Data Frame | 携带数据从发送器到接收器 | 发送节点 |
| 远程帧 | Remote Frame | 请求某个ID的数据 | 接收节点 |
| 错误帧 | Error Frame | 通知总线发生了错误 | 检测到错误的节点 |
| 过载帧 | Overload Frame | 请求延迟下一个帧 | 接收节点 |
| 帧间隔 | Interframe Space | 帧与帧之间的隔离区 | 所有节点 |
说白了,日常开发中打交道最多的就是数据帧和远程帧。错误帧和过载帧是总线自己维护秩序用的,但你必须懂——不然出了问题你都不知道总线在骂你。
核心观点:CAN总线没有主从之分,任何节点都可以在任何时刻发起通信。帧结构就是它们之间唯一的“语言”。
2.2 数据帧——最常用的帧
数据帧是干活的主力。它负责把传感器数据、控制指令从一个节点搬到另一个节点。
数据帧分两种格式:标准帧(11位ID)和扩展帧(29位ID)。我个人的习惯是:能用标准帧就别用扩展帧,省带宽、省时间。除非你的节点数量超过2048个,或者必须兼容CANopen的PDO映射。
2.2.1 数据帧的七个段
一个完整的数据帧,从开始到结束,一共七个段。我画了张图,你对照着看:
嗯,这张图我画了好一会儿。你仔细看,每个段都有它的使命。
我的经验:调试时最常看的是DLC(数据长度码)和CRC。DLC不对,数据就解析错了;CRC不对,说明物理层有问题——要么波特率配错了,要么终端电阻没焊。
2.2.2 仲裁机制——谁ID小谁先走
CAN总线最牛的地方,就是它的非破坏性逐位仲裁。说白了,两个节点同时发数据,谁的ID小,谁就赢。输的那个自动退出发送,等总线空闲了再重试。
为什么会这样?因为CAN总线是“线与”逻辑:显性位(0)会覆盖隐性位(1)。仲裁的时候,每个节点都在发自己的ID位,一边发一边监听总线。如果自己发的是隐性位(1),但总线上是显性位(0),说明有优先级更高的节点在发——自己乖乖闭嘴。
注意:ID越小,优先级越高。所以CANopen里,NMT(网络管理)对象的ID通常设得很小,比如0x000。紧急报文(EMCY)的ID也很小,确保紧急情况能抢到总线。
2.3 远程帧——只问不拿
远程帧长得很像数据帧,但有两个关键区别:
- RTR位 = 1(数据帧的RTR = 0)
- 没有数据场(DLC可以非零,但实际不传数据)
远程帧的用途是:一个节点向另一个节点请求数据。比如,传感器节点A发一个远程帧,ID = 0x200,DLC = 2。节点B收到后,如果它配置了ID=0x200的数据帧,就会立刻发一个数据帧回来。
我记得有一次做CANopen从站,远程帧把我坑惨了。我忘了在接收远程帧后自动回复数据帧,结果主站一直收不到数据,报超时错误。后来查了协议栈源码才发现,CAN控制器硬件会自动响应远程帧——前提是你得把对应的邮箱配成“远程帧触发发送”模式。
2.4 错误帧——总线的“骂街”机制
错误帧是CAN总线自我保护的机制。任何一个节点检测到错误,就会立刻发错误帧,把当前帧冲掉,让所有节点重新同步。
错误帧由两部分组成:
- 错误标志(Error Flag):6个连续相同位(显性或隐性)
- 错误界定符(Error Delimiter):8个隐性位
错误帧有两种:
| 错误类型 | 错误标志 | 触发条件 |
|---|---|---|
| 主动错误 | 6个显性位 | 节点处于主动错误状态 |
| 被动错误 | 6个隐性位 | 节点处于被动错误状态 |
避坑指南:我曾经遇到一个项目,总线上一有干扰就死机。用CAN分析仪抓波形,发现错误帧一个接一个。查到最后,是终端电阻虚焊了。记住:错误帧频繁出现,先查物理层——终端电阻、线缆屏蔽、接地,一个都不能少。
2.5 过载帧——慢点,我跟不上
过载帧用得很少,但你必须知道它存在。它由两部分组成:
- 过载标志(Overload Flag):6个显性位
- 过载界定符(Overload Delimiter):8个隐性位
什么时候会发过载帧?两种情况:
- 接收节点还没处理完上一帧,内部缓冲区满了
- 帧间隔期间,检测到显性位(非法情况)
说实话,我在实际项目中几乎没见过过载帧。现在的CAN控制器硬件FIFO都挺深的,除非你CPU太慢,或者中断处理写得稀烂,否则不会触发过载。
2.6 帧间隔——给总线喘口气
帧间隔不是帧,而是帧与帧之间的空闲时间。它让总线上的节点有时间同步状态。
帧间隔的结构:
- 间歇场(Intermission):3个隐性位
- 总线空闲(Bus Idle):任意长度的隐性位
对于被动错误节点,帧间隔后面还会多一个挂起传输场(Suspend Transmission):8个隐性位。这是对“犯过错”的节点的惩罚——让它多等一会儿,别抢总线。
2.7 实战要点总结
好了,五种帧都讲完了。我帮你划几个重点:
调试时最常用的三个技巧:
- 看ACK位:发送帧后,如果ACK Slot没有被拉显性,说明总线上没有节点在听——要么ID配错了,要么对方没上电。
- 看错误帧频率:偶尔一次正常,连续出现就是物理层有问题。
- 区分远程帧和数据帧:RTR位是1还是0,用CAN分析仪一眼就能看出来。
下一章咱们会深入CANopen协议栈,看看这些帧是怎么被组织成对象字典和PDO/SDO通信的。但今天的内容是地基——地基不牢,后面全白搭。
你想想看,如果连数据帧和远程帧都分不清,你怎么调试CANopen的SDO上传下载?