CAN 是什么

CAN(Controller Area Network)是汽车和工业控制里用得最多的串行总线。多主结构、差分信号、抗干扰强、最远 1km@50kbps。车上几十上百个 ECU(发动机、ABS、仪表、车门)挂在同两根线上,靠 ID 优先级仲裁。

CAN 的精髓是"多主 + 非破坏性仲裁":两个设备同时发,ID 小的赢,输的自动退出发,不损坏数据。
CAN 总线配图:左侧 ECU 芯片右侧示波器显示器,中间发光双总线波纹连接
双总线差分信号通信

这篇讲 CAN 总线编程的实战细节。

CAN 帧结构

标准 CAN 帧(CAN 2.0A)字段:

CAN 帧字段
  • SOF帧起始位。
  • ID11 位标识符,越小优先级越高。
  • RTR远程请求帧。
  • DLC数据长度 0~8 字节。
  • Data0~8 字节 payload。
  • CRC校验。

扩展帧 CAN 2.0B ID 是 29 位。

波特率计算

常见波特率:125k、250k、500k、1M。

// STM32 bxCAN 波特率公式:
// CAN_BAUD = APB1_CLK / ( (Prescaler) × (1 + BS1 + BS2) )
// 比如 APB1=36MHz,要 500kbps:
// Prescaler=6, BS1=11, BS2=4 -> 36M / (6 × 16) = 375k 不对
// Prescaler=4, BS1=11, BS2=4 -> 36M / (4 × 16) = 562.5k
// 常用配置:500k = 36M/(4×18) = BS1=14,BS2=3

STM32 bxCAN 初始化

初始化三步走:GPIO 复用、CAN 进入初始化、设波特率。

// 1. GPIO PA11/PA12 复用推挽
// 2. CAN1 init mode
CAN_InitTypeDef hi;
hi.CAN_TTCM = DISABLE;
hi.CAN_ABOM = ENABLE;       // 自动离线恢复
hi.CAN_AWUM = ENABLE;       // 自动唤醒
hi.CAN_NART = DISABLE;      // 允许重传
hi.CAN_BS1 = CAN_BS1_14tq;
hi.CAN_BS2 = CAN_BS2_3tq;
hi.CAN_Prescaler = 4;
CAN_Init(CAN1, &hi);