|
STM32 的EXTI(外部中断 / 事件控制器) 是用于检测外部引脚电平变化并触发中断或事件的外设,支持19 个中断 / 事件线(EXTI0~EXTI15 对应 GPIO 引脚,EXTI16 对应 PVD,EXTI17 对应 RTC 闹钟,EXTI18 对应 USB OTG FS 唤醒,EXTI19 对应以太网唤醒),是 STM32 处理外部硬件触发的核心模块。 一、EXTI 核心特性- 中断与事件分离
- 中断:触发后会向 NVIC(嵌套向量中断控制器)申请中断,执行中断服务函数。
- 事件:仅产生硬件脉冲,用于触发其他外设(如定时器、DMA),不进入 CPU 中断。
- 触发方式:支持上升沿触发、下降沿触发、双边沿触发、软件触发。
- GPIO 映射:EXTI0~EXTI15 可映射到任意 GPIO 端口的对应引脚(如 EXTI0 可映射到 PA0、PB0、PC0…PG0),通过 SYSCFG 寄存器配置。
二、EXTI 中断配置步骤以STM32F103为例(F4/F7/H7 系列配置逻辑类似,仅库函数 / 寄存器命名略有差异),配置 GPIO 引脚触发 EXTI 中断的通用步骤: 1. 开启时钟- 开启GPIO 端口时钟(如 GPIOA)。
- 开启SYSCFG 时钟(EXTI 的引脚映射需要 SYSCFG 支持,F1 系列 SYSCFG 挂载在 APB2 总线上)。
- 开启EXTI 控制器时钟(部分系列 EXTI 时钟由内核自动使能,无需手动开启)。
- // 以STM32F103为例,使用标准库
- #include "stm32f10x.h"
- // 开启GPIOA和SYSCFG时钟
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SYSCFG, ENABLE);
2. 配置 GPIO 为输入模式EXTI 引脚需配置为浮空输入、上拉输入或下拉输入(不可为输出模式)。
- GPIO_InitTypeDef GPIO_InitStruct;
- // 配置PA0为浮空输入
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
- GPIO_Init(GPIOA, &GPIO_InitStruct);
3. 配置 SYSCFG_EXTICR 寄存器,映射 GPIO 引脚到 EXTI 线通过SYSCFG_EXTILineConfig函数将 GPIO 端口映射到对应的 EXTI 线(如 PA0 映射到 EXTI0)。
- // 映射PA0到EXTI0线:参数1=EXTI线,参数2=GPIO端口
- SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
4. 配置 EXTI 中断触发方式和使能通过EXTI_InitTypeDef结构体配置 EXTI 线的触发方式(上升沿 / 下降沿)、中断使能。
- EXTI_InitTypeDef EXTI_InitStruct;
- // 配置EXTI0线
- EXTI_InitStruct.EXTI_Line = EXTI_Line0; // 选择EXTI0线
- EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; // 中断模式(事件模式为EXTI_Mode_Event)
- EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; // 上升沿触发(下降沿:EXTI_Trigger_Falling;双边沿:EXTI_Trigger_Rising_Falling)
- EXTI_InitStruct.EXTI_LineCmd = ENABLE; // 使能EXTI0线
- EXTI_Init(&EXTI_InitStruct);
5. 配置 NVIC,使能 EXTI 中断通道EXTI 中断需通过 NVIC 配置优先级并使能,不同 EXTI 线对应不同的 NVIC 通道:
- EXTI0~EXTI4:分别对应 NVIC 的 EXTI0_IRQn ~ EXTI4_IRQn。
- EXTI5~EXTI9:共享 EXTI9_5_IRQn。
- EXTI10~EXTI15:共享 EXTI15_10_IRQn。
- NVIC_InitTypeDef NVIC_InitStruct;
- // 配置EXTI0中断
- NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; // EXTI0中断通道
- NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级(根据需求设置)
- NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; // 子优先级(根据需求设置)
- NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道
- NVIC_Init(&NVIC_InitStruct);
6. 编写中断服务函数中断服务函数需清除 EXTI 中断标志位(通过EXTI_ClearITPendingBit),否则会反复触发中断。
- // EXTI0中断服务函数(函数名必须与启动文件中的中断向量表一致)
- void EXTI0_IRQHandler(void)
- {
- // 检查EXTI0中断标志位是否置位
- if(EXTI_GetITStatus(EXTI_Line0) != RESET)
- {
- // *************************
- // 此处编写中断处理逻辑(如LED翻转、数据读取)
- // *************************
- EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志位
- }
- }
三、关键注意事项- 引脚映射限制:EXTI 线 n 只能映射到 GPIOx 的 n 号引脚(如 EXTI5 只能映射到 PA5、PB5、PC5 等)。
- 中断标志位清除:必须在中断服务函数中清除 EXTI 的中断挂起位,否则中断会持续触发。
- NVIC 优先级配置:需根据系统中断优先级规则合理设置抢占优先级和子优先级(注意 SCB->AIRCR 寄存器的优先级分组)。
- 软件触发 EXTI:可通过EXTI_GenerateSWInterrupt函数手动触发 EXTI 中断,用于调试或软件模拟硬件触发。
- // 软件触发EXTI0中断
- EXTI_GenerateSWInterrupt(EXTI_Line0);
四、HAL 库配置示例(以 STM32F4 为例)若使用 STM32 HAL 库,配置逻辑更简洁,核心步骤如下:
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- __HAL_RCC_GPIOA_CLK_ENABLE();
- __HAL_RCC_SYSCFG_CLK_ENABLE();
- // 配置PA0为上升沿触发的外部中断
- GPIO_InitStruct.Pin = GPIO_PIN_0;
- GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; // 上升沿中断模式
- GPIO_InitStruct.Pull = GPIO_NOPULL; // 浮空输入
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
- HAL_NVIC_EnableIRQ(EXTI0_IRQn);
- 中断服务函数与回调函数:HAL 库中,中断服务函数调用通用处理函数,最终通过回调函数执行业务逻辑:
- // EXTI0中断服务函数
- void EXTI0_IRQHandler(void)
- {
- HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); // 调用HAL库通用处理函数
- }
- // EXTI回调函数(重写此函数实现业务逻辑)
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
- {
- if(GPIO_Pin == GPIO_PIN_0)
- {
- // 中断处理逻辑
- }
- }
五、EXTI 事件模式简介若配置为事件模式(EXTI_Mode_Event),EXTI 触发后不会向 NVIC 申请中断,而是通过硬件脉冲触发其他外设(如定时器的捕获、DMA 的启动)。配置时只需将EXTI_Mode设为EXTI_Mode_Event,无需配置 NVIC,也无需清除中断标志位。
EXTI 是 STM32 处理外部硬件触发的基础,掌握其配置流程对实现按键中断、传感器触发、外部设备通信等场景至关重要。
|