CAN 是什么
CAN(Controller Area Network)是汽车和工业控制里用得最多的串行总线。多主结构、差分信号、抗干扰强、最远 1km@50kbps。车上几十上百个 ECU(发动机、ABS、仪表、车门)挂在同两根线上,靠 ID 优先级仲裁。
CAN 的精髓是"多主 + 非破坏性仲裁":两个设备同时发,ID 小的赢,输的自动退出发,不损坏数据。
这篇讲 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);
过滤器配置
过滤器决定哪些 ID 能进接收 FIFO:
// 只接收 ID=0x123 的帧
CAN_FilterInitTypeDef fi;
fi.CAN_FilterNumber = 0;
fi.CAN_FilterMode = CAN_FilterMode_IdList; // 列表模式
fi.CAN_FilterScale = CAN_FilterScale_32bit;
fi.CAN_FilterIdHigh = 0x123 << 5;
fi.CAN_FilterIdLow = 0;
fi.CAN_FilterFIFOAssignment = CAN_FIFO0;
fi.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&fi);
发送与接收
发送一帧数据:
CanTxMsgTypeDef tx;
tx.StdId = 0x123;
tx.IDE = CAN_Id_Standard;
tx.RTR = CAN_RTR_Data;
tx.DLC = 8;
tx.Data[0] = 0x01;
tx.Data[1] = 0x02;
CAN_Transmit(CAN1, &tx);
// 接收中断里读 FIFO0
CanRxMsgTypeDef rx;
CAN_Receive(CAN1, CAN_FIFO0, &rx);
常见问题
// 1. 总线没接终端电阻 120Ω,通信乱码
// 2. 波特率两边不一致,发出去没人 ACK
// 3. CAN_H 和 CAN_L 接反
// 4. 过滤器没配对,收不到数据
// 5. 用 USB-CAN 分析仪抓包调试最快
CAN 调试神器是 USB-CAN 分析仪。插上电脑接总线,实时看每帧 ID 和数据,问题秒定位。
把 CAN 跑通,车规和产线设备都能玩。