第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 数据帧的七个段

一个完整的数据帧,从开始到结束,一共七个段。我画了张图,你对照着看:

CAN数据帧(标准帧)结构 SOF 1 bit 仲裁场 ID 11 bit + RTR 1 bit 控制场 IDE/r0 2 bit + DLC 4 bit 数据场 0 ~ 8 Byte 用户数据 CRC场 CRC 15 bit + 界定符 1 bit ACK场 ACK Slot 1 bit + 界定符 1 bit EOF 7 bit 各段说明: • SOF(Start of Frame):1个显性位,告诉所有节点“我要发帧了” • 仲裁场:ID决定优先级,RTR位区分数据帧(0)和远程帧(1) • 控制场:IDE区分标准/扩展帧,DLC告诉接收方数据长度(0~8) • 数据场:0~8字节,想传啥传啥 • CRC场:15位CRC校验 + 1位界定符,检错用的 • ACK场:发送方发隐性位,接收方拉显性表示“我收到了”

嗯,这张图我画了好一会儿。你仔细看,每个段都有它的使命。

我的经验:调试时最常看的是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总线自我保护的机制。任何一个节点检测到错误,就会立刻发错误帧,把当前帧冲掉,让所有节点重新同步。

错误帧由两部分组成:

  1. 错误标志(Error Flag):6个连续相同位(显性或隐性)
  2. 错误界定符(Error Delimiter):8个隐性位

错误帧有两种:

错误类型 错误标志 触发条件
主动错误 6个显性位 节点处于主动错误状态
被动错误 6个隐性位 节点处于被动错误状态

避坑指南:我曾经遇到一个项目,总线上一有干扰就死机。用CAN分析仪抓波形,发现错误帧一个接一个。查到最后,是终端电阻虚焊了。记住:错误帧频繁出现,先查物理层——终端电阻、线缆屏蔽、接地,一个都不能少。

2.5 过载帧——慢点,我跟不上

过载帧用得很少,但你必须知道它存在。它由两部分组成:

  • 过载标志(Overload Flag):6个显性位
  • 过载界定符(Overload Delimiter):8个隐性位

什么时候会发过载帧?两种情况:

  1. 接收节点还没处理完上一帧,内部缓冲区满了
  2. 帧间隔期间,检测到显性位(非法情况)

说实话,我在实际项目中几乎没见过过载帧。现在的CAN控制器硬件FIFO都挺深的,除非你CPU太慢,或者中断处理写得稀烂,否则不会触发过载。

2.6 帧间隔——给总线喘口气

帧间隔不是帧,而是帧与帧之间的空闲时间。它让总线上的节点有时间同步状态。

帧间隔的结构:

  • 间歇场(Intermission):3个隐性位
  • 总线空闲(Bus Idle):任意长度的隐性位

对于被动错误节点,帧间隔后面还会多一个挂起传输场(Suspend Transmission):8个隐性位。这是对“犯过错”的节点的惩罚——让它多等一会儿,别抢总线。

2.7 实战要点总结

好了,五种帧都讲完了。我帮你划几个重点:

调试时最常用的三个技巧:

  1. 看ACK位:发送帧后,如果ACK Slot没有被拉显性,说明总线上没有节点在听——要么ID配错了,要么对方没上电。
  2. 看错误帧频率:偶尔一次正常,连续出现就是物理层有问题。
  3. 区分远程帧和数据帧:RTR位是1还是0,用CAN分析仪一眼就能看出来。

下一章咱们会深入CANopen协议栈,看看这些帧是怎么被组织成对象字典和PDO/SDO通信的。但今天的内容是地基——地基不牢,后面全白搭。

你想想看,如果连数据帧和远程帧都分不清,你怎么调试CANopen的SDO上传下载?