STM32_HAL库的EXTI外部中断不能使用HAL_Delay()的原因

在上一篇文章中关于STM32_HAL库调试外部中断EXTI的问题(vscode),我们讲到了使用外部中断不能退出的原因,这次我们来说另外一个原因:在外部中断中使用HAL_Delay()函数会进入死循环。
例如下述实例,在中断回调服务函数里调用HAL_Delay(),会导致卡死,无法外部按键触发中断。

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_1) // 检测PC1引脚是否出现下降沿触发
    {
        HAL_Delay(20);
        if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_1) == 0) // 再次检测是否为低电平
        {
            HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);
        }
    }

    // while (GPIO_Pin == GPIO_PIN_1)// 检测PC1引脚是否出现下降沿触发
    // {
    //     if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_1) == 0)// 再次检测是否为低电平
    //     {
    //         HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);
    //     }
    //     break;
    // }

    // do
    // {
    //     if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_1) == 0)// 再次检测是否为低电平
    //     {
    //         HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);
    //     }
    //     break;
    // } while (GPIO_Pin == GPIO_PIN_1);// 检测PC1引脚是否出现下降沿触发
}

原因剖析:

一、先查看HAL_Delay()整体函数

/**
  * @brief This function provides minimum delay (in milliseconds) based
  *        on variable incremented.
  * @note In the default implementation , SysTick timer is the source of time base.
  *       It is used to generate interrupts at regular time intervals where uwTick
  *       is incremented.
  * @note This function is declared as __weak to be overwritten in case of other
  *       implementations in user file.
  * @param Delay specifies the delay time length, in milliseconds.
  * @retval None
  */
__weak void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = HAL_GetTick();
  uint32_t wait = Delay;

  /* Add a freq to guarantee minimum wait */
  if (wait < HAL_MAX_DELAY)
  {
    wait += (uint32_t)(uwTickFreq);
  }

  while ((HAL_GetTick() - tickstart) < wait)
  {
  }
}

二、查看具体循环

在stm32f1xx_hal.c文件中的HAL_Delay()弱库函数中,可以看到有个while循环, 意为:当 系统滴答定时时间 小于 预设时间 ,则循环;否则退出while循环。

while ((HAL_GetTick() - tickstart) < wait)
  {
  }

三、原理说明

由于【系统滴答定时器的优先级数值】=15 > 【中断回调服务函数优先级数值】(数值越小,优先级就越高),当执行中断回调服务函数的时候,高优先级的中断回调抢占了低优先级的系统滴答(发生了中断嵌套),导致系统滴答定时器不执行,无法进行滴答定时,所以上述的while循环处于死等待状态。

四、解决方案

借鉴网上很多大牛的说法,将系统滴答定时器的优先级调高亦或是自定义1个延时函数替代HAL_Delay(),我个人更偏向于后者。

// 延时函数
void custom_delay(int count)
{
    for (int i = 0; i <= count; i++);
}

直接定义custom_delay(),声明调用即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值