STM32F411:清除外部中断标志真的有必要吗?

Posted

技术标签:

【中文标题】STM32F411:清除外部中断标志真的有必要吗?【英文标题】:STM32F411: is clearing an external interrupt flag really necessary? 【发布时间】:2015-01-21 04:28:13 【问题描述】:

我已经购买了 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”来重置。

进一步阅读会发现这对于 events 有点不同:

当所选边沿出现在事件线上时,会产生一个事件脉冲。未设置事件行对应的挂起位。

但是,我没有将按钮 pin 模式设置为任何 GPIO_MODE_EVT_... 模式,所以我没有使用事件机制(老实说,我什至不知道那是什么 - 我只是认为我没有使用它。欢迎任何提示)。

所以我应该在某个地方打电话给void HAL_NVIC_ClearPendingIRQ (IRQn_Type IRQn),不是吗?似乎不需要通过软件清除标志,因为每个下降沿不会多次调用 ISR。我在HAL_GPIO_EXTI_Callback 中添加了一个断点来验证这一点。

编辑

如cmets中提到的,标志清除代码在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 参数对应的挂起标志。所以我必须编写一个 ISR 来整理出设置了哪些标志,并为每个标志调用HAL_GPIO_EXTI_IRQHandler,然后再调用我的HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin),再次将引脚作为参数。对于每个外部中断,引脚号会被检查大约 3 次(在 ISR、处理程序和回调中)!

如果这是解决方案,我希望我的问题回来。

【问题讨论】:

我很确定这个标志在HAL_GPIO_EXTI_IRQHandler() 中被清除了——你没有向我们展示这个特定函数的来源......而且 - 通常 - 这样的问题可以通过 NOT 使用 ST 的这个伪库——它什么也没解决,只是给你更多的问题需要思考。而且它非常糟糕,我只是看不到这段代码...... 哦——你的变量blink_period应该真的被声明为volatile @FreddieChopin 确实外部中断的处理非常复杂,我想我什至不想尝试更复杂外围设备的驱动程序。 HAL_GPIO_EXTI_IRQHandler() 由 ST 提供 - 我看过它,它确实清除了相关标志。那么Cube有什么替代品吗? Nothing that I know of (; 还有libopenCM3——我没用过,所以不知道有什么价值。外围很简单,所以我个人就用我自己的代码,使用 SPL(Cube 的前身)作为示例,当我不明白某些东西或某些东西不应该工作时。如果你愿意,你可以从我的网站上查看 STM32F4 示例项目 - 你有 GPIO 配置和时钟(RCC ) 使用寄存器完成配置,因此您将看到它的外观。该示例不适用于 nucleo,但当您更改 config.h 文件中的设置时它会起作用。 @KarthikNishanth:您可能还没有寻找,但为了其他人的利益,STM32Cube 包中有一堆使用 HAL 驱动程序的示例。见st.com/web/catalog/tools/FM147/CL1794/SC961/SS1743/LN1897 或st.com/web/catalog/tools/FM147/CL1794/SC961/SS1743/LN1897/… 【参考方案1】:

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

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

【讨论】:

以上是关于STM32F411:清除外部中断标志真的有必要吗?的主要内容,如果未能解决你的问题,请参考以下文章

stm32中外部中断进入中断以后,把中断线挂起位清0以后,在检测还有意义吗,不是已经clear了吗

STM32的RTC中断标志只能手动清除

STM32F411RE:程序冻结,超声波传感器不工作

STM32F411我需要通过USB高速发送大量数据

STM32的滴答定时器的计数到0时标志位置1,需要软件清除标志位吗!,还是硬件自动清除

STM32F411CE芯片锁住解决办法