CAN 通信协议详解:从硬件接线、帧格式到仲裁机制、Bus-Off 与工程调试
在嵌入式开发中,CAN 通信广泛用于汽车电子、工业控制、电机驱动和设备之间的数据交换。

很多初学者第一次接触 CAN 时,会把它理解为"另一种串口":
配置波特率,发送几个字节,另一端接收即可。
但真正进入项目后,往往会遇到这些问题:
- 为什么 CAN_TX 和 CAN_RX 不能直接连接其他设备?
- 为什么总线两端需要 120Ω 电阻?
- 多个节点同时发送,为什么不会把数据撞坏?
- 为什么一块开发板发送 CAN 报文可能一直失败?
- 收到了 ACK,是否代表对方已经执行命令?
- 为什么设备运行一段时间后进入 Bus-Off?
- 为什么低负载时正常,高负载时却开始丢消息?
本文以经典 CAN 和高速双线 CAN 总线为主要对象,结合实际开发场景,详细介绍协议原理、硬件连接和工程注意事项,并补充 CAN FD 的主要区别。
一、CAN 是什么?
CAN 的全称是 Controller Area Network,即控制器局域网。
它是一种支持多个节点共享总线的通信机制,具有以下特点:
- 多主通信。
- 广播式报文传输。
- 基于标识符的优先级仲裁。
- 差分信号传输。
- 错误检测与故障隔离。
- 适合多个嵌入式设备之间交换控制和状态信息。
CAN 不要求存在一个固定的主机。只要满足总线访问条件,多个节点都可以主动发送报文。
典型网络如下:
text
控制器节点 ──────── CAN 总线 ──────── 电机节点
│
├────────── 传感器节点
│
└────────── 显示节点
需要注意:上图只表示节点关系。实际高速 CAN 接线通常采用线型主干,支线应尽量短。
1.1 CAN 是广播通信,不是固定地址通信
一个节点发送报文时,总线上的其他节点都能观察到这份报文。
接收节点再根据报文标识符和过滤配置,决定是否把它交给软件处理。
例如,应用协议约定:
text
ID 0x100:电机控制命令
ID 0x200:电机状态
ID 0x300:温度数据
这里的 ID 表示消息含义及其仲裁优先级,不天然等同于某个设备的地址。
上层协议可以把源地址、目的地址编码进 ID,但那属于应用协议的设计,而不是 CAN 的固定规定。
CAN 的广播和标识符机制可参考 Kvaser CAN 协议介绍。
二、CAN 控制器与 CAN 收发器有什么区别?
理解 CAN 硬件时,首先要区分两个模块:
text
MCU / 软件
↓
CAN 控制器
↓ CAN_TX / CAN_RX
CAN 收发器
↓ CAN_H / CAN_L
CAN 总线
2.1 CAN 控制器:处理协议
CAN 控制器负责:
- 组织发送帧。
- 接收和检查报文。
- 参与仲裁。
- 处理 CRC、ACK 和错误检测。
- 管理发送邮箱、接收 FIFO。
- 提供过滤器和错误状态。
很多 MCU 已经内置 CAN 控制器,因此不需要额外的外部控制器。
2.2 CAN 收发器:处理电气信号
CAN 收发器负责在两种信号之间转换:
text
控制器侧:TXD / RXD 逻辑电平
总线侧:CAN_H / CAN_L 差分信号
因此:
MCU 的 CAN_TX 和 CAN_RX 不能直接当作 CAN_H 和 CAN_L 使用。
还应检查收发器的:
- 供电电压。
- IO 电平兼容性。
- 工作模式。
- 待机或使能引脚。
- 共模范围。
- 总线保护能力。
- 是否支持目标 CAN FD 数据速率。
典型节点连接和物理层要求可参考 TI:CAN 物理层要求。
三、CAN_H、CAN_L、显性和隐性怎么理解?
3.1 差分传输
高速 CAN 主要根据 CAN_H 和 CAN_L 之间的电压差判断总线状态:
text
差分电压 = CAN_H 电压 − CAN_L 电压
差分传输有利于抑制同时耦合到两根线上的共模干扰,但这不代表总线对任何干扰和地电位差都免疫。
线缆、接地、隔离和保护设计仍然重要。
3.2 显性与隐性
CAN 中的逻辑位通常对应:
| 逻辑值 | 总线状态 |
|---|---|
| 0 | 显性,Dominant |
| 1 | 隐性,Recessive |
最关键的规则是:
显性可以覆盖隐性。
如果一个节点发送显性 0,另一个节点发送隐性 1,总线显示显性 0。
这一特性是 CAN 仲裁机制的基础。
3.3 电压值不能机械套用
常见 5V 高速 CAN 收发器在正常条件下,显性状态可能表现为 CAN_H 上升、CAN_L 下降;隐性时两线电位接近。
但实际电压会受器件、负载和工作条件影响。
工程中应以收发器数据手册中的:
- 输出范围。
- 接收阈值。
- 共模范围。
- 测试条件。
作为判断依据,而不是把某一组典型电压当作所有器件的绝对标准。
四、为什么需要两个 120Ω 终端电阻?
4.1 终端电阻用于抑制反射
当信号沿线缆传播时,如果线缆末端阻抗不匹配,会产生反射,影响波形和采样。
高速 CAN 通常采用特性阻抗约为 120Ω 的双绞线,并在主干两端分别进行终端匹配。
典型连接如下:
text
120Ω 120Ω
│ │
CAN_H ───────────────────────────────────────── CAN_H
CAN_L ───────────────────────────────────────── CAN_L
│ │
节点 A 节点 B
两个终端电阻都跨接在 CAN_H 与 CAN_L 之间。
4.2 不是每个节点都加终端电阻
正确理解是:
终端匹配取决于总线物理端点,不取决于节点数量。
若每个节点都增加一个 120Ω 电阻,总线等效负载会过重,可能影响正常驱动。
4.3 为什么断电测量通常约为 60Ω?
两个 120Ω 电阻并联:
text
R = 120Ω ∥ 120Ω = 60Ω
在整网断电、测量点正确且没有其他电路影响时,CAN_H 与 CAN_L 之间通常能测得约 60Ω。
可作初步判断:
| 测量现象 | 可能原因 |
|---|---|
| 约 60Ω | 两个 120Ω 终端可能均已接入 |
| 约 120Ω | 可能只接入一个终端 |
| 明显小于 60Ω | 可能存在多余终端或其他负载 |
| 很大或开路 | 可能缺少终端、线缆断开 |
不过,电阻值正常并不能证明整个网络一定正常。仍需检查接线、波形和工作状态。
4.4 支线为什么要短?
较长支线会引入传播延迟和反射。
因此,高速 CAN 一般建议:
- 使用线型主干。
- 支线尽量短。
- 避免随意采用长支线星形连接。
- 结合波特率、线缆和节点数量评估拓扑。
终端匹配及传播延迟设计可参考 TI 物理层应用报告。
五、经典 CAN 报文包含哪些字段?
经典 CAN 数据帧可以概括为:
text
SOF → 仲裁字段 → 控制字段 → 数据字段 → CRC → ACK → EOF
| 字段 | 主要作用 |
|---|---|
| SOF | 帧开始 |
| 仲裁字段 | 包含标识符及相关仲裁位 |
| 控制字段 | 包含数据长度等控制信息 |
| 数据字段 | 应用数据 |
| CRC | 检测传输错误 |
| ACK | 接收节点确认 |
| EOF | 帧结束 |
这是简化结构。具体字段组成还要区分标准帧和扩展帧。
5.1 标准帧
标准帧使用 11 位标识符:
text
0x000 ~ 0x7FF
5.2 扩展帧
扩展帧使用 29 位标识符:
text
0x00000000 ~ 0x1FFFFFFF
扩展帧提供更大的 ID 空间,但相应报文开销也更大。
5.3 经典 CAN 数据长度
经典 CAN 数据帧最多携带:
text
8 字节数据
DLC 是数据长度编码。对于普通经典 CAN 数据帧,通常使用 0~8 表示相应的数据长度。
5.4 数据帧与远程帧
经典 CAN 支持:
- 数据帧:携带实际数据。
- 远程帧:请求相应数据,自身不携带数据字段。
它们通过 RTR 等相关字段区分。
在许多现代应用中,通常采用周期发送和应用层命令/响应,而不是依赖远程帧机制。
六、CAN FD 与经典 CAN 有什么区别?
CAN FD 在经典 CAN 基础上扩展了数据长度和速率能力。
| 对比项 | 经典 CAN | CAN FD |
|---|---|---|
| 最大数据长度 | 8 字节 | 64 字节 |
| 数据阶段速率 | 与仲裁阶段相同 | 可通过 BRS 切换到更高速率 |
| 远程帧 | 支持 | 不支持 |
| ID 长度 | 11 位或 29 位 | 11 位或 29 位 |
CAN FD 数据长度不是任意 0~64 字节全部直接编码。常见 DLC 映射为:
text
0~8、12、16、20、24、32、48、64 字节
设计 CAN FD 网络时,需要同时检查:
- 控制器是否支持 CAN FD。
- 收发器是否满足目标数据速率。
- 总线拓扑是否适合更高速的数据阶段。
- 网络中的其他节点是否兼容 FD 报文。
不要默认经典 CAN 节点能正常容忍 CAN FD 报文。
七、多个节点同时发送,CAN 如何仲裁?
CAN 使用非破坏性逐位仲裁。
7.1 发送节点会监测总线
节点发送时,同时观察总线状态。
在仲裁字段中,如果节点:
text
发送隐性 1
却读到显性 0
就说明有其他节点在这一位发送了显性 0。
该节点输掉仲裁,停止竞争,转为接收,让获胜节点继续发送。
7.2 仲裁示例
假设两个节点同时发送标准数据帧:
text
A:ID = 0x100
B:ID = 0x180
对应 11 位标识符:
text
A:0 0 1 0 0 0 0 0 0 0 0
B:0 0 1 1 0 0 0 0 0 0 0
前三位相同,第 4 位:
text
A 发送 0
B 发送 1
总线显示 0
因此:
text
A 获胜,继续发送
B 退出仲裁,等待下一次机会
7.3 为什么叫非破坏性?
因为获胜节点的报文不会因仲裁竞争而被破坏。
输掉仲裁也不属于传输错误,不能把它与 CRC 错误或位错误混为一谈。
7.4 "ID 越小优先级越高"有前提
对于同格式的数据帧,比较 ID 时,数值越小,仲裁优先级越高。
但比较不同帧格式或数据帧与远程帧时,还要考虑 SRR、IDE、RTR 等位。
另外:
高优先级报文不能打断一份已经开始正常发送的报文。
它只影响下一次总线竞争。
CAN 的非破坏性仲裁机制可参考 Kvaser CAN 协议介绍。
八、ACK 到底表示什么?
ACK 是 CAN 开发中最容易误解的机制之一。
8.1 ACK 的产生过程
在 ACK 槽中:
text
发送节点:发送隐性
正确接收报文的正常接收节点:发送显性
发送端观察到显性,就知道至少有接收节点正确接收了这份报文。
8.2 ACK 不等于目标设备执行成功
ACK 只能说明协议层接收情况,不能证明:
- 指定目标设备一定收到。
- 软件已经从 FIFO 取出报文。
- 对应任务已完成处理。
- 控制命令已经执行。
- 执行结果正确。
总线上的其他正常节点也可能提供 ACK。
而且,验收过滤器没有把这条报文交给应用程序,并不意味着节点一定不会 ACK。
8.3 关键命令需要业务响应
例如:
text
控制器发送:启动电机,序号 15
电机返回:序号 15,已启动
这种业务应答才用于确认目标设备的处理结果。
因此应区分:
text
CAN ACK:报文接收确认
业务响应:命令执行确认
8.4 为什么只有一块板可能发不成功?
正常外部总线通信需要其他接收节点提供 ACK。
如果总线上只有一个发送节点,它可能持续发生 ACK 错误。
另外:
- 监听模式分析仪通常不会 ACK。
- 正常模式分析仪可能提供 ACK。
- 内部回环模式属于另一类测试。
- 自接收并不自动等同于外部 ACK。
正常应答过程可参考 TI CAN 物理层报告。
九、CAN 如何检测错误?
CAN 提供多种错误检测机制。
| 错误类型 | 简要含义 |
|---|---|
| 位错误 | 发送位与监测位不一致,协议规定的例外除外 |
| 填充错误 | 位填充规则被破坏 |
| CRC 错误 | 接收计算结果与报文 CRC 不一致 |
| 格式错误 | 固定格式字段出现不符合规则的位 |
| ACK 错误 | 发送端未获得正确应答 |
9.1 位填充是什么?
经典 CAN 在规定的帧区域中,会在连续 5 个相同位后插入一个相反位。
例如:
text
原始位序列:0 0 0 0 0
插入填充位:0 0 0 0 0 1
接收端按规则去除填充位。
它有助于维持同步,同时使实际报文长度与数据内容相关。
因此,计算总线负载时不能只统计有效数据字节。
9.2 检测到错误后会怎样?
节点检测到错误后,会根据当前错误状态发送相应错误标志,使当前报文被判为无效。
发送控制器通常具有自动重传机制,但具体行为受控制器配置影响,例如是否关闭自动重传、是否采用单次发送模式。
应用程序应区分:
text
报文已进入发送邮箱
报文已开始发送
报文已成功完成发送
它们不是同一个状态。
十、Error Active、Error Passive 和 Bus-Off
CAN 通过错误计数和状态转换,限制异常节点对总线的影响。
两个重要计数器是:
text
TEC:发送错误计数器
REC:接收错误计数器
10.1 Error Active:错误主动状态
通常当:
text
TEC < 128
REC < 128
节点处于错误主动状态,可以正常通信,并在检测错误时发送主动错误标志。
10.2 Error Passive:错误被动状态
当任一错误计数达到 128:
text
TEC ≥ 128
或者
REC ≥ 128
节点进入错误被动状态。
它仍可能参与通信,但错误标志和发送约束发生变化,以降低对网络的影响。
10.3 Bus-Off:总线关闭状态
当:
text
TEC > 255
节点进入 Bus-Off,停止正常参与总线通信。
需要强调:
Bus-Off 由发送错误计数 TEC 触发,REC 超过阈值不会直接触发 Bus-Off。
10.4 不是每个错误都简单"计数加 1"
TEC 和 REC 的增减有具体规则,并存在例外。
一个重要例子:
仅因为缺少 ACK 而不断重发,并不意味着节点一定持续增加 TEC,最终进入 Bus-Off。 错误被动状态下的特定 ACK 错误条件存在计数例外。
因此,诊断时不能简单推断:
text
没有 ACK → 一直加错误计数 → 必然 Bus-Off
应结合实际控制器状态和协议规则分析。
10.5 Bus-Off 不能只靠反复复位
推荐流程:
text
检测 Bus-Off
↓
保存错误状态和诊断信息
↓
按业务需要进入安全状态
↓
检查接线、位时序和波形
↓
满足协议及控制器恢复条件
↓
恢复通信并统计重复发生次数
是否自动恢复、如何触发恢复,要参考具体控制器手册。
十一、波特率与位时序怎么配置?
11.1 波特率的基本关系
常见计算关系为:
text
bitrate = CAN 内核时钟 /(分频值 × 每位时间量子数)
例如:
text
CAN 时钟:48 MHz
分频:6
每位:16 个时间量子
则:
text
48 MHz /(6 × 16)= 500 kbit/s
但寄存器可能采用"实际值减 1"等编码方式,不能直接把公式中的数字照搬进寄存器。
11.2 采样点是什么?
CAN 控制器会在每个位时间的某个位置读取总线状态,这个位置就是采样点。
采样点过早或配置不合适,可能使控制器在信号尚未稳定时采样。
配置时需要考虑:
- 总线长度。
- 收发器传播延迟。
- 节点时钟误差。
- 支线和拓扑。
- 目标位速率。
11.3 SJW 是什么?
SJW 是同步跳转宽度,用于限制重同步时允许进行的时间调整。
它不是越大越好,应与位时序和控制器要求匹配。
11.4 波特率相同也可能通信异常
两个节点都标注为 500 kbit/s,不代表配置一定正确。
还应核对:
- 实际 CAN 时钟。
- 分频参数。
- 各时间段配置。
- 采样点。
- SJW。
- 振荡器误差。
- CAN FD 的数据阶段参数。
十二、接收过滤器怎么理解?
验收过滤器决定哪些报文进入控制器的接收缓存。
常见方式包括:
- 精确匹配。
- 掩码匹配。
- 范围匹配。
具体支持方式因控制器而异。
例如:
text
只接收 ID 0x200
或者
接收 0x200~0x20F 这一组消息
调试过滤器时,应注意:
- 标准帧与扩展帧配置是否正确。
- ID 是否需要移位后写入寄存器。
- 掩码位的含义是否理解正确。
- 数据帧与远程帧是否被区分。
- 报文被路由到哪个 FIFO。
- FIFO 中断是否已启用。
初次联调时,可先采用较宽松的过滤配置,确认通信正常后,再逐步收紧规则。
十三、CAN 中断与 FreeRTOS 如何配合?
推荐的接收结构是:
text
CAN 接收中断
↓
读取报文并快速入队
↓
退出中断
↓
协议解析任务处理数据
↓
业务任务执行命令
中断中应尽量避免:
- 阻塞等待。
- 长时间打印。
- 复杂协议解析。
- 大量计算。
- 等待其他外设完成操作。
逻辑示例:
c
/* 伪代码:具体硬件 API 取决于 MCU 和驱动库 */
void CAN_RxIRQHandler(void)
{
CanMessage message;
BaseType_t higherPriorityTaskWoken = pdFALSE;
if (CAN_ReadMessage(&message))
{
if (xQueueSendFromISR(
canRxQueue,
&message,
&higherPriorityTaskWoken) != pdPASS)
{
/* 统计接收队列溢出 */
}
}
/* 按硬件要求清除中断标志 */
portYIELD_FROM_ISR(higherPriorityTaskWoken);
}
任务中处理:
c
void CanProtocolTask(void *argument)
{
CanMessage message;
for (;;)
{
if (xQueueReceive(
canRxQueue,
&message,
portMAX_DELAY) == pdPASS)
{
ParseCanMessage(&message);
}
}
}
实际项目还需要:
- 保证中断优先级满足 FreeRTOS 的 API 调用约束。
- 根据驱动要求处理 FIFO 中剩余报文。
- 监测硬件 FIFO 和软件队列溢出。
- 确保队列元素包含完整数据,而不是生命周期不明的临时指针。
十四、应用层还需要约定什么?
CAN 解决报文传输,但不自动定义数据含义。
例如,两字节温度:
text
Byte0 = 0x01
Byte1 = 0x2C
接收端必须知道:
- 采用大端还是小端。
- 有符号还是无符号。
- 单位是 ℃ 还是 0.1℃。
- 是否有偏移。
- 哪个值表示无效数据。
如果约定大端、单位为 0.1℃:
c
uint16_t raw =
((uint16_t)data[0] << 8) |
(uint16_t)data[1];
float temperature = raw * 0.1f;
得到:
text
0x012C = 300
温度 = 30.0℃
如果另一个节点采用小端解析,结果就会完全不同。
建议每条消息都定义:
| 项目 | 示例 |
|---|---|
| ID | 0x300 |
| 帧格式 | 标准数据帧 |
| 数据长度 | 8 字节 |
| 发送周期 | 100 ms |
| 字节序 | 大端 |
| 信号单位 | 0.1℃ |
| 超时时间 | 500 ms |
| 异常值 | 按业务约定 |
| 序号/校验 | 根据可靠性需求设计 |
对于关键控制命令,还应考虑业务应答、超时、重试和重复执行问题。
十五、总线负载为什么不能只算数据字节?
经典 CAN 报文除有效数据外,还包含:
- 帧头。
- 仲裁字段。
- 控制字段。
- CRC。
- ACK。
- EOF。
- 位填充。
- 帧间隔。
因此:
text
总线占用时间 ≠ 数据字节数 × 8 / 波特率
高负载时,可能出现:
- 低优先级报文等待时间变长。
- 发送队列积压。
- 接收 FIFO 溢出。
- 业务超时。
- 错误重传进一步增加负载。
设计时应评估:
text
正常周期流量
+ 突发命令流量
+ 诊断或升级流量
+ 错误重传余量
不能只看平均负载,还要关注短时间内的突发流量。
十六、CAN 通信异常的排查顺序
第一步:查供电和模式
- 收发器供电是否正常?
- IO 电平是否兼容?
- 待机或使能脚是否正确?
- 控制器是否处于正常模式?
- 是否误启用监听或回环?
第二步:查接线和终端
- CAN_H 与 CAN_L 是否接反?
- 线缆是否断开?
- 两端终端是否正确?
- 是否存在额外终端?
- 地参考或隔离方案是否合理?
第三步:查位时序
- 实际时钟是否正确?
- 波特率是否一致?
- 采样点与 SJW 是否合适?
- CAN FD 的 BRS 和数据阶段参数是否匹配?
第四步:查协议状态
- 是否获得 ACK?
- 是否丢失仲裁?
- TEC、REC 如何变化?
- 是否有错误帧?
- 是否进入 Error Passive 或 Bus-Off?
第五步:查软件和业务
- 过滤器是否误过滤?
- FIFO 是否溢出?
- 接收队列是否已满?
- 任务是否及时处理?
- ID、字节序、单位是否一致?
- 是否存在应用层超时或重复执行?
可以记成:
先硬件,后时序;先协议,后业务。
十七、面试常见问题速答
1. CAN 为什么需要收发器?
控制器侧使用逻辑电平,CAN 总线使用差分信号。收发器负责两者之间的电气转换。
2. 为什么两个 120Ω 电阻测起来约为 60Ω?
因为两个终端电阻并联。测量应在断电且没有其他电路影响时进行。
3. ID 越小,优先级一定越高吗?
同格式数据帧竞争时可以这样理解。跨格式或涉及远程帧时,还要结合其他仲裁位比较。
4. 输掉仲裁属于错误吗?
不属于。输掉仲裁的节点停止竞争,获胜节点继续发送。
5. 有 ACK 是否说明命令执行成功?
不能。ACK 是协议层接收确认,执行成功需要应用层响应。
6. REC 达到 256 会进入 Bus-Off 吗?
不会直接触发。Bus-Off 由 TEC 超过 255 触发。
7. CAN 报文 CRC 正确,业务数据就一定可靠吗?
不一定。还可能存在旧数据、丢消息、错误的消息来源、软件处理错误或字段解析不一致。
8. 经典 CAN 能直接发送 20 字节吗?
不能在单个经典 CAN 数据帧中发送,需要上层分包;支持 CAN FD 的网络可以选择合适的 FD 数据长度。
十八、总结
稳定的 CAN 通信需要同时满足三个层面的要求:
text
物理层:供电、收发器、接线、终端、波形
协议层:帧格式、仲裁、ACK、错误处理、位时序
应用层:字段定义、缓存、超时、响应、重复处理
其中最值得记住的几个结论是:
- CAN 控制器处理协议,CAN 收发器处理电气信号。
- 高速 CAN 主干两端通常各放一个 120Ω 终端电阻。
- 显性 0 覆盖隐性 1,是逐位仲裁的基础。
- 输掉仲裁不会破坏获胜报文,也不属于通信错误。
- ACK 不等于目标设备已经执行命令。
- Bus-Off 应查明根因,不能只靠反复复位。
- CAN 数据含义、字节序和业务可靠性需要应用层约定。
最后用一句话概括:
接线正确是基础,位时序匹配是前提,仲裁决定发送先后,应用协议决定设备能否真正协同工作。
参考资料
实际开发时,还应结合目标 MCU 的参考手册、CAN 收发器数据手册及所用 CAN/CAN FD 协议规范核对具体参数。