You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32F103RB_T6中__WFI函数未正常工作的技术求助

问题描述

我正使用STM32CubeIDE在STM32F103RB_T6上进行C语言开发。奇怪的是,__WFI()函数并未等待中断触发就自行返回,我已在stm32f1xx_it.c的所有中断函数中设置断点,但均未触发。我希望main函数中的switch执行完成后,仅在中断发生时才进入下一轮循环,不想通过全局变量等临时方法解决,想排查问题根源。

以下是main.c文件内容:

#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "states.h"
#include "creators.h"
#include "structures.h"
#include "displays.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
  TestInit();
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  currentStateMain = CATEGORY_SELECTION;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    switch(currentStateMain)
    {
    ...     }

    //__HAL_UART_DISABLE_IT(&huart2, UART_IT_TC);

    __WFI();
    //__HAL_UART_ENABLE_IT(&huart2, UART_IT_TC);
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief USART2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  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();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pins : PA9 PA10 PA11 PA12 */
  GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI9_5_IRQn, 2, 0);
  HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);

  HAL_NVIC_SetPriority(EXTI15_10_IRQn, 2, 0);
  HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

请问可能是有中断发生但未被检测到吗?该如何排查?希望按规范实现需求,不采用临时方案。


排查方案

是的,确实存在**中断已触发但未进入中断服务函数(ISR)**的可能,或者有未被清除的中断挂起标志导致__WFI()直接返回。以下是逐步排查步骤:

1. 检查中断挂起寄存器,确认是否有未处理的中断

__WFI()会在有中断挂起时直接返回,哪怕该中断被屏蔽或者优先级不够。可以在调用__WFI()前读取以下寄存器:

  • 内核层面:读取SCB->ICSR寄存器,查看PENDSTSET(SysTick挂起)、PENDSVSET(PendSV挂起)、ISRPENDING(外部中断挂起)位
  • 外设层面:
    • GPIO中断:读取EXTI->PR寄存器,查看对应引脚的挂起位(比如PA9对应EXTI9,看PR9位)
    • UART中断:读取USART2->SR寄存器,查看是否有未清除的中断标志(比如RXNE、TC等)

可以添加临时调试代码(调试完移除):

// 在__WFI()前添加
uint32_t scb_icr = SCB->ICSR;
uint32_t exti_pr = EXTI->PR;
uint32_t usart_sr = USART2->SR;
// 用调试器查看这几个变量的值,或者通过UART输出

如果发现某个挂起位为1,说明该中断已经触发但未被处理,__WFI()因此直接返回。

2. 检查SysTick中断是否被默认启用

HAL_Init()会默认初始化SysTick并开启其中断(用于HAL的延时函数)。如果你的代码中没有用到HAL延时,但SysTick中断依然在运行,那么每隔1ms(默认配置)就会触发一次SysTick中断,导致__WFI()频繁返回。

可以在HAL_Init()后手动关闭SysTick中断验证:

HAL_Init();
HAL_SuspendTick(); // 关闭SysTick中断

如果__WFI()能正常等待了,就说明问题出在SysTick上。后续可以根据需求调整SysTick配置,或者在进入低功耗前关闭它,退出时再开启。

3. 验证GPIO中断配置的完整性

从你的MX_GPIO_Init()代码看,已经配置了PA9-PA12为上升沿触发、下拉输入,也开启了对应的EXTI中断通道,但要注意:

  • 检查stm32f1xx_it.c中是否实现了EXTI9_5_IRQHandler()和EXTI15_10_IRQHandler(),并且调用了HAL_GPIO_EXTI_IRQHandler()处理具体引脚。比如:
void EXTI9_5_IRQHandler(void)
{
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);
}

void EXTI15_10_IRQHandler(void)
{
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10);
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
}

如果没有实现这些Handler,或者没有调用HAL的处理函数,中断触发后无法清除挂起位,会导致__WFI()反复返回。

  • 检查HAL_GPIO_EXTI_Callback()是否被正确实现。如果只是实现了Handler但没写Callback,HAL库会默认清除中断标志,但如果你的Callback里没有清除标志(或者写错了引脚),也会导致挂起位一直置1。

4. 检查UART中断的配置

你的代码中注释了UART发送完成中断的使能/禁用,但UART初始化时开启了TX_RX模式,默认情况下HAL会开启哪些中断?可以查看HAL_UART_Init()的实现,或者直接读取USART2->CR1寄存器,确认是否有未预期的中断被开启(比如RXNEIE)。如果UART引脚有噪声导致误触发RX中断,也会让__WFI()返回。

5. 检查全局中断是否被启用

虽然HAL_Init()会默认开启全局中断(__enable_irq()),但如果代码中某个地方不小心调用了__disable_irq(),会导致所有中断被屏蔽,但此时如果有中断挂起,__WFI()依然会返回(因为挂起标志存在),但ISR不会执行。可以在__WFI()前检查全局中断状态:

// 检查PRIMASK寄存器,0表示全局中断开启,1表示关闭
uint32_t primask = __get_PRIMASK();

6. 调试器的影响

有些调试器在连接时会导致__WFI()行为异常,比如调试器的“halt on interrupt”选项被开启,或者调试器本身会周期性唤醒CPU。可以尝试断开调试器,用硬件方式验证(比如LED闪烁)__WFI()是否正常等待。


内容的提问来源于stack exchange,提问作者MieszkoPasierbek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 17:28:09