Loading

CAN总线

CAN 总线是什么?一篇讲清差分信号、帧结构、仲裁和错误处理

做嵌入式通信时,UART、I2C、SPI 解决的是“设备怎么连”,而 CAN 总线 解决的是“很多节点怎么稳定地挂在一根总线上,而且还能优先级仲裁、错误重发、长期可靠运行”。

这也是为什么 CAN 在汽车电子、工业控制、BMS、电机驱动、智能设备网络里一直很强势。它不是最快的,也不是最简单的,但它非常均衡:

  • 抗干扰强
  • 多节点能力好
  • 仲裁机制清晰
  • 错误检测和恢复能力强

对于做 MCU、工业设备、照明电源外围控制、分布式模块网络的人来说,CAN 是非常值得吃透的一条总线。

这篇文章就围绕 5 个核心点展开:

  1. CAN 为什么抗干扰
  2. 一帧 CAN 数据长什么样
  3. 仲裁到底是怎么赢的
  4. 出错了为什么还能继续跑
  5. MCU 落地时要注意什么

1. CAN 总线到底是什么?

CAN(Controller Area Network)最早是为汽车电子设计的多节点串行通信总线。

它的核心特点不是“能发数据”——所有总线都能发数据——而是:

在多节点共享同一条总线的情况下,仍然能高可靠地完成通信。

一个典型的 CAN 网络大概长这样:

ECU A ----+
          |
ECU B ----+------ CAN_H / CAN_L 总线 ------ 120Ω
          |
ECU C ----+

几个关键词先记住:

  • 差分信号:CAN_H 与 CAN_L 配合传输
  • 多主通信:不只有一个主站,多个节点都可以发
  • 无损仲裁:谁优先级高谁先发,其他节点自动退出
  • 错误重发:发现错误就丢弃本帧并自动重试

这四点基本就是 CAN 的灵魂。


2. 为什么 CAN 抗干扰?——先看物理层

CAN 最重要的底层特性,就是 差分传输

总线上通常有两根线:

  • CAN_H
  • CAN_L

接收端真正关心的,不是哪根线绝对电压是多少,而是两者的电压差

2.1 隐性与显性

CAN 总线上的位分成两种状态:

  • 隐性(Recessive,逻辑 1)
  • 显性(Dominant,逻辑 0)

它们最直观的区别是:

状态 CAN_H CAN_L 特点
隐性 1 接近中间电平 接近中间电平 两线差值很小
显性 0 往上拉 往下拉 两线差值明显增大

所以你可以把它简单理解成:

  • 隐性:两线“几乎重合”
  • 显性:一根上扬,一根下压,形成明显差分

这就带来一个很大的好处:如果外部噪声同时加到两根线上,接收器看到的差分值仍然比较稳定。

这也是 CAN 能在汽车、电机、继电器、强干扰工业现场里长期稳定跑的关键原因之一。

2.2 为什么两端还要 120Ω?

标准 CAN 总线通常要求在总线两端各接一个 120Ω 终端电阻

作用是:

  • 抑制信号反射
  • 改善波形质量
  • 保证高速通信时边沿不乱飞

如果你总线拓扑不对,或者终端不合适,最常见的问题就是:

  • 波形失真
  • 某些波特率下偶发错误
  • 节点一多就不稳定

所以 CAN 的可靠,不只是协议设计得好,布线和匹配也非常关键


3. 一帧 CAN 数据长什么样?

一帧经典 CAN 数据帧可以概括成下面这些字段:

SOF -> 仲裁段(ID) -> 控制段 -> 数据段 -> CRC -> ACK -> EOF

可以整理成表:

字段 作用
SOF 帧开始
仲裁段 包含 ID,决定优先级
控制段 数据长度等控制信息
数据段 真正载荷,经典 CAN 最多 8 字节
CRC 校验正确性
ACK 其他节点确认收到
EOF 帧结束

3.1 SOF

SOF(Start Of Frame)表示一帧开始,通常是显性位

作用很简单:告诉全网“有人要开始发了”。

3.2 仲裁段

