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

时间:2014-11-23 11:05:56

标签: interrupt stm32 interrupt-handling

我已经购买了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 Hz变为2 Hz(反之亦然)。这是按预期工作的,但为什么呢?我忘了清除挂起的中断标志,所以应该一遍又一遍地调用ISR。数据表明确指出

  

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

进一步阅读后发现,对于事件

,这有点不同
  

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

但是,我没有将按钮固定模式设置为任何GPIO_MODE_EVT_...模式,所以我没有使用事件机制(说实话我还不知道是什么即便如此 - 我只是认为我没有使用它。欢迎任何提示。

所以在某个地方我应该打电话给void HAL_NVIC_ClearPendingIRQ (IRQn_Type IRQn),不应该吗?似乎不需要通过软件清除标志,因为每个下降沿不会多次调用ISR。我在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 个答案:

答案 0 :(得分:7)

您不必拨打HAL_NVIC_ClearPendingIRQ (IRQn_Type IRQn),因为在输入HAL_GPIO_EXTI_IRQHandler后,NVIC中的待处理位将自动清除。

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