You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

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/LowFilterMaskIdHigh/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,提问作者Δήμητρα Γενναίου

火山引擎 最新活动