HAL库,为什么可以在中断中进行延时?

文章讨论了STM32单片机中使用延时函数delay_ms()时,尽管滴答定时器中断优先级较低,但在EXTI0中断处理中如何保持延时功能。通过EXTI0中断的优先级设置和中断处理机制,即使低优先级也能实现延时。

问题描述

延时函数delay_ms()的实现原理是根据滴答定时器中断来实现的。滴答定时器中断优先级设置为15,即最低优先级。另外开启外部中断EXTI0,EXTI0的中断优先级设置为4,EXTI0的中断优先级高于滴答定时器的中断优先级。此时在中断服务函数内部调用delay_ms()函数,STM32单片机还可以正常进行延时吗?考虑到优先级的原因,这令我很疑惑。我给你举个例子如void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
delay_ms(100); …}

答案解释

因为:

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
   
   
  /* EXTI line interrupt detected */
  if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) 
### HAL EXTI中断中因延时导致程序卡死的原因及解决方案 #### 1. 原因分析 在使用STM32 HAL中的EXTI外部中断时,如果在中断服务程序(ISR)中调用了`HAL_Delay()`函数,可能会导致程序卡死。这是因为`HAL_Delay()`函数依赖于系统滴答定时器(SysTick Timer)来实现延迟功能[^2]。具体来说: - `HAL_Delay()`函数通过阻塞当前任务并等待指定的时间来实现延迟。 - 系统滴答定时器中断服务程序负责更新全局变量`hal_tick`,而`HAL_Delay()`函数正是基于此变量计算剩余时间。 - 如果其他中断优先级高于系统滴答定时器优先级,可能导致系统滴答定时器中断服务程序无法及时执行,从而使`HAL_Delay()`函数陷入无限等待状态,最终导致程序卡死。 此外,`HAL_Delay()`函数本质上是一个忙等待函数,不适合在中断服务程序中使用,因为中断服务程序需要尽可能短小高效,以避免影响其他中断的响应时间[^1]。 #### 2. 解决方案 为了解决上述问题,可以采取以下两种主要方法: ##### 方法一:提高系统滴答定时器优先级 可以通过调整中断优先级配置,确保系统滴答定时器优先级高于其他外设中断优先级。例如,在初始化代码中设置滴答定时器优先级如下: ```c void MX_NVIC_Init(void) { NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); // 设置优先级分组 NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0)); // 设置SysTick优先级为最高 } ``` 通过这种方式,可以保证即使在其他中断服务程序中调用`HAL_Delay()`,系统滴答定时器仍然能够正常工作,从而避免程序卡死[^2]。 ##### 方法二:自定义延时函数 另一种更推荐的方法是避免在中断服务程序中直接使用`HAL_Delay()`,而是通过自定义延时函数来实现非阻塞式延时。例如,可以使用一个简单的循环延时函数: ```c void custom_delay(uint32_t count) { for (uint32_t i = 0; i < count; i++); } ``` 或者利用定时器实现延时功能。例如,可以创建一个定时器实例,并在定时器中断中完成延时操作。以下是一个基于定时器延时示例: ```c TIM_HandleTypeDef htim; void start_timer_for_delay(void) { __HAL_TIM_SET_COUNTER(&htim, 0); // 清零计数器 __HAL_TIM_ENABLE(&htim); // 启动定时器 } bool is_timer_expired(uint32_t timeout_ms) { return __HAL_TIM_GET_COUNTER(&htim) >= timeout_ms; } ``` 在中断服务程序中,可以调用`start_timer_for_delay()`启动定时器,并在主循环中检查是否超时[^3]。 #### 3. 推荐实践 为了避免潜在的问题,建议遵循以下最佳实践: - 在中断服务程序中尽量避免使用任何可能导致阻塞的函数,包括但不限于`HAL_Delay()`、`osDelay()`等。 - 使用非阻塞方式实现延时逻辑,例如通过定时器或轮询机制。 - 根据实际需求合理配置中断优先级,确保关键中断能够及时响应。 ### 示例代码 以下是一个完整的示例,展示如何在EXTI中断中避免使用`HAL_Delay()`: ```c #include "stm32f4xx_hal.h" TIM_HandleTypeDef htim; void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == GPIO_PIN_0) { start_timer_for_delay(); // 启动定时器 } } void start_timer_for_delay(void) { __HAL_TIM_SET_COUNTER(&htim, 0); // 清零计数器 __HAL_TIM_ENABLE(&htim); // 启动定时器 } bool is_timer_expired(uint32_t timeout_ms) { return __HAL_TIM_GET_COUNTER(&htim) >= timeout_ms; } int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM_Init(); while (1) { if (is_timer_expired(1000)) { // 检查是否超时 __HAL_TIM_DISABLE(&htim); // 停止定时器 // 执行后续逻辑 } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九层指针

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值