📚 CAN总线技术系列 · 持续更新中
本系列从差分电气层一路打到 Linux SocketCAN,把"两根线"背后的电气/协议/控制器/驱动/实战全拧成一根线。
👉 想系统追更,戳这里查看完整专栏:
👉 其他技术系列专栏,欢迎关注、交流、共同成长:
【SPI 技术系列】 【I2C 技术系列】 【串口技术系列】【RISC-V 架构系列】【Linux内核系列】 【操作系统设计思想系列】 【 Android 系统全景专栏】
本篇定位:CAN 物理层和位定时讲完,本篇讲协议层------帧格式。CAN 有四种帧:数据帧、远程帧、错误帧、过载帧。数据帧是主战场(SOF+ID+控制+数据+CRC+ACK+EOF)。本篇逐位讲清帧结构、标准/扩展帧、CAN FD 帧扩展。读完你能看懂任何 CAN 抓包波形,知道每一位什么作用。
CAN 帧是协议层的核心I2C 帧(START+地址+ACK+数据+STOP)简单。CAN 帧复杂得多 ------SOF/仲裁/控制/数据/CRC/ACK/EOF 七段,每段有定义,且 CRC15/ACK 机制保证可靠。理解帧格式是抓包分析、错误定位、写驱动的基础。对照 SPI技术系列 04 · SPI 协议与时序详解(CPOL/CPHA) 和 【I2C 技术系列 04】I2C 协议与时序详解 看,理解三种总线帧格式的差异。
目录
- 一、四种帧类型
-
- [1.1 数据帧(主用)](#1.1 数据帧(主用))
- [1.2 远程帧](#1.2 远程帧)
- [1.3 错误帧](#1.3 错误帧)
- [1.4 过载帧](#1.4 过载帧)
- 二、数据帧结构
-
- [2.1 经典 CAN 数据帧(标准帧 11bit ID)](#2.1 经典 CAN 数据帧(标准帧 11bit ID))
- [2.2 各段作用](#2.2 各段作用)
- [2.3 总位数](#2.3 总位数)
- [三、仲裁段(ID + RTR + IDE)](#三、仲裁段(ID + RTR + IDE))
-
- [3.1 仲裁段组成](#3.1 仲裁段组成)
- [3.2 ID(标识符)](#3.2 ID(标识符))
- [3.3 RTR(Remote Transmission Request)](#3.3 RTR(Remote Transmission Request))
- [3.4 IDE(Identifier Extension)](#3.4 IDE(Identifier Extension))
- [3.5 SRR(Substitute Remote Request)](#3.5 SRR(Substitute Remote Request))
- 四、控制段与数据段
-
- [4.1 控制段(6 位)](#4.1 控制段(6 位))
- [4.2 DLC(数据长度码)](#4.2 DLC(数据长度码))
- [4.3 数据段](#4.3 数据段)
- [五、CRC 段与 ACK 段](#五、CRC 段与 ACK 段)
-
- [5.1 CRC 段](#5.1 CRC 段)
- [5.2 CAN FD CRC](#5.2 CAN FD CRC)
- [5.3 ACK 段](#5.3 ACK 段)
- [5.4 ACK 机制意义](#5.4 ACK 机制意义)
- [六、EOF 与帧间隔](#六、EOF 与帧间隔)
-
- [6.1 EOF(End of Frame)](#6.1 EOF(End of Frame))
- [6.2 IFS(Intermission,帧间隔)](#6.2 IFS(Intermission,帧间隔))
- [6.3 挂起传输(Suspend)](#6.3 挂起传输(Suspend))
- [七、标准帧 vs 扩展帧](#七、标准帧 vs 扩展帧)
-
- [7.1 ID 长度](#7.1 ID 长度)
- [7.2 帧长度](#7.2 帧长度)
- [7.3 共存](#7.3 共存)
- [7.4 选择](#7.4 选择)
- [八、CAN FD 帧扩展](#八、CAN FD 帧扩展)
-
- [8.1 FD 帧新增位](#8.1 FD 帧新增位)
- [8.2 FD 帧结构](#8.2 FD 帧结构)
- [8.3 FD 数据段](#8.3 FD 数据段)
- [8.4 FD vs 经典帧识别](#8.4 FD vs 经典帧识别)
- 九、远程帧与错误帧
-
- [9.1 远程帧(Remote Frame)](#9.1 远程帧(Remote Frame))
- [9.2 远程帧的应用](#9.2 远程帧的应用)
- [9.3 错误帧(Error Frame)](#9.3 错误帧(Error Frame))
- [9.4 错误帧作用](#9.4 错误帧作用)
- [9.5 过载帧(Overload Frame)](#9.5 过载帧(Overload Frame))
- [十、关键问题 Q&A](#十、关键问题 Q&A)
-
- [Q1:数据帧从 SOF 到 EOF 每一位什么作用?](#Q1:数据帧从 SOF 到 EOF 每一位什么作用?)
- [Q2:ACK 位怎么工作?](#Q2:ACK 位怎么工作?)
- Q3:标准帧和扩展帧能共存吗?
- [Q4:CAN FD 帧和经典帧怎么识别?](#Q4:CAN FD 帧和经典帧怎么识别?)
- Q5:远程帧现在还用吗?
- [Q6:CRC15 怎么算?](#Q6:CRC15 怎么算?)
- 十一、实战案例
-
- [案例 1:ACK 错误,帧重发](#案例 1:ACK 错误,帧重发)
- [案例 2:扩展帧 ID 解析错](#案例 2:扩展帧 ID 解析错)
- [案例 3:CRC 错,错误帧频发](#案例 3:CRC 错,错误帧频发)
- [案例 4:CAN FD 数据段被当经典帧解析](#案例 4:CAN FD 数据段被当经典帧解析)
- [案例 5:远程帧无响应](#案例 5:远程帧无响应)
- [案例 6:EOF 格式错](#案例 6:EOF 格式错)
- [案例 7:DLC > 8 数据截断](#案例 7:DLC > 8 数据截断)
- 十二、本篇小结与速查
- 延伸阅读
- 参考资料
一、四种帧类型
| 帧类型 | 用途 | 方向 |
|---|---|---|
| 数据帧(Data Frame) | 发送数据 | 主用 |
| 远程帧(Remote Frame) | 请求某 ID 数据 | 辅助 |
| 错误帧(Error Frame) | 报错 | 异常 |
| 过载帧(Overload Frame) | 请求延迟下一帧 | 流控 |
1.1 数据帧(主用)
节点发送数据用,最常见。
1.2 远程帧
节点请求某 ID 的数据(被动请求)。RTR=1,无数据段。现代 CAN 少用(多用应用层请求)。
1.3 错误帧
节点检测到错误时发,6 个连续显性(主动错误)或 6 个隐性(被动错误)+ 8 个隐性定界。破坏当前帧,所有节点丢弃。
1.4 过载帧
接收节点来不及处理,请求延迟下一帧。现代控制器 FIFO 深少用。
二、数据帧结构
2.1 经典 CAN 数据帧(标准帧 11bit ID)
┌─────┬──────────┬───────┬──────┬───────┬────────┬──────┬─────┐
│ SOF │ 仲裁段 │ 控制段│数据段│ CRC段 │ ACK段 │ EOF │ IFS │
│ 1位 │ 12位 │ 6位 │0-64位│16位 │ 2位 │ 7位 │ 3位 │
│ │ID+RTR+IDE│DLC+.. │ │CRC+DEL│ACK+DEL │ │ │
└─────┴──────────┴───────┴──────┴───────┴────────┴──────┴─────┘
显性 仲裁 控制 数据 校验 应答 结束 间隔
2.2 各段作用
| 段 | 位数 | 作用 |
|---|---|---|
| SOF | 1 | 帧起始(显性),硬同步 |
| 仲裁段 | 12(标准)/32(扩展) | ID + RTR + IDE,仲裁优先级 |
| 控制段 | 6 | IDE/R0 + DLC(数据长度) |
| 数据段 | 0~64 | 数据(0~8 字节经典,0~64 FD) |
| CRC段 | 16 | CRC15 + CRC界定符(隐性) |
| ACK段 | 2 | ACK间隙 + ACK界定符 |
| EOF | 7 | 帧结束(7 个隐性) |
| IFS | 3 | 帧间隔(3 个隐性,下一帧前) |
2.3 总位数
- 标准数据帧(8字节):~111 位(含填充)
- 扩展数据帧(8字节):~135 位
- CAN FD(64字节):更长,但数据段高速
三、仲裁段(ID + RTR + IDE)
3.1 仲裁段组成
标准帧(11bit ID):
SOF(1) + ID[10:0](11) + RTR(1) + IDE(1) + r0(1) = 15 位
扩展帧(29bit ID):
SOF(1) + ID[28:18](11) + SRR(1) + IDE(1) + ID[17:0](18) + RTR(1) + r1(1) + r0(1) = 35 位
3.2 ID(标识符)
- 标准帧:11bit ID(0x000~0x7FF)
- 扩展帧:29bit ID(0x00000000~0x1FFFFFFF)
- ID 决定优先级(ID 越小优先级越高,见 \[05-CAN仲裁与优先级])
3.3 RTR(Remote Transmission Request)
- RTR=0:数据帧
- RTR=1:远程帧(请求数据,无数据段)
3.4 IDE(Identifier Extension)
- IDE=0:标准帧(11bit ID)
- IDE=1:扩展帧(29bit ID)
3.5 SRR(Substitute Remote Request)
- 扩展帧中替代 RTR 位置(固定隐性 1)
- 保持标准/扩展帧仲裁段长度对齐
四、控制段与数据段
4.1 控制段(6 位)
标准帧:
IDE(0) + r0 + DLC[3:0] = 6 位
扩展帧:
r1 + r0 + DLC[3:0] = 6 位
- r0/r1:保留位(显性 0)
- DLC:数据长度码(4bit,0~8)
4.2 DLC(数据长度码)
| DLC | 经典 CAN 字节数 | CAN FD 字节数 |
|---|---|---|
| 0 | 0 | 0 |
| 1 | 1 | 1 |
| ... | ... | ... |
| 8 | 8 | 8 |
| 9 | (无效) | 12 |
| 10 | (无效) | 16 |
| 11 | (无效) | 20 |
| 12 | (无效) | 24 |
| 13 | (无效) | 32 |
| 14 | (无效) | 48 |
| 15 | (无效) | 64 |
- 经典 CAN:0~8 字节(DLC > 8 视为 8)
- CAN FD:0~64 字节(DLC 9~15 映射 12/16/20/24/32/48/64)
4.3 数据段
- 经典:0~8 字节,MSB 先发
- CAN FD:0~64 字节
- 内容由应用层定(见 \[07-CAN高层协议])
五、CRC 段与 ACK 段
5.1 CRC 段
CRC序列(15bit) + CRC界定符(1位隐性)
- CRC15:多项式 0x4599,计算 SOF 到数据段
- 所有节点计算 CRC,和发送方比对
- 不符 → 发错误帧
- CRC 界定符:固定隐性 1
5.2 CAN FD CRC
- 数据 0~16 字节:CRC17(17bit)
- 数据 20~64 字节:CRC21(21bit)
- FD CRC 更长(数据多,可靠性要求高)
- FD 还有 Stuff Count(固定位填充计数)
5.3 ACK 段
ACK间隙(1位) + ACK界定符(1位隐性)
- ACK 间隙:发送方发隐性,所有正确接收的节点发显性(覆盖)
- 发送方读到显性 = 至少一个节点正确接收
- 发送方读到隐性 = 无节点正确接收 → ACK 错误
- ACK 界定符:固定隐性 1
5.4 ACK 机制意义
- 发送方知道帧被正确接收(显性 ACK)
- 没收到 ACK = 总线无其他节点 / 所有节点都错 → 重发
- 这是 CAN 可靠性的关键之一(对比 SPI 无 ACK)
ACK 是 CAN 和 SPI 的重要区别
SPI 无 ACK,从机死机主机不知道。CAN 有 ACK,发送方靠 ACK 位确认至少一个节点正确接收 。无 ACK 自动重发。这是 CAN 汽车级可靠的协议层保障。对照SPI技术系列 04 · SPI 协议与时序详解(CPOL/CPHA) 看,SPI 全双工无 ACK,CAN 半双工有 ACK。
六、EOF 与帧间隔
6.1 EOF(End of Frame)
- 7 个连续隐性位
- 标志帧结束
- 任何显性位(7 个隐性中)→ 格式错误
6.2 IFS(Intermission,帧间隔)
- 3 个连续隐性位
- 帧间隔离,下一帧前必须等待
- IFS 中显性 → 过载帧(请求延迟)
6.3 挂起传输(Suspend)
- 主动错误节点在 IFS 后可发下一帧
- 被动错误节点在 IFS 后还要等 8 个隐性(挂起传输),降低优先级
七、标准帧 vs 扩展帧
7.1 ID 长度
- 标准帧:11bit ID(0x000~0x7FF,2048 个 ID)
- 扩展帧:29bit ID(5.37 亿个 ID)
7.2 帧长度
- 标准帧(8字节):~111 位
- 扩展帧(8字节):~135 位(多 18bit ID + SRR + r1)
7.3 共存
- 标准帧和扩展帧可共存同一总线
- 仲裁时:标准帧 11bit ID 和扩展帧高 11bit 比较(IDE 位前)
- 设计建议:同一总线尽量用一种(避免仲裁歧义)
7.4 选择
- 标准帧:多数场景够(2048 ID)
- 扩展帧:J1939(商用车,29bit 编码)/ 大量节点
- 性能:扩展帧多 24 位开销,效率略低
八、CAN FD 帧扩展
8.1 FD 帧新增位
CAN FD 在控制段新增:
控制段(FD): IDE/r1 + r0 + BRS + ESI + DLC[3:0]
- BRS(Bit Rate Switch):1 = 数据段切高速
- ESI(Error State Indicator):1 = 节点处于被动错误状态
8.2 FD 帧结构
SOF + 仲裁段(1M) + 控制段(含BRS/ESI) ─BRS─> 数据段(5M) + CRC(高速) ─> ACK + EOF(1M)
- 仲裁段 1M(兼容)
- BRS 后切 5M/8M(数据段 + CRC)
- ACK 前回到 1M(全网同步 ACK)
8.3 FD 数据段
- 0~64 字节(DLC 9~15 映射)
- 数据段高速(5M/8M)
- CRC17/21(更长)
8.4 FD vs 经典帧识别
- 控制段 IDE 位后:经典帧是 r0(显性0),FD 帧是 EDL(隐性1)
- 控制器自动识别,软件透明
九、远程帧与错误帧
9.1 远程帧(Remote Frame)
SOF + 仲裁段(ID + RTR=1) + 控制段(DLC) + CRC + ACK + EOF
- RTR=1(数据帧 RTR=0)
- 无数据段
- 请求该 ID 的节点发数据
- DLC 应等于请求帧的数据长度
9.2 远程帧的应用
- 节点 A 想要 ID 0x123 的数据,发远程帧(ID=0x123, RTR=1)
- 节点 B(提供 0x123 数据)收到,响应数据帧(ID=0x123, RTR=0, 数据)
- 现代少用(多用应用层请求-响应)
9.3 错误帧(Error Frame)
错误标志(6位) + 错误定界符(8位隐性)
- 主动错误标志:6 个连续显性(主动错误节点发)
- 被动错误标志:6 个连续隐性(被动错误节点发,可能被覆盖)
- 错误定界符:8 个隐性
9.4 错误帧作用
- 检测到错误的节点发错误帧
- 破坏当前帧(让所有节点丢弃)
- 发送方重发(自动)
9.5 过载帧(Overload Frame)
过载标志(6位显性) + 过载定界符(7位隐性)
- 接收节点来不及处理,请求延迟下一帧
- 现代控制器 FIFO 深少用
十、关键问题 Q&A
Q1:数据帧从 SOF 到 EOF 每一位什么作用?
A:
- SOF(1):帧起始显性,硬同步
- 仲裁段(ID+RTR+IDE):优先级 + 帧类型
- 控制段(DLC):数据长度
- 数据段:内容
- CRC15+CRC界定符:校验
- ACK+ACK界定符:应答
- EOF(7隐性):结束
- IFS(3隐性):间隔
Q2:ACK 位怎么工作?
A :发送方在 ACK 间隙发隐性,所有正确接收的节点发显性覆盖 (线与)。发送方读到显性 = 至少一个节点正确接收。读到隐性 = 无节点正确接收(ACK 错误,重发)。这是 CAN 可靠性关键------发送方知道帧被接收。
Q3:标准帧和扩展帧能共存吗?
A :能。仲裁时标准帧 11bit ID 和扩展帧高 11bit 比较(IDE 位前),IDE 位决定后续。但建议同一总线用一种,避免仲裁歧义(标准帧 ID 和扩展帧高 11bit 相同时,标准帧优先级高)。
Q4:CAN FD 帧和经典帧怎么识别?
A :控制段 IDE 位后,经典帧是 r0(显性0),FD 帧是 EDL(隐性1)。控制器硬件自动识别,软件透明(配置 FD 模式后,收发自动区分)。
Q5:远程帧现在还用吗?
A :少用。早期 CAN 用远程帧请求数据(节点 A 发远程,节点 B 响应数据)。现代多用应用层请求-响应(如 UDS 0x22 读数据),更灵活。部分老设备(CANopen PDO 请求)还用。
Q6:CRC15 怎么算?
A:多项式 0x4599,计算范围 SOF 到数据段(含填充位)。发送方算 CRC 放 CRC 段,接收方重算比对。不符发错误帧。FD 帧 0~16 字节用 CRC17,20~64 字节用 CRC21(数据多需更强 CRC)。
十一、实战案例
案例 1:ACK 错误,帧重发
现象:某节点发送,示波器看 ACK 间隙是隐性(无应答),帧重发。
分析:总线无其他节点(单节点自测),或所有节点都错(没正确接收)。
解决:单节点自测开 Loopback 模式(自收自发 ACK);多节点检查接收节点是否正常。
案例 2:扩展帧 ID 解析错
现象:29bit ID 抓包,解析成标准帧 ID 错。
分析:抓包工具或代码没识别 IDE 位,把扩展帧当标准帧。
解决:解析时检查 IDE 位,IDE=1 用 29bit ID 解析。
案例 3:CRC 错,错误帧频发
现象:CAN 总线错误帧频发,通信失败。
分析:某节点位定时错(采样点不一致),采错数据,CRC 不符,发错误帧。
解决:统一所有节点位定时(采样点 87.5%),CRC 错消失。
案例 4:CAN FD 数据段被当经典帧解析
现象:CAN FD 帧,抓包工具把数据段按 1M 解析,数据乱。
分析:抓包工具不支持 FD,按经典帧速率解析数据段(实际 5M)。
解决:用支持 FD 的抓包工具(PCAN-View/CANalyzer),正确识别 BRS 切速。
案例 5:远程帧无响应
现象:发远程帧(ID=0x123, RTR=1),无数据帧响应。
分析:① 没有节点提供 0x123 数据;② 提供节点没配远程响应;③ DLC 不匹配。
解决:确认提供节点存在且配响应,或改用应用层请求(UDS 0x22)。
案例 6:EOF 格式错
现象:帧末偶发格式错误,重发。
分析:EOF 7 个隐性中混入显性(EMI 干扰),格式错。
解决:查 EMI 源,加共模扼流圈 + TVS,提高抗扰。
案例 7:DLC > 8 数据截断
现象:经典 CAN 发 DLC=12,接收只到 8 字节。
分析:经典 CAN DLC > 8 视为 8,只发 8 字节。
解决:要发 > 8 字节用 CAN FD,或用 ISO-TP 多帧分包(见 \[07-CAN高层协议])。
十二、本篇小结与速查
核心要点
- 四种帧:数据帧(主用)/远程帧(请求)/错误帧(报错)/过载帧(流控)
- 数据帧七段:SOF + 仲裁段 + 控制段 + 数据段 + CRC段 + ACK段 + EOF + IFS
- 仲裁段:ID(11/29bit) + RTR(0数据/1远程) + IDE(0标准/1扩展)
- 控制段:DLC(08经典/064 FD)
- CRC段:CRC15(经典)/CRC17-21(FD) + 界定符
- ACK段:发送方隐性,接收方显性覆盖(线与),发送方确认被接收
- EOF:7 隐性;IFS:3 隐性(间隔)
- 标准帧 11bit ID(2048),扩展帧 29bit ID(J1939 用)
- CAN FD:BRS 切速 + ESI 错误状态 + 数据段 64 字节 + CRC17/21
- 远程帧:RTR=1 无数据,少用;错误帧:6 显性+8 隐性,破坏当前帧
数据帧速查(标准帧 8 字节)
| 段 | 位数 | 内容 |
|---|---|---|
| SOF | 1 | 显性 |
| ID | 11 | 标识符(优先级) |
| RTR | 1 | 0=数据,1=远程 |
| IDE | 1 | 0=标准,1=扩展 |
| r0 | 1 | 保留 |
| DLC | 4 | 数据长度 |
| 数据 | 0~64 | 数据 |
| CRC | 15 | 校验 |
| CRC DEL | 1 | 隐性 |
| ACK | 1 | 显性(接收方) |
| ACK DEL | 1 | 隐性 |
| EOF | 7 | 隐性 |
| IFS | 3 | 隐性 |
CAN FD 新增位
| 位 | 含义 |
|---|---|
| EDL | FD 帧标识(替代经典 r0) |
| BRS | 切速(1=数据段高速) |
| ESI | 错误状态(1=被动错误) |
帧类型速查
| 帧 | RTR | IDE | 数据 | 用途 |
|---|---|---|---|---|
| 标准数据 | 0 | 0 | 0~8B | 主用 |
| 标准远程 | 1 | 0 | 无 | 请求 |
| 扩展数据 | 0 | 1 | 0~8B | J1939 |
| 扩展远程 | 1 | 1 | 无 | 请求 |
| FD 数据 | 0 | EDL=1 | 0~64B | 高速大块 |
延伸阅读
- \[03-CAN位定时与同步] ------ SOF 同步
- \[05-CAN仲裁与优先级] ------ 仲裁段深入
- \[06-CAN错误处理与错误帧] ------ 错误帧机制
- \[07-CAN高层协议] ------ 数据段语义
- \[08-CAN控制器寄存器与IP架构] ------ 帧寄存器
- \[04-I2C协议时序与地址] ------ 对比 I2C 帧
- \[04-SPI协议与时序详解-CPOL-CPHA] ------ 对比 SPI 帧
参考资料
- Bosch CAN Specification 2.0
- Bosch CAN FD Specification
- ISO 11898-1(数据链路层)
- CiA CAN Basics
CAN 技术系列 00 · 总目录 · 上一篇:\[03-CAN位定时与同步] · 下一篇:\[05-CAN仲裁与优先级]
✨ 感谢你的阅读 ✨
技术之路漫漫,分享是为了更好地交流。
如果本文的内容对你有启发,希望能得到你的支持:
👍 点赞 | ⭐ 收藏 | 👀 关注
如果你在调试过程中遇到了其他问题,
欢迎在 评论区 💬 留言,我们一起探讨。
关注我,一起交流底层开发的那些事儿!🚀