STM32 CAN回环模式下发送消息无法接收的问题排查
STM32 CAN回环模式下发送消息未被接收的问题排查
问题描述
我正在开发一个涉及CAN(控制器局域网)通信与UART的STM32单片机项目,相关配置如下:
- CAN配置:外设初始化为**回环模式(Loopback Mode)**用于测试。TxHeader设置为标准标识符(StdId = 0x103)、数据帧模式(CAN_RTR_DATA)、8字节负载,通过
HAL_CAN_AddTxMessage()发送消息。 - CAN消息接收:已通过
HAL_CAN_ActivateNotification()启用CAN接收,实现了HAL_CAN_RxFifo0MsgPendingCallback()函数用于获取传入消息。
核心问题:TxData数组已正确填充数据,但发送的消息未按预期被接收,RxData缓冲区全为0x00,表明无数据接收。使用回环模式,预期同一设备能接收发送的消息,请问这是什么原因?
项目代码
/* USER CODE BEGIN Header */ /** #include "main.h" #include "string.h" #include <stdio.h> CAN_HandleTypeDef hcan; UART_HandleTypeDef huart2; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_CAN_Init(void); static void MX_USART2_UART_Init(void); CAN_TxHeaderTypeDef TxHeader; CAN_RxHeaderTypeDef RxHeader; uint32_t TxMailbox; uint8_t TxData [8]; uint8_t RxData [8]; void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan){ HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData); } int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_CAN_Init(); MX_USART2_UART_Init(); HAL_CAN_Start(&hcan); HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING); TxHeader.DLC = 8; TxHeader.ExtId = 0; TxHeader.IDE = CAN_ID_STD; TxHeader.RTR =CAN_RTR_DATA; TxHeader.StdId = 0x103; TxHeader.TransmitGlobalTime = DISABLE; memset(TxData, 0, sizeof(TxData)); TxData[0] =0xf3 ; HAL_CAN_AddTxMessage(&hcan, &TxHeader, TxData, &TxMailbox); while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } static void MX_CAN_Init(void) { hcan.Instance = CAN1; hcan.Init.Prescaler = 18; hcan.Init.Mode = CAN_MODE_LOOPBACK; hcan.Init.SyncJumpWidth = CAN_SJW_1TQ; hcan.Init.TimeSeg1 = CAN_BS1_2TQ; hcan.Init.TimeSeg2 = CAN_BS2_1TQ; hcan.Init.TimeTriggeredMode = DISABLE; hcan.Init.AutoBusOff = DISABLE; hcan.Init.AutoWakeUp = DISABLE; hcan.Init.AutoRetransmission = DISABLE; hcan.Init.ReceiveFifoLocked = DISABLE; hcan.Init.TransmitFifoPriority = DISABLE; if (HAL_CAN_Init(&hcan) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN CAN_Init 2 */ CAN_FilterTypeDef canfilterconfig; canfilterconfig.FilterActivation = CAN_FILTER_ENABLE; canfilterconfig.FilterBank =10; canfilterconfig.FilterFIFOAssignment = CAN_RX_FIFO0; canfilterconfig.FilterIdHigh =0; canfilterconfig.FilterIdLow = 0x0000; canfilterconfig.FilterMaskIdHigh =0; canfilterconfig.FilterMaskIdLow = 0x0000; canfilterconfig.FilterMode = CAN_FILTERMODE_IDMASK; canfilterconfig.FilterScale = CAN_FILTERSCALE_32BIT; HAL_CAN_ConfigFilter( &hcan, &canfilterconfig); canfilterconfig.SlaveStartFilterBank = 0; /* USER CODE END CAN_Init 2 */ } static void MX_USART2_UART_Init(void) { huart2.Instance = USART2; huart2.Init.BaudRate = 115200; huart2.Init.WordLength = UART_WORDLENGTH_8B; huart2.Init.StopBits = UART_STOPBITS_1; huart2.Init.Parity = UART_PARITY_NONE; huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart2) != HAL_OK) { Error_Handler(); } } static void MX_GPIO_Init(void) { __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); } void Error_Handler(void) { __disable_irq(); while (1) { } } #ifdef USE_FULL_ASSERT void assert_failed(uint8_t *file, uint32_t line) { } #endif /* USE_FULL_ASSERT */
问题原因及修复方案
1. CAN过滤器配置错误
当前过滤器设置的FilterIdHigh/Low和FilterMaskIdHigh/Low均为0,这意味着仅会接收ID为0的CAN消息,而你发送的是ID为0x103的消息,直接被过滤器拦截,导致RxData无数据。
针对标准帧的正确过滤器配置(以接收0x103为例):
CAN_FilterTypeDef canfilterconfig; canfilterconfig.FilterActivation = CAN_FILTER_ENABLE; canfilterconfig.FilterBank = 10; canfilterconfig.FilterFIFOAssignment = CAN_RX_FIFO0; canfilterconfig.FilterMode = CAN_FILTERMODE_IDMASK; canfilterconfig.FilterScale = CAN_FILTERSCALE_32BIT; // 标准ID左移5位放入FilterIdHigh的高11位(符合CAN过滤器寄存器格式) canfilterconfig.FilterIdHigh = (0x103 << 5) & 0xFFFF; canfilterconfig.FilterIdLow = 0x0000; // 掩码高11位全1,确保匹配目标标准ID canfilterconfig.FilterMaskIdHigh = 0xFFE0; canfilterconfig.FilterMaskIdLow = 0x0000; HAL_CAN_ConfigFilter(&hcan, &canfilterconfig);
如果需要接收所有标准帧,可将FilterMaskIdHigh设为0x0000,FilterIdHigh设为0x0000。
2. 冗余配置代码干扰
你在过滤器配置后设置了canfilterconfig.SlaveStartFilterBank = 0;,该参数仅针对双CAN外设(如STM32F4的CAN1/CAN2),单CAN外设下无需设置,且该行代码在HAL_CAN_ConfigFilter()之后不会生效,建议直接删除。
3. 调试补充建议
- 在
HAL_CAN_RxFifo0MsgPendingCallback()中添加UART打印,确认回调是否被触发; - 检查
HAL_CAN_AddTxMessage()的返回值,确保返回HAL_OK,确认消息成功进入发送邮箱; - 主循环中主动检查接收FIFO状态,避免依赖回调的延迟:
while (1) { if (HAL_CAN_GetRxFifoFillLevel(&hcan, CAN_RX_FIFO0) > 0) { HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &RxHeader, RxData); // 此处添加数据打印或处理逻辑 } }
内容的提问来源于stack exchange,提问作者Δήμητρα Γενναίου




