跳转至

最近修改日期:2026-01-29

预计阅读时间:8-10 分钟

参与者:Jackrainman

CAN 总线通信原理与软件驱动架构

0. 引言

如果你从来没有了解过这个概念,这个视频能帮助你更好地了解本文档:https://www.bilibili.com/video/BV14k4y187e6/

1. 概述

CAN (Controller Area Network) 是一种广泛应用于汽车与工业控制的串行通信协议。在机器人开发中,CAN 总线因其走线简单(节省线束)和极高的抗干扰能力,成为电控系统(ECU)之间通信的首选方案。

节省线束的优势: CAN 总线最开始是为了减少铜线的长度而开发的。如果不使用 CAN 总线,每个 ECU 之间都需要单独的连线,这将使用数倍长的铜线,而且线束会非常杂乱。通过 CAN 总线,多个 ECU 只需要挂载到总线上就可以组成局域网通讯,大大减少了线束的长度和复杂度。

通信系统由三个层级构成:

  • 物理层(硬件):包括单片机、CAN 收发器与双绞线。
  • 数据链路层(控制器):STM32 内部集成的 bx CAN 或 FDCAN 外设。
  • 应用层(软件):基于 can_list.c 驱动的协议解析与业务处理。

1.1 核心术语表

术语 全称 / 含义 说明
CAN Controller Area Network 控制器局域网络,一种多主串行通信协议
ECU Electronic Control Unit 电子控制单元,可以看作是一台超小型的计算机,它内部集成了供电系统、单片机驱动系统,是汽车里面最小的控制模块
bx CAN Basic Extended CAN STM32 传统的 CAN 外设模块,遵循 CAN 2.0B 协议
FDCAN Flexible Data-rate CAN STM32 高性能 CAN 外设,支持更高数据速率和更长数据帧
CAN_H / CAN_L CAN High / Low 差分信号线对,用于传输数据
显性电平 Dominant Level 逻辑 0,CAN_H=3.5V,CAN_L=1.5V,电压差约 2V
隐性电平 Recessive Level 逻辑 1,CAN_H=CAN_L≈2.5V,电压差接近 0V
ID Identifier 报文标识符,用于标识消息内容和优先级
标准帧 Standard Frame 11 位 ID,最大数据长度 8 字节
扩展帧 Extended Frame 29 位 ID,最大数据长度 8 字节 (bx CAN) 或 64 字节 (FDCAN)
DLC Data Length Code 数据长度代码,指示数据字段的字节数
FIFO First In First Out 先进先出队列,硬件接收缓冲区
ISR Interrupt Service Routine 中断服务程序,硬件事件触发时执行的紧急代码
HAL Hardware Abstraction Layer 硬件抽象层库,提供统一硬件操作接口
RTOS Real-Time Operating System 实时操作系统,如 FreeRTOS
哈希表 Hash Table 一种通过哈希函数快速查找的数据结构
掩码 Mask 位掩码,用于过滤 ID 中不关心的位
回调函数 Callback Function 预先定义的函数,在特定事件发生时由系统自动调用

2. CAN 协议基础

2.1 报文帧类型

CAN 协议定义了四种帧类型:

  1. 数据帧:携带实际数据,包含以下部分:

    • 仲裁场:ID + RTR 位
    • 控制场:IDE 位 + 保留位 + DLC
    • 数据场:0-8/64 字节数据
    • CRC 场:循环冗余校验码
    • 应答场:ACK 位 + EOF

    详细说明: - 起始位:必须是逻辑 0,标识帧的开始 - 识别码(ID):根据这 11 位识别码就能知道这一帧信息是发给哪一个设备的,每一个设备都有属于自己的 11 位识别码。ID 不仅是设备的唯一识别码,而且还代表了优先级。 - IDE 位:用于区分标准格式和扩展格式。在标准格式当中有 11 位识别码,这一位是逻辑 0;而在扩展格式中,它的识别码有 29 位,这一位是逻辑 1。 - 保留位:逻辑 0,用于未来扩展 - DLC 位(数据长度代码):4 位,二进制编码范围是 0~8。如果 DLC=1,则后面的数据位就只有 1 个字节(8 位);如果 DLC=8,则后面的数据位就是 8 个字节(64 位)。 - CRC 码:16 位循环冗余校验码,用于确保数据的准确性。首先是 15 位 CRC 校验码,设备接收端会根据数据计算出它的 CRC 位,如果计算出来的和接收到的 CRC 不一致,说明数据存在问题,就会重新发送一遍数据帧。 - CRC 界定符:逻辑 1,目的是为了把后面的信息隔开 - ACK 应答位:第一位是 ACK 确认槽,发送端发送的是逻辑 1,而接收端回复的是逻辑 0 来表示应答。第二位是 ACK 界定符,一定是逻辑 1,作用是把后面的数据隔开 - 7 位结束位(EOF):这 7 位都是逻辑 1,表示数据帧传输结束

  2. 远程帧:请求特定 ID 的数据,不含数据场

  3. 错误帧:节点检测到错误时发送
  4. 过载帧:请求延迟下一帧传输

