2. CAN总线帧结构:数据帧、远程帧、错误帧、过载帧、帧间隔的详细结构与作用
CAN总线上跑的数据,说白了就五种“信封”。每种信封长什么样、干什么用、什么时候发,是每个CAN工程师必须烂熟于心的基本功。我当年刚入行时,就是靠死磕这五种帧结构,才把CAN总线的底层逻辑彻底吃透。
咱们一个一个来拆。
2.1 数据帧——最常用的“快递包裹”
数据帧负责把数据从发送节点送到接收节点。它有两种格式:标准帧(11位ID)和扩展帧(29位ID)。结构上,数据帧由7个段组成:
| 段名称 | 标准帧位数 | 扩展帧位数 | 作用 |
|---|---|---|---|
| 帧起始(SOF) | 1 | 1 | 同步所有节点,标志总线从空闲变为忙碌 |
| 仲裁段 | 12 | 32 | 包含ID和RTR位,决定谁有发送权 |
| 控制段 | 6 | 6 | 标识数据长度(DLC)和扩展格式标志 |
| 数据段 | 0~64 | 0~64 | 真正的有效载荷,最多8字节 |
| CRC段 | 16 | 16 | 15位CRC校验 + 1位CRC界定符 |
| ACK段 | 2 | 2 | 接收节点回应,确认收到无误 |
| 帧结束(EOF) | 7 | 7 | 标志帧结束,释放总线 |
关键点:数据帧的仲裁段里有个RTR位(远程发送请求位),数据帧的RTR=0。这个位在仲裁时非常关键——我后面讲远程帧时会对比。
我在项目中遇到过一个问题:两个节点同时发数据帧,ID小的那个赢了仲裁,但ID大的那个节点因为没收到ACK,会一直重发。嗯,这就是仲裁机制带来的“隐性重发”,设计时一定要考虑好ID的优先级分配。
2.2 远程帧——只问不拿的“查询单”
远程帧的结构和数据帧几乎一样,唯一的区别是:数据段为空,且RTR位=1。
远程帧的作用是什么?说白了就是“请求数据”。节点A发一个远程帧,告诉节点B:“把你那个ID的数据发给我。”节点B收到后,就会发一个同ID的数据帧回来。
避坑指南:我曾经在调试一个电机控制器时,发现总线负载率莫名其妙很高。查了半天,原来是某个传感器节点一直在发远程帧请求数据,而数据节点响应太慢,导致远程帧反复重发。后来我把远程帧的发送间隔调大,问题就解决了。远程帧不是免费的,别滥用。
数据帧和远程帧的仲裁对比:
| 对比项 | 数据帧 | 远程帧 |
|---|---|---|
| RTR位 | 0(显性) | 1(隐性) |
| 数据段 | 有数据(0~8字节) | 无数据 |
| 仲裁优先级 | 更高(RTR=0更优先) | 更低(RTR=1) |
| 典型用途 | 发送传感器值、控制指令 | 请求其他节点发送数据 |
你想想看,如果数据帧和远程帧的ID相同,数据帧一定会赢得仲裁。因为RTR=0比RTR=1更“显性”。这个细节在总线竞争激烈时特别重要。
2.3 错误帧——总线的“警报器”
错误帧是CAN总线自我纠错的核心机制。任何节点检测到错误,都会立即发送错误帧,通知所有节点:“刚才那帧有问题,别用了!”
错误帧由两部分组成:
- 错误标志(Error Flag):6个连续的显性位(主动错误节点)或6个连续的隐性位(被动错误节点)
- 错误界定符(Error Delimiter):8个连续的隐性位
注意:错误帧的发送时机非常关键。节点检测到错误后,必须在下一个位时间就开始发送错误标志。如果多个节点同时检测到错误,它们会同时发送错误标志,导致总线上出现6~12个显性位——这叫“错误叠加”,是CAN协议允许的。
错误帧的触发条件有五种:
- 位错误:发送节点监控总线,发现发送的位和总线上的位不一致
- 填充错误:连续5个相同位后,没有插入填充位
- CRC错误:接收节点计算的CRC和发送节点的不一致
- 形式错误:固定格式的位段(如EOF、界定符)出现错误电平
- ACK错误:发送节点没有收到ACK显性回应
我个人习惯在调试时,用CAN分析仪抓一下错误帧的类型。如果看到大量CRC错误,多半是总线干扰大;如果看到位错误,可能是节点时钟偏差太大。这些经验,都是被项目逼出来的。
2.4 过载帧——总线的“慢点,我还没准备好”
过载帧的作用很简单:当一个节点忙不过来时,它发一个过载帧,让其他节点等一等。
过载帧的结构和错误帧很像:
- 过载标志:6个显性位
- 过载界定符:8个隐性位
触发过载帧的条件有两个:
- 接收节点内部条件未准备好(比如缓冲区满了)
- 在帧间隔的间歇场检测到显性位(这属于异常情况)
实战经验:我曾经在一个多节点系统中,发现某个节点频繁发送过载帧。一开始以为是硬件问题,后来用示波器一量,发现那个节点的MCU主频偏低,导致CAN控制器来不及处理接收到的数据。换了个晶振就好了。过载帧是“求救信号”,别忽视它。
2.5 帧间隔——总线的“休息时间”
帧间隔不是一帧,而是两帧之间的空闲时段。它让总线有时间恢复,也让节点有时间处理上一帧的数据。
帧间隔由两部分组成:
- 间歇场(Intermission):3个隐性位
- 总线空闲(Bus Idle):任意长度的隐性位,直到有节点开始发送
对于被动错误节点,帧间隔还会多一个暂停发送场(Suspend Transmission):8个隐性位。这是对被动错误节点的“惩罚”——让它多等一会儿,减少对总线的干扰。
你想想看,如果没有帧间隔,总线上的帧会一个接一个地紧挨着发。接收节点根本没时间处理数据,缓冲区很快就满了。帧间隔就是给节点喘口气的机会。
2.6 五种帧的关系——一张SVG图说清楚
下面这张图展示了五种帧在总线上的出现顺序和关系。我建议你把它存下来,面试时绝对用得上。
2.7 实战中的帧结构调试技巧
说了这么多理论,来点实际的。我调试CAN总线时,最常用的三板斧:
- 看SOF和EOF:用示波器抓波形,先找到帧起始的下降沿和帧结束的7个隐性位。如果EOF不完整,说明帧被错误帧打断了。
- 数填充位:连续5个相同位后,必须有一个填充位。如果发现连续6个相同位,那就是填充错误,节点会发错误帧。
- 查ACK:发送节点在ACK槽位会释放总线(隐性),接收节点必须拉成显性。如果ACK槽一直是隐性,说明没有节点收到这帧——要么ID不匹配,要么节点离线了。
核心总结:数据帧是主力,远程帧是辅助,错误帧是保镖,过载帧是缓冲,帧间隔是呼吸。把这五种帧吃透了,CAN总线对你来说就没有秘密了。