首页 文章

STM32F411:是否真的需要清除外部中断标志?

提问于
浏览
8

我已经购买了STM32F411核板,现在我正在尝试了解HAL的各种零碎 . 从外部中断开始似乎是一个好主意,因为电路板有一个连接到PC13的按钮 . 所以我设置了一个简单的切换频率闪烁 . 下面的代码有点简化:

#define LED_PIN GPIO_PIN_5
#define BTN_PIN GPIO_PIN_13

static uint32_t blink_period = 250;

int main(void)
{
  HAL_Init();
  SystemClock_Config();

  __GPIOA_CLK_ENABLE();
  GPIO_InitTypeDef pinConfig;
  pinConfig.Pin = (LED_PIN);
  pinConfig.Pull = GPIO_NOPULL;
  pinConfig.Mode = GPIO_MODE_OUTPUT_PP;
  pinConfig.Speed = GPIO_SPEED_FAST;
  HAL_GPIO_Init(GPIOA, &pinConfig);

  __GPIOC_CLK_ENABLE();
  pinConfig.Pin = (BTN_PIN);
  pinConfig.Pull = GPIO_NOPULL;
  pinConfig.Mode = GPIO_MODE_IT_FALLING;
  pinConfig.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(GPIOC, &pinConfig);
  HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0x0F, 0x00);
  HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

  while (1)
  {
    HAL_GPIO_TogglePin(GPIOA, LED_PIN);
    HAL_Delay(blink_period);
  }
}

void EXTI15_10_IRQHandler(void)
{
  HAL_GPIO_EXTI_IRQHandler(BTN_PIN);
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if(GPIO_Pin == BTN_PIN)
  {
    if (blink_period == 500)
    {
      blink_period = 250;
    }
    else
    {
      blink_period = 500;
    }
  }
}

当我按下按钮时,会产生一个中断,闪烁的频率从1到2 Hz变化(反之亦然) . 这是按预期工作的,但为什么呢?我忘了清除挂起的中断标志,所以应该一遍又一遍地调用ISR . 数据表清楚地说明了这一点

当外部中断线上出现所选边沿时,会产生中断请求 . 还设置对应于中断线的待定位 . 通过在挂起的寄存器中写入'1'来重置该请求 .

进一步阅读可以发现事件有点不同:

当事件行上出现选定边时,会生成事件脉冲 . 未设置与事件行对应的挂起位 .

但是,我没有将按钮引脚模式设置为任何 GPIO_MODE_EVT_... 模式,所以我还知道它是什么 - 我只是认为我没有使用它 . 任何提示都是受欢迎的) .

所以在某个地方我应该调用 void HAL_NVIC_ClearPendingIRQ (IRQn_Type IRQn) ,不应该't I? It seems that clearing the flag by software is not necessary, because the ISR is not called more than once per falling edge. I'在 HAL_GPIO_EXTI_Callback 中添加一个断点来验证这一点 .

编辑

正如评论中所提到的,标志清除代码是ST的GPIO中断处理程序的实现:

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Callback(GPIO_Pin);
  }
}

这个处理程序需要由实际的ISR(在我的代码中完成)调用,并清除对应于GPIO_Pin参数的pending标志 . 所以我必须编写一个ISR来排序设置哪些标志,并为每个标志调用 HAL_GPIO_EXTI_IRQHandler ,然后再将该引脚作为参数调用我的 HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) . 对于每个外部中断,引脚号将被检查约3次(在ISR中,在处理程序中和回调中)!

如果这是解决方案,我想回到我的问题 .

1 回答

  • 5

    您不必调用 HAL_NVIC_ClearPendingIRQ (IRQn_Type IRQn) ,因为NVIC中的挂起位将在输入 HAL_GPIO_EXTI_IRQHandler 时自动清除 .

    HAL_GPIO_EXTI_IRQHandler() 实现清除 peripheral 中的挂起位,而不是NVIC中的挂起位 . 如果它没有通过调用 __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin) 来清除挂起位,那么将一次又一次地调用该处理程序 . 关键是您必须区分外设中的中断挂起位和NVIC中的挂起位 .

相关问题