目前代码中只有数据帧与远程帧,并没有错误帧和过载帧。远程帧简单来说,是用来请求数据的。

2.2 仲裁机制

CAN 采用非破坏性位仲裁: - 所有节点同时发送时,逐位比较 ID - 发送显性位(0)的节点覆盖隐性位(1) - ID 值越小优先级越高(显性位多) - 优先级高的节点继续发送,其他节点转为接收模式

仲裁详细过程: 当总线上同时有多个设备发送信息时,哪一个设备发送的信息优先呢?这就得看 11 位的识别码了,它不仅是设备的唯一识别码,而且还代表了优先级。比如两帧数据是同时发出的,那应该以哪一个为准呢?当总线上同时出现逻辑零和逻辑一的时候,总线会被视为逻辑 0。此后 ID 值较大的数据帧就不会再发送了,而 ID 值较小的数据帧会继续发送,从而实现非破坏性的仲裁。

2.3 错误检测与处理

CAN 具有多层错误检测机制: 1. 位错误:发送位与读取位不一致 2. 填充错误:违反位填充规则(连续 5 个相同位后必须插入相反位) 3. CRC 错误:循环冗余校验失败 4. 格式错误:固定格式位出现非法值 5. 应答错误:发送端未收到应答

每个 CAN 节点维护错误计数器,根据错误严重程度进入不同状态: - 主动错误:正常通信状态 - 被动错误:限制错误帧发送 - 总线关闭:停止发送和接收

3. 物理层:差分信号与抗干扰原理

CAN 收发器负责将单片机的逻辑信号转换为总线上的差分信号。

3.1 差分信号定义

CAN 总线使用两根信号线:CAN_H (High) 和 CAN_L (Low)。接收端通过比较两根线的电压差来判断逻辑状态。

  • 显性电平 (Dominant, 逻辑 0)
    • CAN_H 拉高 (约 3.5V),CAN_L 拉低 (约 1.5V)
    • 电压差约为 2V
    • 特性:总线上只要有一个节点发送"显性",总线即呈现"显性"状态(线与机制)
  • 隐性电平 (Recessive, 逻辑 1)
    • CAN_H 和 CAN_L 均维持在中间电压 (约 2.5V)
    • 电压差近乎 0V
    • 特性:只有所有节点都处于"隐性"时,总线才呈现"隐性"状态

3.2 位时序与同步

CAN 位时间由四个段组成: 1. 同步段 (Sync_Seg):用于同步各节点时钟 2. 传播段 (Prop_Seg):补偿物理延迟 3. 相位缓冲段 1 (Phase_Seg1):补偿上升沿误差 4. 相位缓冲段 2 (Phase_Seg2):补偿下降沿误差

再同步:当边沿出现在同步段之外时,通过延长或缩短相位缓冲段来调整采样点位置。

3.3 抗干扰机制

CAN 总线通过双绞线传输差分信号,能有效抵御电机启动等高噪环境下的共模干扰。

案例分析: 假设主控制器 (Master) 向电机 (Device) 发送逻辑"0"。

  1. 正常发送:Master 输出 CAN_H=3.5V,CAN_L=1.5V,差值 ΔV = 2.0V
  2. 干扰引入:外界产生 +1.0V 的共模干扰(如电压尖峰)。由于双绞线紧密缠绕,干扰同时作用于两线:

    • CAN_H 变为 4.5V (3.5 + 1.0)
    • CAN_L 变为 2.5V (1.5 + 1.0)
  3. 差分解码:接收端仅计算差值:ΔV = 4.5V - 2.5V = 2.0V

  4. 结论:尽管绝对电压发生偏移,但差值保持不变,数据仍被正确识别为"0"

4. STM32 CAN 外设

4.1 bxCAN (Basic Extended CAN),目前使用较多

  • 支持标准:CAN 2.0A 和 2.0B
  • 数据长度:最多 8 字节
  • ID 长度:11 位标准帧,29 位扩展帧

4.2 FDCAN (Flexible Data-rate CAN)

  • 支持标准:CAN FD (Flexible Data-rate)
  • 数据长度:最多 64 字节
  • ID 长度:11 位标准帧,29 位扩展帧

4.3 硬件过滤器

STM32 CAN 外设提供硬件过滤器,可在不占用 CPU 的情况下过滤不需要的报文: - 列表模式:只接收 ID 完全匹配的报文 - 掩码模式:接收 ID 在掩码范围内匹配的报文 - FIFO 分配:不同过滤器可指向不同 FIFO

4.4 硬件架构与数据流向

bxCAN 外设的内部逻辑组成主要分为发送、接收和过滤三个部分:

CAN 硬件架构

