CAN 帧格式 -- 帧类型、仲裁与位填充
目录
1. CAN 帧类型总览
CAN 协议定义了 4 种帧类型:
| 帧类型 | 用途 |
|---|---|
| 数据帧(Data Frame) | 发送节点向其他节点传输数据 |
| 远程帧(Remote Frame) | 请求其他节点发送数据(已较少使用) |
| 错误帧(Error Frame) | 节点检测到总线错误时发送 |
| 过载帧(Overload Frame) | 接收节点需要更多处理时间时发送 |
数据帧是最常用的帧类型,本教程重点讲解。
2. 数据帧结构详解
一个标准数据帧由以下字段组成:
SOF | 仲裁场 | 控制场 | 数据场 | CRC 场 | ACK 场 | EOF
1bit | 11/29bit | 6bit | 0-8字节 | 16bit | 2bit | 7bit2.1 帧起始(SOF, Start of Frame)
- 1 bit 显性电平
- 所有节点通过 SOF 实现位同步
- 表示一帧的开始
2.2 仲裁场(Arbitration Field)
仲裁场包含 CAN ID 和 RTR 位:
| 帧类型 | CAN ID 长度 | RTR 位 | 总长度 |
|---|---|---|---|
| 标准帧(CAN 2.0A) | 11 bit | 1 bit | 12 bit |
| 扩展帧(CAN 2.0B) | 29 bit | 1 bit | 30 bit |
- CAN ID:标识报文的身份,数值越小,优先级越高
- RTR(Remote Transmission Request):
- 数据帧:RTR = 显性(0)
- 远程帧:RTR = 隐性(1)
2.3 控制场(Control Field)
| 字段 | 长度 | 说明 |
|---|---|---|
| IDE | 1 bit | 标识符扩展位(0=标准帧,1=扩展帧) |
| r0 | 1 bit | 保留位 |
| DLC | 4 bit | 数据长度码(0-8) |
2.4 数据场(Data Field)
- 0-8 字节数据
- 这是 CAN 2.0 的硬性限制 —— 最多只能携带 8 字节有效数据
- 字节顺序:高位字节先发送
思考:8 字节的限制对高层协议(如 CANOpen SDO 传输大于 4 字节的数据)有什么影响?答案是:需要分段传输。
2.5 CRC 场(CRC Field)
- 15 bit CRC + 1 bit CRC 定界符
- 用于检测传输错误
- 发送方计算 CRC,接收方验证
2.6 ACK 场(Acknowledgment Field)
- ACK 槽(1 bit)+ ACK 定界符(1 bit)
- 接收方在 ACK 槽位置发送显性电平,表示"我收到了"
- 如果发送方在 ACK 槽读到隐性电平,说明没有节点收到此帧
2.7 帧结束(EOF, End of Frame)
- 7 bit 隐性电平
- 表示一帧的结束
3. 仲裁机制(重点)
3.1 为什么需要仲裁?
当多个节点同时尝试发送时,总线不能冲突。CAN 使用 CSMA/CD+AMP(带仲裁的载波监听多路访问/碰撞检测)机制来解决这个问题。
3.2 仲裁过程
规则:逐位仲裁,ID 越小,优先级越高。
过程图解:
时间 →
节点 A (ID=0x100): 0 0 0 1 0 0 0 0 0 0 0 ... (发送 0x100)
节点 B (ID=0x200): 0 1 0 0 0 0 0 0 0 0 0 ... (发送 0x200)
─────────────────────────────────────────────
总线实际值: 0 0 0 1 0 0 0 0 0 0 0 ... (显性覆盖隐性)
↑
节点 B 发送隐性(1)
但读到显性(0) → 退出发送详细步骤:
- 节点 A 和节点 B 同时开始发送
- 第 1 位:都是 0(显性),双方都继续
- 第 2 位:A 发 0(显性),B 发 1(隐性)
- B 读到 0(显性),但自己发的是 1(隐性) → B 知道有更高优先级的节点在发送 → B 立即停止发送,转为接收模式
- A 继续完成发送
关键结论:
- ID 值越小,在仲裁中越早赢得总线
- 0x000 是最高优先级(这就是为什么 CANOpen 的 NMT 命令使用 COB-ID 0x000)
- 仲裁过程无延迟、无数据损失 —— 失败的节点自动在下一帧重试
4. 位填充规则
4.1 什么是位填充?
CAN 规定:连续发送 5 个相同电平的位后,自动插入一个相反电平的位。
原始数据: 0 0 0 0 0 0 0 0 (连续 8 个 0)
填充后: 0 0 0 0 0 1 0 0 0 0 1 0 (每 5 个 0 后插入 1)4.2 为什么需要位填充?
- 时钟同步:接收方通过电平跳变来同步时钟,长串相同位会导致失去同步
- 区分帧边界:SOF 是显性,前面至少有 3 个隐性位(帧间空间),位填充确保数据中不会出现类似 SOF 的长串隐性
4.3 哪些字段需要位填充?
| 字段 | 是否位填充 |
|---|---|
| SOF | 否 |
| 仲裁场 | 是 |
| 控制场 | 是 |
| 数据场 | 是 |
| CRC 场 | 是 |
| ACK 场 | 否 |
| EOF | 否 |
5. CAN ID 与 CANOpen COB-ID 的关系
在纯 CAN 层,只有 CAN ID(11-bit 或 29-bit)。
在 CANOpen 应用层,这个 ID 被称为 COB-ID(Communication Object Identifier),并被赋予了更丰富的语义:
COB-ID 结构(11-bit 标准帧):
高 4 bit | 低 7 bit
─────────────────────────────
功能码 | 节点 ID
(Function Code)| (Node ID)| 功能码(高 4 bit) | COB-ID 范围 | CANOpen 功能 |
|---|---|---|
| 0000 | 0x000 | NMT(网络管理) |
| 0001 | 0x080-0x0FF | SYNC / TIME |
| 0011 | 0x180-0x1FF | PDO 1 TX |
| 0100 | 0x200-0x27F | PDO 1 RX |
| … | … | … |
| 1011 | 0x580-0x5FF | SDO TX(响应) |
| 1100 | 0x600-0x67F | SDO RX(请求) |
| 1110 | 0x700-0x77F | Heartbeat / Node Guarding |
这就是 CANOpen 的核心设计 —— 通过预定义的 COB-ID 分配表,将不同的通信对象映射到不同的 CAN ID 上,利用 CAN 的仲裁机制实现优先级管理。
6. 扩展帧(CAN 2.0B)
扩展帧使用 29-bit 标识符,结构为:
SOF | 11-bit 基 ID | SRR | IDE | 18-bit 扩展 ID | 控制场 | ...- SRR(Substitute Remote Request):替代远程请求位,始终为隐性
- IDE(Identifier Extension):标识符扩展位,扩展帧中为 1
CANOpen 主要使用标准帧(11-bit),因为 2048 个 COB-ID 已经足够大多数应用。
7. 关键知识点总结
| 知识点 | 要点 |
|---|---|
| 数据帧字段 | SOF → 仲裁 → 控制 → 数据 → CRC → ACK → EOF |
| CAN ID 长度 | 标准帧 11-bit(0x000-0x7FF),扩展帧 29-bit |
| 仲裁规则 | ID 越小优先级越高,显性覆盖隐性 |
| 位填充 | 连续 5 个相同位后插入相反位 |
| 数据限制 | 最多 8 字节 |
| COB-ID | CAN ID 在 CANOpen 中的称呼,高 4 bit = 功能码,低 7 bit = 节点 ID |
★ Insight ─────────────────────────────────────
- CAN 仲裁的优雅之处在于:它不需要额外的时间槽或重传机制,仲裁与数据传输同时进行,失败的节点在第一个不同位就自动退出。
- 8 字节数据限制是 CAN 的核心瓶颈,也是 CAN FD(64 字节)出现的原因。但在 CANOpen 中,这个限制通过 SDO 分段传输得到了巧妙解决。
- COB-ID 的设计体现了"ID 即功能"的思想 —— 不需要额外的协议头来标识报文类型,CAN ID 本身就携带了语义信息。
─────────────────────────────────────────────────
上一步 | 下一步
← 01-can-physical-layer.md —— CAN 物理层 → 03-socketcan-intro.md —— SocketCAN 入门
如果这篇文章对你有帮助,欢迎请我喝杯咖啡 ☕
支付宝
微信