1. 问题描述
按以下方式使用CubeMX配置STM32F103C8T6的CAN总线后,发送数据正常,接收则一直无法进入接收中断,先记录该问题于此,如日后解决会更新该文章。如有前辈在看过我的代码后能够发现我的问题,也很欢迎在评论区加以指正,感激不尽。
2.CAN配置
-
CubeMX CAN波特率配置
波特率配置为1Mhz,系统时钟为64M,APB1则为32M。
-
CAN其他配置
-
NVIC配置
-
生成代码后打开源代码,在
CAN.C
中添加屏蔽器设置代码
CAN_RxPacketTypeDef CanRxPacket;
CAN_TxPacketTypeDef CanTxPacket;
void CAN_Filter_Config(void)
{
CAN_FilterTypeDef sFilterConfig;
CAN_FilterRegTypeDef IDH = {0};
CAN_FilterRegTypeDef IDL = {0};
#if CAN_ID_TYPE_STD_ENABLE
IDH.Sub.STID = (CAN_BASE_ID >> 16) & 0xFFFF; // 标准ID高16位
IDL.Sub.STID = (CAN_BASE_ID & 0xFFFF); // 标准ID低16位
#else
IDH.Sub.EXID = (CAN_BASE_ID >> 16) & 0xFFFF; // 扩展ID高16位
IDL.Sub.EXID = (CAN_BASE_ID & 0xFFFF); // 扩展ID低16位
IDL.Sub.IDE = 1; // 扩展帧标志位置位
#endif
sFilterConfig.FilterBank = 0; // 设置过滤器组编号
#if CAN_FILTER_MODE_MASK_ENABLE
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 屏蔽位模式
#else
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; // 列表模式
#endif
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 32位宽
sFilterConfig.FilterIdHigh = IDH.value; // 标识符寄存器一ID高十六位,放入扩展帧位
sFilterConfig.FilterIdLow = IDL.value; // 标识符寄存器一ID低十六位,放入扩展帧位
sFilterConfig.FilterMaskIdHigh = IDH.value; // 标识符寄存器二ID高十六位,放入扩展帧位
sFilterConfig.FilterMaskIdLow = IDL.value; // 标识符寄存器二ID低十六位,放入扩展帧位
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 过滤器组关联到FIFO0
sFilterConfig.FilterActivation = ENABLE; // 激活过滤器
//sFilterConfig.SlaveStartFilterBank = 11; // 设置从CAN的起始过滤器编号,本单片机只有一个CAN,顾此参数无效
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
}
在CAN.H
添加
typedef struct
{
uint32_t mailbox;
CAN_TxHeaderTypeDef hdr;
uint8_t payload[8];
}CAN_TxPacketTypeDef;
typedef struct
{
CAN_RxHeaderTypeDef hdr;
uint8_t payload[8];
}CAN_RxPacketTypeDef;
extern CAN_RxPacketTypeDef CanRxPacket;
extern CAN_TxPacketTypeDef CanTxPacket;
typedef union
{
__IO uint32_t value;
struct
{
uint8_t REV : 1; //< [0]
uint8_t RTR : 1; //< [1]
uint8_t IDE : 1; //< [2]
uint32_t EXID : 18; //< [21:3]
uint16_t STID : 11; //< [31:22]
} Sub;
} CAN_FilterRegTypeDef;
#define CAN_BASE_ID 0
#define CAN_FILTER_MODE_MASK_ENABLE 1
#define CAN_ID_TYPE_STD_ENABLE 1
#define CAN_Target_ID 0x01
extern uint8_t CAN_TX_Sign;
void CAN_Init(void);
void CAN_SetTxPacket(uint16_t Target_Id);
- 添加发送函数
uint8_t CAN_Transmit(CAN_TxPacketTypeDef* packet)
{
if(HAL_CAN_AddTxMessage(&hcan, &packet->hdr, packet->payload, &packet->mailbox) != HAL_OK)
return 1;
return 0;
}
- 添加初始化代码
void CAN_Init(void)
{
CAN_Filter_Config();
HAL_CAN_Start(&hcan);
HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING); // 使能CAN接收中断
}
将初始化代码加入main.c
:
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_TIM2_Init();
MX_ADC1_Init();
MX_I2C1_Init();
MX_USART2_UART_Init();
MX_USART1_UART_Init();
MX_CAN_Init();
/* USER CODE BEGIN 2 */
CAN_Init();//CAN初始化
- 添加用户发送函数
void CAN_SetTxPacket(uint16_t Target_Id)
{
CanTxPacket.hdr.StdId = Target_Id; // 标准ID
// CanTxPacket.hdr.ExtId = 0x10F01234; // 扩展ID
CanTxPacket.hdr.IDE = CAN_ID_STD; // 标准ID类型
// CanTxPacket.hdr.IDE = CAN_ID_EXT; // 扩展ID类型
CanTxPacket.hdr.DLC = 8; // 数据长度
CanTxPacket.hdr.RTR = CAN_RTR_DATA; // 数据�??
// CanTxPacket.hdr.RTR = CAN_RTR_REMOTE; // 远程�??
CanTxPacket.hdr.TransmitGlobalTime = DISABLE;
CAN_Transmit(&CanTxPacket);
}
- 在
stm32f1xx_it.c
中添加接收中断回传函数
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *canHandle)
{
// CAN数据接收
if (canHandle->Instance == CAN1)
{
if (HAL_CAN_GetRxMessage(canHandle, CAN_RX_FIFO0, &CanRxPacket.hdr, CanRxPacket.payload) == HAL_OK) // 获得接收到的数据头和数据
{
if(!CAN_TX_Sign)
CAN_TX_Sign = 1;
HAL_CAN_ActivateNotification(canHandle, CAN_IT_RX_FIFO0_MSG_PENDING); // 再次使能FIFO0接收中断
}
}
}
- 在
main.c
的while(1)
中添加用户代码
/* USER CODE BEGIN 3 */
if(CAN_TX_Sign)
{
CAN_SetTxPacket(0x102);
CAN_TX_Sign = 0;
}
HAL_Delay(10);
}
/* USER CODE END 3 */
3. 测试:
前期问题描述:调试时在HAL_CAN_IRQHandler(&hcan);
处设置断点,用电脑通过CAN分析器发送数据,使用Jlink进行Debug未进入CAN的接收中断。使用单片机给电脑发送数据正常。
问题解决:重新查看了CAN的收发代码,在接收时HAL库函数是通过过滤ID来判断是否进入中断来接收数据的,因此接收时,只有指定正确的ID才能够进入中断。本机ID设置位置如下:
CAN.h
中
#define CAN_BASE_ID 0 //< CAN标准ID,最大11位,也就是0x7FF
4.例程
整理了一下CAN总线收发的代码单独形成了一个例程,可直接测试使用
https://download.csdn.net/download/weixin_44087298/34875003
烧录方式:SWD,可在STM32_HAL_CAN.ioc中自行修改