名词解释:
NVIC:Nested Vectored Interrupt Controller
SCB:System Control Block
EXTI:External Interrupt/Event Controller
LSM:Light Sensor Module
CPU:Central Processing Unit
IRQ:Interrupt Request
ISR:Interrupt Service Routine
ISER:Interrupt Set Enable Registers
ICER:Interrupt Clear Enable Registers
ISPR:Interrupt Set Pending Registers
ICPR:Interrupt Clear Pending Registers
IABR:Interrupt Active Bit Registers
IPR:Interrupt - Priority Registers
ICSR:Interrupt Control and State Register
VTOR:Vector Table Offset Register
AIRCR:Application Interrupt / Reset Control Register
SHPR:System Handler Priority Registers
TBLBASE:Table Base Select Bit
IMR:Interrupt mask register
EMR:Event mask register
RTSR:Rising trigger selection register
FTSR:Falling trigger selection register
SWIER:Software interrupt event register
APB:Advanced Peripheral Bus
本文将对中断的概念、NVIC的基础知识、EXTI的基础知识、STM32CubeMX生成EXIT的配置函数以及对生成EXIT的配置函数进行分析(包括结构体配置、相关寄存器配置)。最后针对于EXTI的功能,利用KEY输入引脚配置成EXIT,使LED0状态翻转进行实践。
这部分不太好写,如果本文哪里有问题或者补充,欢迎在评论区指正。
1. 中断
1.1 什么是中断?
中断(Interrupt) 是计算机或嵌入式系统中一种事件驱动的响应机制。当发生需要立即处理的紧急事件(如硬件信号、软件请求或异常)时,CPU 暂停当前任务,转去执行特定的处理程序,完成后恢复原任务。中断是实现实时性、多任务协作和高效资源利用的核心技术。
The Cortex -M processors have a number of programmable registers for managinginterrupts and exceptions. Most of these registers are inside the NVIC and SystemControl Block (SCB).
1.2 中断工作流程
- 外设 ->> 中断控制器:发送中断请求(IRQ)
- 中断控制器 ->> CPU:通知有中断待处理
- CPU ->> CPU:完成当前指令,保存上下文(压栈)
- CPU ->> 中断控制器:获取中断向量号
- 中断控制器 ->> CPU:返回中断服务程序(ISR)地址
- CPU ->> 内存(ISR):跳转执行ISR
- 内存(ISR) ->> 外设:处理事件(如读取数据)
- 内存(ISR) ->> 中断控制器:清除中断标志
- CPU ->> CPU:恢复上下文(弹栈)
- CPU ->> 原任务:继续执行被中断的代码
1.3 中断补充知识
1.3.1 MCU reset,中断?
- 所有中断都会disabled
- 所有中断赋予优先级值为0(最高优先级)
- 所有中断的状态标志位清零
1.3.2 CPU接收中断请求条件?
- 中断标志位置1
- 中断使能
- 中断优先级大于屏蔽中断优先级
1.4 中断注意点
- 中断屏蔽:通过寄存器(如 PRIMASK)临时关闭中断,保护关键代码(临界区)。
// 关闭所有中断(设置PRIMASK=1) __disable_irq(); // 关闭全局中断 // 临界区操作(如修改全局变量) // 开启中断(设置PRIMASK=0) __enable_irq(); // 恢复中断
- 中断嵌套:高优先级中断可打断低优先级中断(需配置抢占优先级)。
- 中断延迟:从触发中断到执行 ISR 第一条指令的时间,影响实时性。
2. NVIC
2.1 什么是NVIC?
2.1.1 NVIC概念与结构框图
Nested vectored interrupt controller,嵌套向量中断控制器。
-
全局管理所有中断源的优先级、使能和响应
-
处理中断仲裁、跳转到ISR地址等核心操作
-
属于内核级中断管理(Core-Level Control)
-
IRQs(Interrupt Requests,外设中断请求:连接外部外设(如串口、GPIO 等),接收外设发送的中断请求信号。NVIC 根据预设的优先级对多个 IRQ 请求进行仲裁,决定响应顺序。
-
NMI(Non-Maskable Interrupt,非屏蔽中断):优先级最高的中断,用于处理紧急不可屏蔽事件(如电源故障),一旦触发,CPU 必须立即响应。
-
SysTick Timer(系统滴答定时器):内置的定时器,为操作系统或应用程序提供精准的时间基准。与 NVIC 交互,可配置为触发中断,让 CPU 定期执行时间相关的任务(如延时、周期性数据采集)。
-
Processor Core(处理器内核):与 NVIC 通信:接收 NVIC 的中断响应通知,跳转执行中断服务程序。处理System Exceptions(系统异常/内核中断):如复位、硬件错误、总线错误等系统级异常事件,由内核直接管理。
2.1.2 中断向量表(基于STM32F407ZGT6,别的系列中断数可能不同)
关于中断向量表和中断向量号相关,可以参考学习
MCU开发学习记录3 - MAP、启动流程(HAL库)-CSDN博客
-
中断向量表中的内核中断10个(从Reference manual可知)
优先级为负数的
通常reset -> main()
-
中断向量表的外部中断一共有82个
2.2 NVIC相关配置函数(基础版)
2.2.1 NVIC相关配置函数
中断失能:只是阻止NVIC将中断请求传递给CPU(即不执行ISR)。如果有中断发生,中断标志位会保持为1,只能软件手动清除。
1. cortex内核函数
2. HAL库NVIC配置函数(stm32f4xx_hal_cortex.c)
2.2.2 NVIC配置流程
- NVIC进行中断优先级分组(一般都是程序开头就完成了声明)
- NVIC设置中断优先级
- NVIC对应外设使能
- 编写对应外设句柄函数
一般这个函数是调用 HAL库对应外设的ISR
1. 对应外设的ISR有两个作用:清理中断标志位,调用中断回调函数(__weak,用户自定义)
2. 再次清理该中断标志位(此时Callback已经执行完毕) - 编写对应外设的中断回调函数Callback
2.2.3 NVIC中断优先级概念
在STM32的中断优先级配置中,数值越小的中断优先级越高。
NVIC中断优先级分为抢占优先级(Preemption Priority)与子优先级(Subpriority)。
1. 抢占优先级
高抢占优先级的中断可以打断正在执行的低抢占优先级的中断(嵌套中断)。
2. 子优先级
• 仅在同一抢占优先级的中断之间比较。
• 子优先级高的中断会优先执行,但不能打断正在执行的同抢占优先级中断。3. 自然优先级
即在前两者设置相同时,根据自然优先级决定中断顺序。
自然优先级就是中断向量表是序号。
3. NVIC相关寄存器总结(详细介绍)
NVIC:管理 外设中断 和 内核中断 的使能、优先级配置、挂起状态和活动状态。
SCB:本文只对SCB中,中断相关寄存器进行介绍。
管理 系统级控制,如优先级分组、系统异常(内核中断)配置、复位控制等。
3.1 NVIC寄存器
0xE000E100 - 0xE000E11C | Interrupt Set Enable Registers | NVIC->ISER [0] - NVIC->ISER [7] | Write 1 to set enable |
0xE000E180 - 0xE000E19C | Interrupt Clear Enable Registers | NVIC->ICER [0] - NVIC->ICER [7] | Write 1 to clear enable |
0xE000E200 - 0xE000E21C | Interrupt Set Pending Registers | NVIC->ISPR [0] - NVIC->ISPR [7] | Write 1 to set pending status |
0xE000E280 - 0xE000E29C | Interrupt Clear Pending Registers | NVIC->ICPR [0] - NVIC->ICPR [7] | Write 1 to clear pending status |
0xE000E300 - 0xE000E31C | Interrupt Active Bit Registers | NVIC->IABR [0] - NVIC->IABR [7] | Active status bit. Read only. |
0xE000E400 - 0xE000E4EF | Interrupt - Priority Registers | NVIC->IPR [0] - NVIC->IPR [239] | Interrupt - Priority Level (8 - bit wide) for each interrupt |
0xE000EF00 | Software Trigger Interrupt Register | NVIC->STIR | Write an interrupt number to set its pending status |
3.1.1 ISER and ICER(控制外部中断)
对应的函数:
3.1.2 ISPR and ICPR(内核级)
通过ISPR/ICPR,使用NVIC控制器向CPU直接发送中断挂起信号,不需要外部触发。
注:
这种内核级发送中断挂起信号,要成对使用。(平常不使用)
正常:外设中断控制器->NVIC控制器->CPU(也不需要清除挂起标志位,内部清除)
3.1.3 IABR
Active status基础概念:
当处理器启动中断处理程序时,该位被设置为1,并在执行中断返回时被清除。即使在这个过程中被抢断,该位仍置为1。相较于读取ISPR确定中断是否active,在嵌套中断,读取ISPR无法判断该中断是否active。
3.1.4 IPR
使用IPR对外部中断配置优先级。
3.1.5 STIR
STIR用来软件触发中断挂起信号(与ISPR功能一样)
3.2 SCB寄存器
0xE000ED04 | Interrupt Control and State Register | SCB->ICSR | Control and status of system exceptions |
0xE000ED08 | Vector Table Offset Register | SCB->VTOR | Enable the vector table to be relocated to other address location |
0xE000ED0C | Application Interrupt / Reset Control Register | SCB->AIRCR | Configuration for priority grouping, and self - reset control |
0xE000ED18- 0xE000ED23 | System Handler Priority Registers | SCB->SHPR[0]- SCB->SHPR [11] | Exception priority setting for system exceptions |
3.2.1 ICSR
ICSR用于管理和监控系统中断及异常状态。(设计中断调试使用。)
无这种需求,先不了解了。
3.2.2 VTOR(这个就是Bootloader+APP要用到的寄存器)
后续开创一个新专栏做一些小项目,然后会针对这个Bootloader+APP,会写一个文章来说明。
通过修改VTOR的值,可以将默认位于Flash起始地址(0x00000000)的中断向量表重定位到其他内存区域(如SRAM或用户自定义的Flash地址),适应多阶段启动、动态固件更新等场景。
// Bootloader跳转代码示例
void jump_to_user_app(uint32_t user_app_addr) {
// 1. 关闭全局中断
__disable_irq();
// 2. 设置VTOR指向用户程序的向量表(地址需128字对齐)
SCB->VTOR = user_app_addr; // 例如:0x08008000
// 3. 获取用户程序复位向量(用户程序的入口地址)
uint32_t *reset_vector = (uint32_t*)(user_app_addr + 0x04);
// 4. 设置堆栈指针并跳转
__set_MSP(*(uint32_t*)user_app_addr); // 初始化主堆栈指针
void (*user_reset_handler)(void) = (void (*)(void))(*reset_vector);
user_reset_handler(); // 跳转到用户程序
}
3.2.3 AIRCR(10:8)
对于该寄存器只关注[10:8],用来确定中断优先级如何进行分组(分抢占优先级位数和子优先级位数)。
3.2.4 SHPR
SHPR对内部中断进行中断优先级设置。
3.3 NVIC相关函数汇总(HAL库)
4. EXTI
终于写到EXTI了,回忆一下EXTI的全称:External Interrupt/Event Controller。这名字起的真好,直接把作用写了出来。EXTI的作用:一是可以用来作为外部中断使用,二是可以作为外部触发事件使用(这个控制器真不错)。本文针对第一种使用。
下面是这个是正点原子对于中断与事件的描述(说的很好)。
- 中断:要进入NVIC,有相应的中断服务函数,需要CPU处理。
- 事件:不进入NVIC,仅用于内部硬件自动控制的,如:TIM、DMA、ADC。
4.1 什么是EXTI?
4.1.1 EXTI结构框图
4.1.2 EXTI构成
1. EXTI可以产生23个中断/事件请求。
2. 每个EXTI的线,都有自己的触发器和屏蔽器。
3. 每个EXTI的线,都有自己专属的状态位。
4. 但是,不是每个EXTI的线都有专属于自己的中断请求
5. 同时参考手册里说明,EXTI可以捕获比APB时钟周期更短的脉冲(具体需要查看芯片手册),例如UART1(APB2_CLK=84Mhz,11.9ns)
4.2 基于HAL库配置EXTI中断
本文根据MCU开发学习记录4 - GPIO学习与实践(HAL库)-CSDN博客,建立工程继续修改,即使用按键作为外部中断控制LED灯状态反转。
4.2.1 CubeMX配置EXTI中断
- 使能EXIT9引脚
这里一共有六个模式,选择中断模式下降沿触发。
- 使能NVIC对应中断
- cubemx生成代码
4.2.2 EXTI中断初始化流程
- main函数初始化,设置SCB的AIRCR
- GPIO初始化(MCU开发学习记录4 - GPIO学习与实践(HAL库)-CSDN博客)
- 给NVIC配置EXTI中断
- 编写中断服务函数(cubemx会自动把中断服务函数放到stm32f4xx_it.c)
它会自动清除中断标志位
- 编写中断处理回调函数
一般会再回调函数结束时,再清除一次中断标志位
4.2.3 EXTI寄存器基地址
4.2.3 EXTI寄存器介绍
- Interrupt mask register (EXTI_IMR)
-
Event mask register (EXTI_EMR)
-
Rising trigger selection register (EXTI_RTSR)
-
Falling trigger selection register (EXTI_FTSR)
-
Software interrupt event register (EXTI_SWIER)
-
Pending register (EXTI_PR)
4.3 EXTI中断实践
4.3.1 硬件连接
PB9 - KEY0 - GND
4.3.2 用户代码
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == KEY0_Pin)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
}
}
//main()
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// key_val = key_scan(0);
// if (key_val == 1)
// {
// dht11_read_data(&temp, &humi);
// printf("temp:%d\r\n", temp);
// printf("humi:%d\r\n", humi);
// HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
// delay_ms(500);
// }
delay_ms(500);
}
5. 本文相关下载连接
5.1 本文参考资料下载链接
1. Programming manual
https://www.st.com/en/microcontrollers-microprocessors/stm32f407-417/documentation.html
2. Cortex -M4 Devices Generic User Guide Generic User Guide
3. The Definitive Guide to ARM® CORTEX®-M3 and CORTEX®-M4 Processors
https://archive.org/details/cortexr-m4/page/n975/mode/2up
5.2 本文的工程文件下载链接
工程CSDN下载链接:https://download.csdn.net/download/weixin_45483813/90583949?spm=1001.2014.3001.5503
工程Github下载链接:https://github.com/chipdynkid/MCU-DL-STM32
(国内)工程Gitcode下载链接:GitCode - 全球开发者的开源社区,开源代码托管平台