【STM32 CAN通信实战手册】原理与代码详解,手把手玩转CAN总线通信
[摘要]
CAN(Controller Area Network)是广泛应用于工业控制、汽车电子等领域的可靠通信协议。本文基于STM32F1系列微控制器,深入解析CAN总线原理,并提供完整的配置代码和实验流程,帮助开发者快速掌握CAN通信核心技术。
一、CAN总线基础原理
1.1 CAN协议核心特点
多主结构:总线上所有节点地位平等,均可主动发送数据
非破坏性仲裁:通过ID优先级解决总线冲突
高可靠性:CRC校验、错误检测与自动重发机制
双线差分信号:CAN_H和CAN_L组成抗干扰传输线
1.2 CAN帧格式(标准帧)
字段 | 长度 | 说明 |
---|---|---|
SOF | 1 bit | 帧起始 |
ID(11位) | 11 bits | 报文标识符 |
RTR | 1 bit | 远程传输请求标志 |
IDE | 1 bit | 标识符扩展位(0=标准帧) |
r0 | 1 bit | 保留位 |
DLC | 4 bits | 数据长度码(0-8字节) |
Data Field | 0-8字节 | 数据内容 |
CRC | 15 bits | 循环冗余校验码 |
ACK | 2 bits | 应答 |
EOF | 7 bits | 帧结束 |
1.3 STM32 CAN控制器(bxCAN)
支持CAN 2.0A/B协议
3个发送邮箱
2个接收FIFO,每个FIFO 3级深度
可配置位时间参数
28个过滤器组(STM32F103)
二、硬件设计
2.1 典型电路连接
STM32 CAN_TX --> TJA1050 TXD
STM32 CAN_RX <-- TJA1050 RXD
TJA1050 CAN_H -- 120Ω -- CAN_H
TJA1050 CAN_L -- 120Ω -- CAN_L
2.2 关键参数计算
波特率计算公式:
波特率 = APB1时钟 / (Prescaler * (BS1 + BS2 + 1))
例如:APB1=36MHz,目标波特率500kbps
设置Prescaler=6, BS1=5, BS2=3
实际波特率 = 36MHz / (6*(5+3+1)) = 500kbps
三、软件配置(基于STM32CubeMX+HAL库)
3.1 CubeMX配置步骤
-
选择CAN模式:Normal或Loopback(自测试)
-
配置参数:
-
Prescaler: 分频系数
-
Time Quantum: 1/(APB1时钟/Prescaler)
-
BS1: 时间段1(5-20 Tq)
-
BS2: 时间段2(1-16 Tq)
-
启用CAN中断(可选)
3.2 过滤器配置
CAN_FilterTypeDef filter;
filter.FilterBank = 0;
filter.FilterMode = CAN_FILTERMODE_IDMASK;
filter.FilterScale = CAN_FILTERSCALE_32BIT;
filter.FilterIdHigh = 0x123 << 5; // 标准ID左移5位
filter.FilterMaskIdHigh = 0x7FF <<5;
filter.FilterFIFOAssignment = CAN_RX_FIFO0;
filter.FilterActivation = ENABLE;
HAL_CAN_ConfigFilter(&hcan, &filter);
四、代码实现
4.1 CAN初始化
void MX_CAN_Init(void)
{
hcan.Instance = CAN1;
hcan.Init.Prescaler = 6;
hcan.Init.Mode = CAN_MODE_NORMAL;
hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan.Init.TimeSeg1 = CAN_BS1_5TQ;
hcan.Init.TimeSeg2 = CAN_BS2_3TQ;
hcan.Init.TimeTriggeredMode = DISABLE;
hcan.Init.AutoBusOff = DISABLE;
hcan.Init.AutoWakeUp = DISABLE;
hcan.Init.AutoRetransmission = ENABLE;
hcan.Init.ReceiveFifoLocked = DISABLE;
hcan.Init.TransmitFifoPriority = DISABLE;
HAL_CAN_Init(&hcan);
}
4.2 发送数据
void CAN_SendMessage(uint32_t id, uint8_t* data, uint8_t len)
{
CAN_TxHeaderTypeDef txHeader;
uint32_t txMailbox;
txHeader.StdId = id;
txHeader.RTR = CAN_RTR_DATA;
txHeader.IDE = CAN_ID_STD;
txHeader.DLC = len;
txHeader.TransmitGlobalTime = DISABLE;
if(HAL_CAN_AddTxMessage(&hcan, &txHeader, data, &txMailbox) != HAL_OK)
{
Error_Handler();
}
}
4.3 接收数据(中断方式)
// 启动CAN接收
HAL_CAN_Start(&hcan);
HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
// 接收回调函数
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
CAN_RxHeaderTypeDef rxHeader;
uint8_t rxData[8];
HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rxHeader, rxData);
printf("Received ID: 0x%03X, Data: ", rxHeader.StdId);
for(int i=0; i<rxHeader.DLC; i++){
printf("%02X ", rxData[i]);
}
printf("\n");
}
五、实验验证
5.1 硬件连接
两个STM32开发板通过CAN收发器连接
终端电阻配置:总线两端各接120Ω电阻
5.2 测试结果
发送端发送:ID=0x123, Data=AA 55 01 02
接收端显示:Received ID: 0x123, Data: AA 55 01 02
六、常见问题排查
-
无法进入中断
-
检查NVIC中断使能
-
确认过滤器配置正确
-
验证HAL_CAN_Start()已调用
-
波特率不匹配
-
使用示波器测量实际波特率
-
重新计算时间参数
-
发送失败
-
检查CAN控制器是否进入Bus-Off状态
-
使用CAN分析仪监控总线活动
七、扩展应用
CANopen协议栈移植
多节点组网通信
汽车诊断协议(ISO-TP)实现
作者:DOMINICHZL