我已经购买了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 回答
您不必调用
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中的挂起位 .