“ STM32F4xx 的 EXTI 控制器可将 GPIO 或外设信号转换为中断 / 事件触发源,支持上升沿、下降沿或双边沿触发。本文介绍其 23 条中断 / 事件线的映射关系及工作原理,结合按键检测案例,详细阐述外部中断配置流程及中断服务函数实现”
01
—
stm32 EXTI简介
EXTI 是 STM32F4xx 的外部中断/事件控制器,可把 GPIO 或外设信号 变成 中断/事件触发源。EXTI 让任何引脚或外设事件都能瞬间唤醒 CPU 或触发 DMA,实际应用如按键、RTC 闹钟、USB 插拔等实时响应场景。
stm32f4xx共有23 条外部中断/事件线,其中多达 140 个 GPIO(STM32F405xx/07xx 和 STM32F415xx/17xx的GPIOx.0~GPIOx.15 )通过以下方式连接到 16 根外部中断/事件线,触发事件可配置为上升沿触发、下降沿触发或边沿触发。GPIO与外部中断/事件EXTI0~EXTI15 连接关系如下图:
另外7根 EXTI16~EXTI22线连接方式如下:
● EXTI 线 16 连接到 PVD 输出;
● EXTI 线 17 连接到 RTC 闹钟事件;
● EXTI 线 18 连接到 USB OTG FS 唤醒事件;
● EXTI 线 19 连接到以太网唤醒事件;
● EXTI 线 20 连接到 USB OTG HS(在 FS 中配置)唤醒事件;
● EXTI 线 21 连接到 RTC 入侵和时间戳事件;
● EXTI 线 22 连接到 RTC 唤醒事件。
02
—
原理

STM32F4xx 的 EXTI 由 23 条输入线(EXTI0-15 对应 GPIOx.0-15,EXTI16-22 固定映射 PVD/RTC/USB/以太网等外设事件)经 SYSCFG 选择器 后进入每条线上的 上升沿/下降沿检测器(由 EXTI_RTSR/FTSR 配置),检测结果与 软件触发位 EXTI_SWIER 做 OR 运算,随后被 中断屏蔽寄存器 EXTI_IMR 和 事件屏蔽寄存器 EXTI_EMR 分别选通,形成 中断路径和事件路径:中断路径经 与门→请求挂起寄存器 EXTI_PR→NVIC 向 Cortex-M4 申请中断;事件路径直接输出脉冲给 其他外设或 DMA;挂起寄存器 EXTI_PR 用于锁存中断标志,读/写 1 清零复位。整个链路实现“输入→检测→屏蔽→挂起→NVIC/事件”的级联,确保任何引脚或外设事件能在 零 CPU 干预 下唤醒系统或触发后续动作。
03
—
硬件说明
KEY1和KEY2的输出信号直接与stm32的PA0和PC13连接,按下按键使PA0和PC13变为高电平,释放按键使PA0和PC13变为低电平,通过电路设计可以使得按下时产生电平变化。2个GPIO口设置成外部中断、上升沿触发,从而检测到KEY1和KEY2电平变化。
04
—
程序设计案例
程序设计步骤:
1.使能 GPIO 端口时钟 和 SYSCFG 时钟。
2.选择外部中断引脚。
3.设置目标引脚为 输入模式 并选择上拉/下拉。
4.设 EXTI 参数,上升沿中断。
5.配 NVIC 优先级、开启中断 。
6.写中断服务函数。
7.主循环保持空转或执行其他任务,中断触发后由 硬件自动进入服务函数 处理。
main.c
int main(void){ /* 系统时钟初始化成168MHz */ SystemClock_Config(); /* LED 端口初始化 */ LED_GPIO_Config(); /* 初始化EXTI中断,按下按键会触发中断, * 触发中断会进入stm32f7xx_it.c文件中的函数 * KEY1_IRQHandler和KEY2_IRQHandler,处理中断,反转LED灯。 */ EXTI_Key_Config(); /* 等待中断,由于使用中断方式,CPU不用轮询按键 */ while(1) { }}
bsp_led.c
void EXTI_Key_Config(void){ GPIO_InitTypeDef GPIO_InitStructure; /*开启按键GPIO口的时钟*/ KEY1_INT_GPIO_CLK_ENABLE(); KEY2_INT_GPIO_CLK_ENABLE(); /* 选择按键1的引脚 */ GPIO_InitStructure.Pin = KEY1_INT_GPIO_PIN; /* 设置引脚为输入模式 */ GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING; /* 设置引脚不上拉也不下拉 */ GPIO_InitStructure.Pull = GPIO_NOPULL; /* 使用上面的结构体初始化按键 */ HAL_GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure); /* 配置 EXTI 中断源 到key1 引脚、配置中断优先级*/ HAL_NVIC_SetPriority(KEY1_INT_EXTI_IRQ, 0, 0); /* 使能中断 */ HAL_NVIC_EnableIRQ(KEY1_INT_EXTI_IRQ); /* 选择按键2的引脚 */ GPIO_InitStructure.Pin = KEY2_INT_GPIO_PIN; /* 其他配置与上面相同 */ HAL_GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure); /* 配置 EXTI 中断源 到key1 引脚、配置中断优先级*/ HAL_NVIC_SetPriority(KEY2_INT_EXTI_IRQ, 0, 0); /* 使能中断 */ HAL_NVIC_EnableIRQ(KEY2_INT_EXTI_IRQ);}
中断服务函数stm32f4xx_it.c
void KEY1_IRQHandler(void){ //确保是否产生了EXTI Line中断 if(__HAL_GPIO_EXTI_GET_IT(KEY1_INT_GPIO_PIN) != RESET) { // LED1 取反 LED1_TOGGLE; //清除中断标志位 __HAL_GPIO_EXTI_CLEAR_IT(KEY1_INT_GPIO_PIN); } } void KEY2_IRQHandler(void){ //确保是否产生了EXTI Line中断 if(__HAL_GPIO_EXTI_GET_IT(KEY2_INT_GPIO_PIN) != RESET) { // LED2 取反 LED2_TOGGLE; //清除中断标志位 __HAL_GPIO_EXTI_CLEAR_IT(KEY2_INT_GPIO_PIN); } }
05
—
代码链接
工程代码链接:
https://gitee.com/ylm1101111/stm32_basic8.git
0