这是 CAN 最有辨识度的部分。

仲裁段里的 ID 不只是“地址”或者“消息编号”,它还决定了:

谁优先发。

3.3 数据段

经典 CAN 的数据段最多是 8 字节。这也是为什么很多设备会把消息拆得比较细。

如果你看到的是 CAN FD,那最大长度可以更大,但这篇先只讲经典 CAN 的核心逻辑。

3.4 CRC 与 ACK

CRC 用来校验整帧是否正确。

ACK 表示:

  • 有其他节点成功收到了这一帧
  • 并且愿意给出确认

这让 CAN 不只是“发了就完”,而是能知道“有没有真的被别人收到了”。


4. CAN 最厉害的地方:无损仲裁

很多总线在多节点同时发的时候会“打架”。

但 CAN 的设计很巧妙:

多个节点可以同时开始发,但优先级低的节点会自动退出,不会把高优先级帧破坏掉。

这就叫 无损仲裁

4.1 基本规则

CAN 仲裁的核心规则非常简单:

  • 显性 0 压过 隐性 1
  • ID 越小,优先级越高

因为仲裁是逐位进行的,所以:

  • 如果某个节点想发 1
  • 但总线上实际读到了 0
  • 它就知道自己输了
  • 于是立刻停止发送,转成接收模式

4.2 举个直观点的例子

假设三个节点同时发:

  • Node A:ID = 0x120
  • Node B:ID = 0x080
  • Node C:ID = 0x300

在逐位比较过程中,只要某一位上:

  • Node 自己发的是隐性 1
  • 总线上出现的是显性 0

它就会退出。

最终 ID 最小 的那个节点胜出。

这套机制有两个很大的好处:

  1. 高优先级消息一定更容易抢到总线
  2. 赢的那帧不会被碰坏

这就是为什么 CAN 特别适合:

  • 制动/转向/电机控制这类实时性更高的消息
  • 多个控制器共享同一条通信通道的场景

5. 为什么 CAN 可靠?——因为它会主动发现错误

CAN 的另一个强项,是错误检测非常全面

常见错误包括:

  • 位错误
  • 填充错误
  • CRC 错误
  • 格式错误
  • 应答错误

5.1 发现错误后会怎样?

如果某个节点发现当前帧不对,它不会“装作没看见”,而是会主动发出 Error Frame(错误帧)

这相当于告诉全网:

这帧作废,别信,重新来。

然后发送节点会自动重发。

5.2 这意味着什么?

这意味着 CAN 在现场干扰出现时,不是“默默错掉”,而是:

  • 主动检测
  • 主动打断错误帧
  • 自动触发重发

这对工业系统非常重要。

比如在电机驱动、BMS、工业模块通信里,比起偶尔丢一帧,更怕的是:

  • 收到了错误数据却没发现
  • 系统还继续按错数据执行

CAN 的错误机制,就是为了解决这类风险。


6. MCU 上怎么落地 CAN?

对嵌入式开发来说,理解协议只是第一步,真正能用起来还要落到硬件和驱动上。

典型结构:

MCU CAN 控制器 <-> CAN 收发器 <-> CAN_H / CAN_L 总线

6.1 MCU 里通常包含什么

很多 STM32、NXP、TI、GD、英飞凌等 MCU 会内置 CAN 控制器。

你真正还需要外接的是:

  • CAN 收发器(比如 TJA1050、SN65HVD 系列等)

因为 MCU 内部 CAN 外设主要负责:

  • 帧格式处理
  • ID 过滤
  • 仲裁时序
  • 错误检测

而真正把逻辑电平变成总线差分信号的是收发器。

6.2 过滤器很关键

CAN 常见的一个特点是:总线上所有节点都能看到广播的帧

所以 MCU 里一般要配:

  • 标准帧/扩展帧过滤
  • 接收 FIFO
  • 中断回调或轮询处理

否则消息一多,CPU 很容易被无关帧淹没。

6.3 波特率与总线长度要匹配

CAN 也不是你想跑多快就跑多快。

