mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1595 字
4 分钟
STM32-02:NVIC外部中断的初步使用
2026-07-14

NVIC(Nested Vectored Interrupt Controller) ,嵌套向量中断控制器,是ARM Cortex-M系列微控制器内核中集成的一个关键组件,用于管理中断和异常。

在芯片配置中启动外部中断#

  1. 左键芯片引脚,在功能中选择GPIO_EXTIxx(以PB12和GPIO_EXTI12为例):

  2. 在左侧选择System Core展开后选择SYS,在其中的GPIO选项可以调整GPIO口的具体信息:

  • GPIO mode:触发中断的模式,例如External Interrupt Mode with Falling edge trigger detection指的是下降沿触发,即由高电平变为低电平时触发中断;
  1. System CoreNVIC中启用EXTI line[15<10>] interrupts

  2. 配置好其他内容后,生成代码。

编辑代码启用中断#

目的:LED_Red规律闪烁,按下KEY1实现切换LED_Green亮灭。

先在main函数的while(1)中写入以下程序,实现红灯规律闪烁:

HAL_GPIO_WritePin(LED_Red_GPIO_Port, LED_Red_Pin, GPIO_PIN_SET);
HAL_Delay(500);
HAL_GPIO_WritePin(LED_Red_GPIO_Port, LED_Red_Pin, GPIO_PIN_RESET);
HAL_Delay(500);

中断函数位于\Core\Srcstm32f1xx.c文件的void EXTI15_10_IRQHandler(void)

void EXTI15_10_IRQHandler(void)
{
/* USER CODE BEGIN EXTI15_10_IRQn 0 */
/* USER CODE END EXTI15_10_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(KEY1_Pin);
/* USER CODE BEGIN EXTI15_10_IRQn 1 */
/* USER CODE END EXTI15_10_IRQn 1 */
}

由于我们设置的GPIO modeExternal Interrupt Mode with Falling edge trigger detection,在KEY1被按下时,会从高电平变为低电平,从而触发中断函数EXTI15_10_IRQHandler()
/* USER CODE BEGIN EXTI15_10_IRQn 0 *//* USER CODE END EXTI15_10_IRQn 0 */之间写入以下代码:

HAL_GPIO_TogglePin(LED_Green_GPIO_Port, LED_Green_Pin);

下载程序后,KEY1基本可以实现绿灯的切换,但是多次尝试切换后,还是会发现有时不灵敏,这是因为硬件消抖还是不足以完全清除抖动,因此我们需要为其添加软件消抖:

HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin)==GPIO_PIN_RESET){
HAL_GPIO_TogglePin(LED_Green_GPIO_Port, LED_Green_Pin);
}

下载程序后按下KEY1,我们却发现程序一动不动,甚至LED_Red都不再闪烁了。
这是因为发生了多个中断的优先级问题,HAL_Delay()函数依赖于Time base:System tick timer的中断,但是此中断的优先级低于EXTI line[15:10] interrupts,因而不能在EXTI15_10_IRQHandler中执行。
解决方法如下:

  1. 回到CubeMX中,在左侧的System Core中找到NVIC,修改各中断的优先级,我们让Time base:System tick timer的优先级高于EXTI line[15:10] interrupts
    注:数字越小,代表其优先级越高
  2. 完成修改后,重新生成代码,下载程序,便可以发现目的已经达成:LED_Red规律闪烁,按下KEY1切换LED_Green亮灭。
CAUTION

不建议在中断中使用HAL_Delay()阻塞式延时,对于按键中断,在之后会有更加巧妙的方法来实现。

深入中断#

参考视频
外部中断/事件控制器: 去除与中断无关的部分,简化后,可以变化为以下的电路:

边沿检测电路#

上升/下降沿触发选择寄存器:决定是检测到上升沿向后传递高电平信号,还是检测到下降沿向后传递高电平信号,或者二者都。
配置GPIO mode,实际上就是在配置上升沿触发选择寄存器下降沿触发选择寄存器

请求挂起寄存器#

接受到边沿检测电路发送来的高电平时,其对应位会被置1。

中断屏蔽寄存器#

配置GPIO引脚为GPIO_EXTIxx时,实际上就是在配置中断屏蔽寄存器的对应位置1。

NVIC(嵌套向量中断控制器)#

通过与门请求挂起寄存器中断屏蔽寄存器相连,当且仅当二者都置1时,才向后发送高电平信号。
掌管中断向量表,即由名称指向中断处理函数。

名称处理向量
EXTI0EXTI0_IRQHandler
EXTI1EXTI1_IRQHandler
EXTI2EXTI2_IRQHandler
EXTI3EXTI3_IRQHandler
EXTI4EXTI4_IRQHandler
EXTI9_5EXTI9_5_IRQHandler
EXTI15_10EXTI15_10_IRQHandler

例如,配置为`EXTI12`且**下降沿触发**的`KEY1`被按下,会依次发生以下过程:
  1. 生成代码阶段:
    • 上升沿触发选择寄存器的第12位被置0;
    • 下降沿触发选择寄存器的第12位被置1;
    • 中断屏蔽寄存器的第12位被置1。
  2. 经过输入驱动器处理的PB12的电平信号经由输入线进入到边沿检测电路
  3. 边沿检测电路检测到高电平转化为低电平;
  4. 边沿检测电路向后发送高电平信号;
  5. 请求挂起寄存器接受到高电平信号,将第12位置1;
  6. 中断屏蔽寄存器请求挂起寄存器的第12位均被置1,通过与门向后输出高电平信号;
  7. NVIC找到中断向量EXTI15_10,执行函数EXTI15_10_IRQHandler
  8. 执行函数HAL_GPIO_EXTI_IRQHandler(),将请求挂起寄存器的第12位置0,终止中断执行,防止中断函数EXTI15_10_IRQHandler被反复执行。

中断优先级#

分为抢占优先级(Preemption Priority)响应优先级(Sub Priority)为什么不是叫次优先级
在STM32中,每个中断向量都有4个二进制位来存储中断优先级信息,我们可以分别为抢占优先级响应优先级分配不同的位数,默认地,会为抢占优先级分配4位,而为响应优先级分配0位,此时每个中断向量的抢占优先级可设置为0-15,而响应优先级只能是0。不过响应优先级的实际作用不大,一般保持默认设置为抢占优先级分配4位即可。

两个中断同时发生时#

  • 优先比较抢占优先级
  • 抢占优先级相同,则再比较响应优先级
  • 响应优先级也相同,则按照中断向量表中顺序决定执行顺序。

在其一中断执行中,接受到另一中断的信号#

仅比较抢占优先级

  • 若后者中断B抢占优先级更高,则会中断当前执行的中断A,优先执行中断B,待中断B完成后,继续完成中断A。
  • 若后者中断B抢占优先级更低,则当前的中断A会继续执行,执行完中断A之后,再执行中断B。

在刚才的项目中,设置Time base:System tick timer的优先级高于EXTI line[15:10] interrupts,便是为了系统计时的中断能够在外部中断执行过程中抢占执行,从而为HAL_Delay()函数提供时间基准。

总结#

相关函数#

void EXTIxx_IRQHandler(void)

位于Src\stm32f1xx_it.c中,触发外部中断时会调用此函数。
…好像没啥要总结的

STM32-02:NVIC外部中断的初步使用
https://nf3eb.github.io/posts/stm32/stm32-02/
作者
NF3eb
发布于
2026-07-14
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录