4. CAN帧结构详解

各位好,今天我们正式进入CAN数据帧的细节。说实话,很多工程师学了几年CAN,报文能收发,但遇到总线竞争、应答异常时还是一头雾水。根本原因就是帧结构没吃透。

数据帧是CAN总线最常用的帧类型,没有之一。它负责把节点要发送的数据,从发送器传到接收器。整个帧由7个段组成,今天我们只讲前三个:帧起始(SOF)、仲裁场和控制场。这三个段决定了谁能发、发什么、发多少。

核心要点:SOF同步总线,仲裁场决定优先级,控制场告诉接收方数据长度。这三个段加起来只有不到20个位,但它们是CAN总线“无主通信”的基石。

4.1 帧起始(SOF)—— 总线的“发令枪”

SOF只有一个显性位(逻辑0)。别看它短,作用极大。

  • 同步作用:所有节点在总线空闲时,都在监听。一旦某个节点拉低总线(发送显性位),其他节点立即同步到这位的边沿。
  • 标志作用:SOF告诉所有节点:“我要开始发帧了,你们准备好接收。”
  • 硬同步:每个节点收到SOF的下降沿时,会强制调整自己的采样点位置。这是CAN总线位同步的第一道保障。

我的经验:有一次调试一个电机控制器,总线偶尔丢帧。抓波形发现SOF之后的同步段有毛刺,导致采样点偏移。后来在硬件上加了一级施密特触发器,问题解决。嗯,SOF的边沿质量,直接影响整个帧的接收可靠性。

4.2 仲裁场 —— 谁优先级高谁先走

仲裁场由两部分组成:11位标识符(ID) + RTR位。这是CAN总线最精彩的设计之一。

4.2.1 11位标识符(ID)

ID不是地址,而是优先级标签。数值越小,优先级越高。

  • 范围:0x000 ~ 0x7FF(0~2047),共2048个可用ID。
  • 发送顺序:从高位(ID.10)到低位(ID.0)逐位发送。
  • 仲裁机制:多个节点同时发送时,逐位比较。谁先发出显性位(0),谁就赢得总线。

为什么会这样?因为CAN总线是“线与”逻辑:显性位(0)会覆盖隐性位(1)。你想想看,如果两个节点同时发,一个发0,一个发1,总线上最终是0。发1的节点检测到总线与自己输出不一致,就知道自己输了,立即转为接收模式。

避坑指南:我曾经见过一个团队,把ID从0x700开始分配,结果所有节点优先级都很低,高优先级的紧急报文反而抢不到总线。记住:ID越小优先级越高,紧急报文用小编号ID。

4.2.2 RTR位(Remote Transmission Request)

RTR位紧跟在ID之后,用于区分数据帧和远程帧。

帧类型 RTR值 说明
数据帧 显性(0) 发送器主动发送数据
远程帧 隐性(1) 请求其他节点发送数据

这里有个细节:如果数据帧和远程帧的ID相同,数据帧的RTR=0,远程帧的RTR=1。仲裁时,数据帧的显性位会获胜。所以远程帧的优先级永远低于同ID的数据帧。

我个人的习惯:除非有明确的远程请求需求,否则尽量少用远程帧。因为远程帧不携带数据,却占用总线带宽。而且处理不好容易造成“请求风暴”。

4.3 控制场 —— 帧格式与数据长度

控制场共6位:IDE(1位) + r0(1位保留位) + DLC(4位)。

4.3.1 IDE位(Identifier Extension)

IDE位决定当前帧是标准帧还是扩展帧。

  • IDE = 0(显性):标准帧,11位ID。控制场之后直接跟数据场。
  • IDE = 1(隐性):扩展帧,29位ID。控制场之后还有18位扩展ID。

注意:标准帧的IDE是显性,扩展帧的IDE是隐性。这意味着在仲裁时,标准帧的优先级天然高于同ID的扩展帧。

4.3.2 r0位(保留位)

r0是保留位,必须发送显性(0)。接收器会检查这一位,如果收到隐性(1),则视为格式错误。

我曾经踩过的坑:早期某款MCU的CAN控制器,r0位在初始化时默认配置为隐性。结果一上总线就报格式错误。查了两天才发现是寄存器配置问题。所以,保留位一定要按规范置0,别想当然。

4.3.3 DLC(Data Length Code)

DLC共4位,表示数据场包含的字节数。取值范围0~8。

DLC值(二进制) 数据长度(字节) 常见用途
0000 ~ 1000 0 ~ 8 标准数据长度
1001 ~ 1111 保留(通常视为8) 部分控制器会报错

DLC超过8(即二进制1001~1111)时,大多数CAN控制器仍然发送8字节数据,但部分严格实现会报错。我个人建议:永远不要用DLC > 8,这是给自己挖坑。

4.4 本章结构总览

下面这张图把今天讲的三个段串起来,方便你记忆。

CAN数据帧前三个段结构图 CAN数据帧前三个段结构 SOF 1位 显性0 仲裁场 12位 11位ID RTR 控制场 6位 IDE r0 DLC 后续段 下章讲解 📌 关键记忆点 • SOF:1位显性,同步所有节点 • 仲裁场:11位ID(优先级)+ RTR(帧类型),逐位仲裁 • 控制场:IDE(标准/扩展)+ r0(保留)+ DLC(数据长度0~8) • 三个段共19位,决定了帧的“身份”和“大小”

4.5 常见问题与避坑

  1. ID分配问题:不要从大往小分配,紧急报文用小编号。
  2. RTR滥用:远程帧优先级低,且不携带数据,非必要不使用。
  3. DLC超限:DLC > 8时行为未定义,不同控制器处理方式不同,统一用0~8。
  4. 保留位r0:必须置0,不要依赖控制器自动处理。