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了吗