STM32 中 EXTI 和 NVIC 是什么?为什么配置中断时两个都要配置?
一、前言
在学习 STM32 外部中断时,经常会看到这样的配置流程:
GPIO_Init(...);
GPIO_EXTILineConfig(...);
EXTI_Init(...);
NVIC_Init(...);
很多初学者会疑惑:
明明我只是想让一个按键触发中断,为什么既要配置 EXTI,又要配置 NVIC?
其实,EXTI 和 NVIC 都和中断有关,但它们负责的层次不同。
一句话理解:
EXTI:负责检测外部中断事件
NVIC:负责管理 CPU 是否响应这个中断
也就是说:
EXTI 负责“中断从哪里来”
NVIC 负责“CPU 要不要处理它”
二、EXTI 是什么?
EXTI 的全称是:
External Interrupt/Event Controller
外部中断/事件控制器
它主要用于检测外部引脚上的电平变化,比如:
上升沿
下降沿
上升沿和下降沿
例如,一个按键连接在 PB14 上,当按键按下时,PB14 的电平发生变化,EXTI 就可以检测到这个变化,并产生中断请求。
比如配置 PB14 为下降沿触发中断:
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line14;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
这段代码的意思是:
配置 EXTI14 这条外部中断线
工作模式是中断模式
触发方式是下降沿触发
使能这条 EXTI 中断线
所以,EXTI 主要解决的问题是:
哪个外部引脚触发中断?
通过哪条 EXTI 线触发?
上升沿触发还是下降沿触发?
是否允许这条 EXTI 线产生中断请求?
三、NVIC 是什么?
NVIC 的全称是:
Nested Vectored Interrupt Controller
嵌套向量中断控制器
它是 ARM Cortex-M 内核中的中断管理器。
STM32 中的中断源有很多,比如:
EXTI 外部中断
TIM 定时器中断
USART 串口中断
ADC 中断
DMA 中断
SPI 中断
I2C 中断
这些中断最终都要交给 NVIC 管理。
NVIC 主要负责:
是否允许某个中断进入 CPU
设置中断优先级
多个中断同时发生时,决定先处理谁
管理中断嵌套
例如配置 EXTI15_10 中断通道:
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
这段代码的意思是:
使能 EXTI15_10 这个中断通道
设置抢占优先级为 1
设置响应优先级为 1
允许 CPU 响应这个中断
所以,NVIC 主要解决的问题是:
这个中断 CPU 允不允许响应?
这个中断优先级是多少?
多个中断同时来了先执行谁?
这个中断能不能打断其他中断?
四、EXTI 和 NVIC 的区别
可以用一张表来理解:
| 对比项 | EXTI | NVIC |
|---|---|---|
| 全称 | External Interrupt/Event Controller | Nested Vectored Interrupt Controller |
| 中文名 | 外部中断/事件控制器 | 嵌套向量中断控制器 |
| 所属位置 | STM32 外设部分 | ARM Cortex-M 内核部分 |
| 负责内容 | 检测外部引脚触发事件 | 管理 CPU 是否响应中断 |
| 主要配置 | 中断线、触发边沿、中断/事件模式 | 中断通道、优先级、使能 |
| 作用对象 | GPIO 外部中断线 | 所有中断源 |
| 举例 | EXTI_Line14 | EXTI15_10_IRQn |
简单来说:
EXTI 管的是外部中断的“触发条件”
NVIC 管的是 CPU 对中断的“响应规则”
五、为什么配置中断时 EXTI 和 NVIC 都要配置?
一个完整的中断过程需要两步:
第一步:外设产生中断请求
第二步:CPU 响应中断请求
EXTI 负责第一步:
检测到 PB14 发生下降沿
产生 EXTI14 中断请求
NVIC 负责第二步:
允许 EXTI15_10_IRQn 这个中断通道进入 CPU
然后 CPU 执行中断服务函数
如果只配置 EXTI,不配置 NVIC:
EXTI 能检测到外部中断事件
但是 CPU 不会进入中断服务函数
如果只配置 NVIC,不配置 EXTI:
CPU 虽然允许响应这个中断通道
但是 EXTI 没有产生中断请求
所以中断也不会发生
因此,配置外部中断时,EXTI 和 NVIC 必须同时配置。
六、以 PB14 按键中断为例
假设按键连接在 PB14 上,希望按键按下时触发外部中断。
完整的中断路径如下:
PB14 引脚电平变化
↓
AFIO 将 PB14 映射到 EXTI14
↓
EXTI14 检测下降沿
↓
EXTI 产生中断请求
↓
NVIC 接收 EXTI15_10_IRQn 中断请求
↓
CPU 暂停当前程序
↓
进入 EXTI15_10_IRQHandler()
↓
执行中断服务函数
这里要注意一点:
PB14 对应的是 EXTI_Line14
但是中断通道是 EXTI15_10_IRQn
中断服务函数是 EXTI15_10_IRQHandler
原因是 STM32 把 EXTI10 到 EXTI15 合并到了同一个中断通道里:
EXTI10
EXTI11
EXTI12
EXTI13
EXTI14
EXTI15
↓
EXTI15_10_IRQn
↓
EXTI15_10_IRQHandler()
所以在中断服务函数中,需要判断到底是哪一条 EXTI 线触发的中断。
七、PB14 外部中断配置示例
下面是一个基于 STM32F10x 标准外设库的 PB14 外部中断配置示例。
1. GPIO 和 AFIO 配置
void ExtiKey_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 1. 开启 GPIOB 和 AFIO 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
// 2. 配置 PB14 为上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 3. 将 PB14 映射到 EXTI14
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
// 4. 配置 EXTI14
EXTI_InitStructure.EXTI_Line = EXTI_Line14;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
// 5. 配置 NVIC
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
2. 中断服务函数
void EXTI15_10_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line14) == SET)
{
// 这里写按键按下之后要执行的代码
// 清除中断挂起标志位
EXTI_ClearITPendingBit(EXTI_Line14);
}
}
这里有一个非常重要的细节:
EXTI_ClearITPendingBit(EXTI_Line14);
这句代码必须写。
因为中断发生后,EXTI 的挂起标志位会被置位。如果不清除这个标志位,程序可能会一直重复进入中断服务函数。
八、GPIO、AFIO、EXTI、NVIC 的关系
配置外部中断时,通常需要配置四个部分:
GPIO:配置引脚输入模式
AFIO:把 GPIO 引脚映射到 EXTI 线
EXTI:配置中断线和触发方式
NVIC:配置中断通道和优先级
以 PB14 为例:
GPIO:把 PB14 配置成上拉输入
AFIO:把 PB14 连接到 EXTI14
EXTI:配置 EXTI14 为下降沿触发
NVIC:打开 EXTI15_10_IRQn 中断通道
完整关系如下:
PB14
↓
GPIO 输入模式
↓
AFIO 映射到 EXTI14
↓
EXTI14 检测下降沿
↓
NVIC 管理 EXTI15_10_IRQn
↓
CPU 执行 EXTI15_10_IRQHandler()
九、为什么 PB14 对应 EXTI14?
STM32 的 EXTI 线和 GPIO 引脚编号是一一对应的。
例如:
PA0 / PB0 / PC0 / PD0 对应 EXTI0
PA1 / PB1 / PC1 / PD1 对应 EXTI1
PA2 / PB2 / PC2 / PD2 对应 EXTI2
...
PA14 / PB14 / PC14 / PD14 对应 EXTI14
所以:
PB14 对应 EXTI_Line14
PC13 对应 EXTI_Line13
PA0 对应 EXTI_Line0
但是需要注意:
同一条 EXTI 线同一时间只能连接一个 GPIO 端口
也就是说,EXTI14 可以选择连接 PA14,也可以选择连接 PB14,也可以选择连接 PC14,但不能同时连接多个。
例如:
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
这句代码的意思是:
把 GPIOB 的 Pin14,也就是 PB14,连接到 EXTI14
十、总结
EXTI 和 NVIC 的核心区别是:
EXTI:负责检测外部中断触发条件
NVIC:负责管理 CPU 是否响应中断
配置外部中断时,两个都要配置:
EXTI 不配置:没有中断请求
NVIC 不配置:CPU 不响应中断
外部中断的完整流程可以总结为:
GPIO 输入配置
↓
AFIO 外部中断线映射
↓
EXTI 配置触发方式
↓
NVIC 配置中断优先级
↓
编写中断服务函数
用生活中的例子理解:
EXTI 像门铃检测器,负责发现有人按门铃;
NVIC 像大脑的调度器,负责决定是否去处理这个门铃事件。
所以,EXTI 和 NVIC 不是重复配置,而是分别负责中断系统的不同环节。只有 EXTI 产生中断请求,并且 NVIC 允许 CPU 响应,中断服务函数才会真正执行。
更多推荐


所有评论(0)