如图所示:

  • 发送端:CPU 将待发送的报文写入 发送邮箱(Mailbox 0/1/2)。bxCAN 拥有 3 个发送邮箱,发送优先级由硬件根据标识符(ID)或写入顺序决定。硬件会自动进行仲裁:当多个邮箱同时有报文待发送时,硬件会优先发送 ID 值最小的报文(即优先级最高的报文)。如果同时出现逻辑 0 和逻辑 1,总线会被视为逻辑 0,ID 值较大的报文会停止发送。
  • 接收端:总线上的报文通过 GPIO 和控制器进入 接收过滤器
  • 过滤器(Filter):bx CAN 共有 14 个过滤器(0-13)。过滤器决定哪些报文是本节点需要的。只有匹配成功的报文才会进入 接收 FIFO
  • 接收 FIFO:有两个独立的 FIFO(FIFO 0 和 FIFO 1),每个 FIFO 包含 3 个级联的邮箱。这种结构可以缓存最多 6 帧报文,防止 CPU 处理不及时导致丢包。

4.5 测试模式

在开发调试阶段,bxCAN 提供了三种特殊的测试模式:

CAN 测试模式

如图所示:

  • 静默模式 (Silent Mode):只能接收,不能发送(TX 引脚内部断开,只能监测总线数据)。用于总线监听或波特率自适应。
  • 环回模式 (Loopback Mode):发送的报文不经过总线,直接反馈到接收端。用于在没有外部节点的情况下进行自测。
  • 环回静默模式 (Silent Loopback):结合了前两者的特点,完全不影响总线,且能实现内部自测,常用于"热自检"。

4.6 工作模式与状态转换

bx CAN 的状态机由三个主要状态组成,通过控制寄存器的位(如 INRQSLEEP)进行切换:

CAN 工作模式与状态转换

如图所示:

  • 初始化模式 (Initialization):配置波特率、过滤器等参数时必须进入此模式,此时禁止收发报文。
  • 正常模式 (Normal):配置完成后进入,此时外设可以与总线进行正常的数据交换。
  • 睡眠模式 (Sleep):低功耗状态,时钟停止。
  • 唤醒机制 (AWUM)

    - 自动唤醒 (AWUM=1):一旦检测到总线活动,硬件自动清零 SLEEP 位并唤醒。

    - 手动唤醒 (AWUM=0):需要软件干预清零 SLEEP 位。

5. 软件驱动架构 (can_list)

本战队使用的 can_list 驱动采用分层设计,旨在解决高频中断下的实时性问题及多设备 ID 的快速检索。

5.1 第一阶段:中断接收 (ISR)

此阶段为信号入口,位于 can_list.c 的中断服务函数中。

  • 中断源区分:兼容 FDCAN (H7/G4 系列) 和 bx CAN (F1/F4 系列) 的中断接口。
  • 处理模式
    • RTOS 模式 (推荐):为了保证系统实时性,ISR (Interrupt Service Routine) 不直接解析数据。它构建一个轻量级通知,通过 FreeRTOS 队列 (xQueueSendFromISR) 发送至后台任务,随即退出中断。
    • 非 RTOS 模式:在中断内直接调用处理函数,适用于简单应用,但可能阻塞其他高优先级任务。

5.2 第二阶段:数据分发 (核心逻辑)

此阶段由后台任务 (can_list_polling_task) 执行,负责将原始数据映射到具体设备。

  • 读取寄存器:通过 HAL 库函数 (HAL_CAN_GetRxMessage) 从硬件 FIFO 读取解码后的报文。
  • 哈希查表 (Hash Lookup)
    • 利用 ID % table_length 计算哈希桶索引,快速定位链表头。
    • 此算法将遍历搜索的时间复杂度大幅降低,适合挂载大量电机的场景。
  • 掩码匹配 (Masking)
    • 遍历链表时,不仅对比 ID,还引入了 掩码 (Mask) 机制。
    • 应用场景:若掩码设为 0xFF,则 ID 0x123402010xAAAA0201 均匹配注册 ID 0x01。这允许驱动统一处理某一类设备的反馈(如提取低 8 位作为子 ID)。

5.3 第三阶段:业务回调 (Callback)

一旦匹配成功,驱动将执行最终的业务逻辑。

  • 数据标准化:将不同硬件(bx CAN/FDCAN)的数据格式统一封装为 can_rx_header_t 结构体。
  • 执行回调
    • 调用用户注册的函数指针:node->callback(node->can_data, ...)
    • 面向对象设计can_data 指针通常指向具体的电机对象。用户在回调中直接操作该指针,无需通过全局变量查找电机,实现了代码的高内聚低耦合。

6. 总结

CAN 总线是机器人电控系统的核心通信技术,掌握其原理和实际应用对电控工程师至关重要。本模块提供的 can_list 驱动通过哈希表和掩码机制,实现了高效的消息接收,特别适合多电机、多传感器的机器人系统。结合 RTOS 使用可进一步提升系统实时性和稳定性。

评论