一、外部中断核心概念
EXTI (External Interrupt/Event Controller) 是STM32的外部中断/事件控制器,用于管理外部中断触发。NVIC (Nested Vectored Interrupt Controller) 负责中断优先级管理和中断服务函数(ISR)的路由。
1.1 EXTI与GPIO映射关系
STM32的EXTI线(0-15)对应GPIO引脚号,但同一时刻每个EXTI线只能绑定到一个GPIO端口。映射规则如下:
EXTI线 | 支持的GPIO引脚 | 中断通道(IRQn) | 中断号 |
---|---|---|---|
EXTI0 | PA0, PB0, PC0, …, Px0 | EXTI0_IRQn | 6 |
EXTI1 | PA1, PB1, PC1, …, Px1 | EXTI1_IRQn | 7 |
… | … | … | … |
EXTI15 | PA15, PB15, PC15, …, Px15 | EXTI15_10_IRQn | 40 |
关键规则:
- EXTI线编号 = GPIO引脚号(如PA3使用EXTI3)
- 同一EXTI线可被多个GPIO端口复用(需通过配置选择具体端口)
- 不同EXTI线对应不同的中断通道和中断号
二、外部中断配置步骤(以PA0为例)
2.1 GPIO初始化
1
2
3
4
5
6
7
8
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入(按键接地时使用)
// GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD; // 下拉输入(按键接电源时使用)
GPIO_Init(GPIOA, &GPIO_InitStruct);
2.2 配置EXTI中断线
1
2
3
4
5
6
7
8
9
10
11
EXTI_InitTypeDef EXTI_InitStruct;
// 绑定PA0到EXTI0线
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发(按键按下)
// EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; // 上升沿触发(按键释放)
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
2.3 配置NVIC中断优先级
1
2
3
4
5
6
7
8
9
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 优先级分组(根据需求选择)
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; // 中断通道为EXTI0
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; // 子优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
2.4 编写中断服务函数(ISR)
1
2
3
4
5
6
7
void EXTI0_IRQHandler(void) {
if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
// 处理按键中断逻辑
EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志
}
}
三、关键结构体解析
3.1 EXTI_InitTypeDef结构体
1
2
3
4
5
6
typedef struct {
uint32_t EXTI_Line; // 中断/事件线
EXTIMode_TypeDef EXTI_Mode; // EXTI模式:中断或事件
EXTITrigger_TypeDef EXTI_Trigger; // 触发类型:上升沿/下降沿/双边沿
FunctionalState EXTI_LineCmd; // EXTI线使能/禁用
} EXTI_InitTypeDef;
3.2 NVIC_InitTypeDef结构体
1
2
3
4
5
6
typedef struct {
uint8_t NVIC_IRQChannel; // 中断源
uint8_t NVIC_IRQChannelPreemptionPriority; // 抢占优先级
uint8_t NVIC_IRQChannelSubPriority; // 子优先级
FunctionalState NVIC_IRQChannelCmd; // 中断使能/禁用
} NVIC_InitTypeDef;
四、外部中断系统架构
EXTI控制器支持19个中断/事件线,其中EXTI0-EXTI15用于GPIO输入,其他线用于特定外设事件。外部中断处理流程包括:GPIO输入检测→EXTI边沿检测→NVIC优先级仲裁→CPU执行中断服务函数。
五、中断优先级分组
STM32中断优先级分为抢占优先级和子优先级,通过NVIC_PriorityGroupConfig()函数配置分组:
组 | AIRCR[10:8] | bit[7:4]分配情况 | 分配结果 |
---|---|---|---|
0 | 111 | 0:4 | 0位抢占优先级,4位响应优先级 |
1 | 110 | 1:3 | 1位抢占优先级,3位响应优先级 |
2 | 101 | 2:2 | 2位抢占优先级,2位响应优先级 |
3 | 100 | 3:1 | 3位抢占优先级,1位响应优先级 |
4 | 011 | 4:0 | 4位抢占优先级,0位响应优先级 |
六、多中断线共享处理
EXTI5-9共享EXTI9_5_IRQn中断通道,EXTI10-15共享EXTI15_10_IRQn中断通道。在中断服务函数中需判断具体中断线:
1
2
3
4
5
6
7
8
9
10
11
12
13
void EXTI15_10_IRQHandler(void) {
if (EXTI_GetITStatus(EXTI_Line13) != RESET) {
// 处理EXTI13中断
EXTI_ClearITPendingBit(EXTI_Line13);
}
if (EXTI_GetITStatus(EXTI_Line14) != RESET) {
// 处理EXTI14中断
EXTI_ClearITPendingBit(EXTI_Line14);
}
}
七、调试注意事项
-
中断不触发检查:
- GPIO和AFIO时钟是否使能
- GPIO_EXTILineConfig映射是否正确
- EXTI_LineCmd是否设为ENABLE
- NVIC中断是否使能
-
按键消抖处理:
- 硬件消抖:并联0.1μF电容
- 软件消抖:在ISR中延时10-20ms后再次检测电平
-
中断标志清除:
- 必须在ISR中调用EXTI_ClearITPendingBit()清除标志
- 未清除标志会导致中断持续触发
八、应用场景
外部中断广泛应用于:
- 按键输入检测
- 传感器信号触发
- 外部设备唤醒
- 紧急事件处理
通过合理配置外部中断,可以显著提高系统对外部事件的响应速度和实时性。