STM32F103C8T6 CAN通信实现方案
·
一、硬件配置
-
核心电路设计
-
信号线连接:
STM32引脚 TJA1050引脚 功能说明 PA11 RXD CAN接收输入(需上拉) PA12 TXD CAN发送输出(推挽驱动) -
总线连接:
-
TJA1050的CANH/CANL连接至总线,两端各接120Ω终端电阻
-
总线共地,避免电位差干扰
-
-
-
关键参数
-
供电要求:TJA1050需5V供电,与STM32共地
-
波特率配置:典型值500kbps(APB1时钟36MHz,分频系数18)
-
引脚重映射:默认PA11/PA12,需在CubeMX开启
CAN_REMAP[1:0]=10
-
二、软件实现(STM32CubeMX + HAL库)
1. CubeMX配置流程
-
外设使能:勾选CAN1,模式选择
Normal(正常模式) -
波特率设置:
-
APB1时钟:36MHz
-
预分频系数:18
-
时间段配置:
SYNC_SEG=1tq, PRS=1tq, SBS1=2tq, SBS2=3tq -
最终波特率:36MHz/(18×(1+2+3))=500kbps
-
-
过滤器配置:
-
过滤器模式:
Mask Mode -
过滤器尺度:32位
-
过滤器ID:0x0000(接收所有标准ID)
-
-
中断配置:使能
CAN_RX0_IRQn中断
2. 关键代码实现
// can.c
#include "can.h"
CAN_HandleTypeDef hcan1;
void MX_CAN1_Init(void)
{
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 18; // 分频系数
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; // 同步跳转宽度
hcan1.Init.TimeSeg1 = CAN_BS1_2TQ; // 时间段1
hcan1.Init.TimeSeg2 = CAN_BS2_3TQ; // 时间段2
hcan1.Init.Mode = CAN_MODE_NORMAL; // 正常模式
hcan1.Init.AutoRetransmission = DISABLE;// 关闭自动重传
HAL_CAN_Init(&hcan1);
}
// 过滤器配置
void CAN_Filter_Config(void)
{
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterBank = 0; // 过滤器组0
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 掩码模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 32位尺度
sFilterConfig.FilterIdHigh = 0x0000; // 高16位
sFilterConfig.FilterIdLow = 0x0000; // 低16位
sFilterConfig.FilterMaskIdHigh = 0x0000;// 掩码高16位
sFilterConfig.FilterMaskIdLow = 0x0000; // 掩码低16位
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 分配到FIFO0
HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig);
}
// CAN接收中断服务函数
void USB_LP_CAN1_RX0_IRQHandler(void)
{
HAL_CAN_IRQHandler(&hcan1);
}
// 接收回调函数
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
CanRxMsgTypeDef RxMessage;
HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxMessage, RxData);
printf("Received ID:0x%03X, Data:", RxMessage.StdId);
for(int i=0; i<8; i++) printf("%02X ", RxData[i]);
printf("\r\n");
}
3. 发送与接收函数
// 发送数据(标准帧)
void CAN_Send_Msg(uint32_t StdId, uint8_t *data, uint8_t len)
{
CanTxMsgTypeDef TxMessage = {0};
TxMessage.StdId = StdId; // 标准ID
TxMessage.IDE = CAN_ID_STD; // 标准帧模式
TxMessage.RTR = CAN_RTR_DATA; // 数据帧
TxMessage.DLC = len; // 数据长度
memcpy(TxMessage.Data, data, len);
uint32_t TxMailbox;
HAL_CAN_AddTxMessage(&hcan1, &TxMessage, data, &TxMailbox);
}
// 接收数据(轮询模式)
void CAN_Recv_Msg(uint8_t *data)
{
CanRxMsgTypeDef RxMessage;
if(HAL_CAN_GetRxFifoFillLevel(&hcan1, CAN_RX_FIFO0) > 0)
{
HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxMessage, data);
}
}
三、调试与常见问题
-
信号验证
-
使用示波器测量CAN_H/CAN_L差分电压:
-
空闲状态:CAN_H=2.5V, CAN_L=2.5V(差分0V)
-
显性电平:CAN_H=3.5V, CAN_L=1.5V(差分2V)
-
-
逻辑分析仪捕获CAN帧结构(标识符+数据)
-
-
常见问题解决
现象 可能原因 解决方案 无法初始化 引脚未重映射 检查CubeMX的CAN_REMAP配置 接收不到数据 过滤器未配置 设置接收所有ID(0x0000掩码) 数据错误 总线终端电阻缺失 添加120Ω电阻至总线两端 通信不稳定 电源噪声干扰 增加0.1μF陶瓷电容并联10μF电解电容
参考代码 STM32F103C8T6 CAN通讯 www.youwenfan.com/contentcsr/102049.html
四、扩展功能实现
-
多节点通信
-
每个节点分配唯一ID(如0x100~0x1FF)
-
示例:节点1发送数据至节点2
// 节点1发送 uint8_t data[8] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}; CAN_Send_Msg(0x100, data, 8); // 节点2接收 CAN_Recv_Msg(RxData); if(RxMessage.StdId == 0x100) process_data(RxData);
-
-
CAN总线波特率自适应
// 动态切换波特率(需重新初始化CAN) void CAN_SetBaudRate(uint32_t baud) { hcan1.Instance->BTR = (SystemCoreClock/2)/(baud*(1+CAN_BS1_2TQ+CAN_BS2_3TQ)); HAL_CAN_Stop(&hcan1); HAL_CAN_Init(&hcan1); }
更多推荐



所有评论(0)