经验上:

  • 波特率越高,可允许的总线长度越短
  • 总线越长,波特率就要更保守

这和 RS485 很像,本质上都涉及传输线和边沿质量问题。


7. CAN 在实际产品里常用来干什么?

7.1 汽车电子

这是 CAN 最经典的应用场景。

比如:

  • 发动机 ECU
  • ABS
  • 仪表
  • 车身控制模块
  • 电池管理系统(BMS)
  • 电机控制器

这些模块都可以挂在同一条总线上交换状态和指令。

7.2 工业现场

在工业系统里,CAN 也很常见,尤其是:

  • 电机驱动器
  • 伺服控制器
  • PLC 扩展模块
  • 传感器网络
  • AGV / 机器人系统

因为它:

  • 节点多
  • 布线省
  • 抗干扰比普通 UART 强
  • 比较适合实时状态广播

7.3 电源 / 模块化设备网络

对于做电源或控制模块的人来说,CAN 适合用在:

  • 多模块并联状态同步
  • 主控与多个功率板通信
  • 分布式设备告警广播
  • 上位机批量读取运行数据

虽然照明电源里 RS485/Modbus 更常见,但在更复杂的多控制器系统里,CAN 也很有价值。


8. 调试 CAN 最常见的坑

下面这张表基本能覆盖大部分现场问题。

现象 常见原因 排查方向
完全没通信 收发器未工作、波特率不一致 先查硬件、时钟、位时序
偶发错误帧 终端电阻不对、布线反射 检查两端 120Ω 和拓扑
某节点收不到数据 过滤器配置错 检查 ID / 掩码设置
总线一直 busy 某节点异常持续发显性 看是否节点损坏或软件卡死
一发就仲裁失败 ID 优先级低 检查是否被高优先级帧压制
干扰大时掉线 接地/布线/屏蔽处理差 看供电、电缆、共地策略

排查顺序建议

建议按这个顺序查:

  1. 先查硬件层

    • 收发器型号对不对
    • CAN_H / CAN_L 有没有接反
    • 两端终端电阻有没有配
  2. 再查位时序

    • 波特率
    • 采样点
    • 时钟源配置
  3. 再查 ID 和过滤器

    • 帧格式是否匹配
    • 掩码是否把消息挡掉了
  4. 最后看错误计数器和错误状态

    • 是否进入 error passive / bus off

9. 一个最小接收思路示例

下面给一个偏思路型的示例,不依赖具体 HAL 版本:

typedef struct
{
    uint32_t id;
    uint8_t  dlc;
    uint8_t  data[8];
} can_msg_t;

void can_rx_callback(can_msg_t *msg)
{
    switch (msg->id)
    {
        case 0x101:
            // 电机转速反馈
            break;

        case 0x102:
            // 电流反馈
            break;

        case 0x201:
            // 告警状态
            break;

        default:
            break;
    }
}

工程里一般会再配合:

  • 中断接收
  • FIFO 缓冲
  • ID 分类分发
  • 超时监测
  • 错误状态机处理

如果消息量比较大,最好不要在中断里做太重的解析逻辑,而是:

  • 中断里只搬运
  • 主循环或任务里做协议层处理

10. 一张表快速记住 CAN 总线

项目 说明
物理层 差分双线:CAN_H / CAN_L
通信方式 多主广播
典型位值 显性 0、隐性 1
仲裁规则 显性压过隐性,ID 越小优先级越高
可靠性机制 CRC、ACK、错误帧、自动重发
数据长度 经典 CAN 最多 8 字节
常见场景 汽车 ECU、BMS、工业控制、电机驱动

11. 总结

CAN 总线真正厉害的地方,不只是“能通信”,而是它在多节点、强干扰、实时性要求高的环境里,依然能保持可靠。

你可以把它的核心价值概括成四句话:

  • 差分传输,抗干扰强
  • 逐位仲裁,多主也不乱
  • 错误检测完善,坏帧不硬扛
  • 非常适合广播式实时控制系统
posted @ 2026-06-02 16:58  cc_record  阅读(32)  评论(0)    收藏  举报