从零到一:CAN通信实战入门与STM32配置详解

发布时间:2026/7/15 4:55:26

从零到一:CAN通信实战入门与STM32配置详解 1. CAN通信基础与STM32实战准备第一次接触CAN总线是在大四的机器人比赛中当时需要控制四个大疆的3508电机。看着队友用STM32通过两根线就能同时指挥这么多电机感觉特别神奇。后来才知道这就是CAN总线的威力。CANController Area Network是一种多主机工作的串行通信协议最早由德国博世公司开发用于汽车电子。它的核心优势在于多设备协同一条总线上可以挂载多个设备每个设备都能主动发送数据优先级仲裁通过ID标识优先级冲突时高优先级设备自动获得总线控制权强抗干扰差分信号传输CAN_H和CAN_L能有效抑制共模干扰在STM32CubeMX中配置CAN时有三个关键参数需要特别注意波特率设置常见的有125Kbps、250Kbps、500Kbps和1Mbps。根据总线长度选择我的经验是1米内可以用1Mbps超过5米建议降到125Kbps工作模式通常选择Normal模式调试时可以用Loopback模式自测自动重传建议开启确保重要数据不会因偶尔的干扰丢失硬件连接有个容易踩的坑CAN总线两端必须接120Ω终端电阻我第一次调试时因为漏接这个电阻通信距离连50cm都不到加上电阻后直接稳定传输10米。2. STM32CubeMX配置详解打开CubeMX后按照这个流程操作2.1 基础参数配置在Pinout界面启用CAN1Configuration标签页设置Mode: NormalPrescaler: 根据时钟计算比如APB1时钟54MHz要配500Kbps时填6Time Quanta in Bit Segment 1: 通常设13-15个时间单元Time Quanta in Bit Segment 2: 设2-3个时间单元ReSynchronization Jump Width: 设为1小技巧点击Bit Timing Calculation可以自动计算参数但要注意实际测试时可能需要微调2.2 过滤器配置过滤器是CAN的安检系统决定接收哪些ID的消息。我的推荐配置CAN_FilterTypeDef filter; filter.FilterBank 0; filter.FilterMode CAN_FILTERMODE_IDMASK; filter.FilterScale CAN_FILTERSCALE_32BIT; filter.FilterIdHigh 0x0000; // 不筛选ID高位 filter.FilterIdLow 0x0000; // 不筛选ID低位 filter.FilterMaskIdHigh 0x0000; // 不屏蔽任何位 filter.FilterMaskIdLow 0x0000; filter.FilterFIFOAssignment CAN_RX_FIFO0; filter.FilterActivation ENABLE; HAL_CAN_ConfigFilter(hcan1, filter);2.3 中断设置在NVIC Settings中启用这两个中断CAN1 RX0 interruptsCAN1 SCE interrupt这样当收到消息或发生错误时CPU会立即处理。3. 核心代码实现与调试3.1 发送函数封装这个发送函数支持发送4个short类型数据void CAN_Send_Msg(CAN_HandleTypeDef *hcan, uint32_t id, short i1, short i2, short i3, short i4) { static CAN_TxHeaderTypeDef tx_header; uint8_t tx_data[8]; tx_header.StdId id; // 标准ID tx_header.IDE CAN_ID_STD; // 标准格式 tx_header.RTR CAN_RTR_DATA; // 数据帧 tx_header.DLC 8; // 8字节数据 // 将short拆分为两个byte tx_data[0] i1 8; tx_data[1] i1; tx_data[2] i2 8; tx_data[3] i2; tx_data[4] i3 8; tx_data[5] i3; tx_data[6] i4 8; tx_data[7] i4; HAL_CAN_AddTxMessage(hcan, tx_header, tx_data, (uint32_t *)CAN_TX_MAILBOX0); }3.2 接收回调函数接收处理放在中断回调中void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { CAN_RxHeaderTypeDef rx_header; uint8_t rx_data[8]; HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, rx_header, rx_data); // 示例处理电机反馈数据 if(rx_header.StdId 0x201) { // 电机1的反馈ID int16_t angle (rx_data[0] 8) | rx_data[1]; int16_t speed (rx_data[2] 8) | rx_data[3]; // 更新电机状态... } }3.3 调试技巧逻辑分析仪抓包用Saleae观察CAN_H和CAN_L波形检查波特率是否准确终端电阻检测用万用表测量CAN_H和CAN_L间电阻应为60Ω左右两个120Ω并联错误计数器调用HAL_CAN_GetError()查看错误状态常见问题波特率不匹配错误计数器快速增加接线错误显性电平电压异常正常CAN_H3.5VCAN_L1.5V4. 多电机控制实战以控制四个大疆电机为例需要实现4.1 电机ID分配电机控制ID反馈ID电机10x2000x201电机20x2000x202电机30x2000x203电机40x2000x2044.2 控制指令发送// 发送速度控制指令 void Motor_Speed_Ctrl(CAN_HandleTypeDef *hcan, int16_t spd1, int16_t spd2, int16_t spd3, int16_t spd4) { CAN_Send_Msg(hcan, 0x200, spd1, spd2, spd3, spd4); }4.3 数据解析优化使用联合体提升数据处理效率typedef union { uint8_t data[8]; struct { int16_t angle; int16_t speed; int16_t torque; int16_t temp; } motor; } MotorData; // 在接收回调中 MotorData md; memcpy(md.data, rx_data, 8); printf(角度:%d 速度:%d\n, md.motor.angle, md.motor.speed);5. 典型故障排查案例5.1 通信时断时续现象电机偶尔不响应控制指令排查用示波器检查电源电压发现电机启动时电压跌落严重在CAN收发器电源端增加100μF电容改用粗线径电源线降低压降5.2 数据错乱现象收到的角度值突然跳变解决检查发现未启用CAN硬件CRC校验在CubeMX中启用hcan1.Init.AutoRetransmission ENABLE在代码中添加软件校验if(HAL_CALC_CRC(rx_data, 8) ! expected_crc) { // 请求重发 }5.3 总线死锁现象所有设备无法通信应急处理断开所有设备电源用万用表检查总线是否有短路逐个设备上电定位故障节点记得第一次调通CAN控制四个电机同步转动时那种成就感至今难忘。虽然中途因为接线问题烧过一个CAN收发器但这些经验让我深刻理解了差分信号和总线仲裁的精妙设计。

相关新闻