一、EXTI简介
EXTI(External interrupt/event controller)—外部中断/事件控制器,管理了23个中断/事件线。EXTI可以对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及设置触发方式(上升沿或下降沿或者双边沿触发)。每个输入线都可以独立地被屏蔽,也可以挂起保持着状态线的中断请求。
简而言之就是EXTI控制器通过检测外部的电平信号来触发中断或者事件,这里的事件是指产生脉冲信号,可以供给其他外设电路使用。外部的电平信号来自于23个中断/事件线,如下:
EXTI 线0~15:对应外部 GPIO引脚的输入中断。
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 唤醒事件。
EXTI控制器结构见下图。
说明:
(1)输入线可以通过寄存器设置为GPIO引脚或者外设的事件
(2)边沿检测电路以输入线作为信号输入端,根据上升沿触发选择寄存器和下降沿触发选择寄存器的设置来控制信号触发。如果检测到有效边沿跳变信号则输出有效信号1,否则输出无效信号0。
(3)软件中断事件寄存器:可通过该寄存器设置产生中断请求。
(4)中断屏蔽寄存器:可以设置该寄存器是否允许开放中断请求;
事件屏蔽寄存器:设置该寄存器是否允许开放事件请求。
(5)挂起请求寄存器,当外部中断线上发生了选择的边沿事件,该位置1。
二、外部中断线与IO引脚对应关系
F4的IO引脚多达112个,每个GPIO都可以触发一个外部中断,但是GPIO口的外部中断线只有16个(EXTI线0~15),如何把112个引脚和外部中断线联系起来?
GPIO口中断以组为单位,PA0、PB0、PC0、PD0、PE0、PG0、PH0为一组,对应EXTI线0;PA1、PB1、PC1、PD1、PE1、PG1、PH1为一组,对应EXTI线1;同理,PA15、PB15、PC15、PD15、PE15、PG15、PH15为一组,对应EXTI线15。这样就把每个GPIO口同16个EXTI外部中断线一一对应起来了。见下图。
【注】同组同一时间只能用一个GPIO引脚作为外部中断输入线。如果PA0作为外部中断源,那么同组的其它GPIO(PB0、PC0、PD0、PE0、PG0和PH0)就不能再使用,只能使用类似于PB1、PC2这种数字序号不同的引脚作为外部中断源。
图中的SYSCFG_EXTICR1~SYSCFG_EXTICR4寄存器是SYSCFG(系统配置控制器)下的外部中断配置寄存器,用来选择 EXTI外部中断的源输入。
三、EXTI库函数(库函数和相关变量分别定义在stm32f4xx_exti.c/stm32f4xx_exti.h)
经过上面的分析,使用GPIO口作为外部中断输入口,一是需要设置GPIO口与EXTI线的对应关系,即使用哪个IO引脚来作为外部中断输入口;二是设置触发方式,是上升沿触发还是下降沿触发;三是设置为中断或事件;四是EXTI的中断服务函数。
(1)设置GPIO口与EXTI线的对应关系
上面讲过SYSCFG_EXTICR1~SYSCFG_EXTICR4寄存器是SYSCFG系统配置控制器下的外部中断配置寄存器,用来选择 EXTI外部中断的源输入,即设置GPIO 与EXTI中断线的对应关系。
与此对应的库函数为:
void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex)
参数1:EXTI_PortSourceGPIOx为选择GPIO口,x=A~I
参数2:EXTI_PinSourcex为选择的引脚,x=0~15
使用示例:将PA0与EXTI0对应起来
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
【注】由于使用到了SYSCFG系统配置控制器,需要使能系统配置控制器时钟,见下图,在APB2总线下。
开启该时钟的库函数为:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG 时钟
(2)设置触发方式、选择中断或事件模式
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
【注】类比CPIO_Init()、NVIC_Init(),这种初始化库函数传入的参数都是结构体指针。
EXTI的结构体定义如下:
typedefstruct
{
uint32_t EXTI_Line; //选择外部线路,EXTI_Line0~23。
EXTIMode_TypeDef EXTI_Mode; //线路模式。中断/事件
EXTIrigger_TypeDef EXTI_Trigger; //线路的触发模式。上升/下降
FunctionalState EXTI_LineCmd; //使能中断。ENABLE / DISABLE
}EXTI_InitTypeDef;
成员1:EXTI_Line,选择外部中断线路,取值为EXTI_Line0~23
成员2:EXTI_Mode,线路模式,取值为EXTI_Mode_Interrupt中断模式、EXTI_Mode_Event事件模式。
成员3:EXTI_Trigger,线路触发方式,EXTI_Trigger_Falling下降沿触发、EXTI_Trigger_Rising上升沿触发、EXTI_Trigger_Rising_Falling上升下降都触发
成员4:EXTI_LineCmd,使能控制,ENABLE使能 / DISABLE禁止
使用示例:
EXTI_InitTypeDef EXTI_InitStructure; //定义结构体
EXTI_InitStructure.EXTI_Line = EXTI_Line12 | EXTI_Line14;//选择中断线12和14
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;//外部中断使能
EXTI_Init(&EXTI_InitStructure);//完成参数初始化
(3)获取中断标志位函数
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line); //判断中断线中断状态,是否发生
参数:EXTI_Line,取值为EXTI_Line_0~EXTI_Line_23,表示获取某条中断线的中断标志位。
返回值:SET,表示对应的中断线已触发;RESET,表示对应的中断线未触发。
(4)清除中断标志位函数
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);//清除中断线上的中断标志位
参数:EXTI_Line,取值为EXTI_Line_0~EXTI_Line_23,表示清除某条中断线的中断标志位。
(5)中断服务函数
STM32F4 的EXTI中断函数只有7 个,分别为:
【注】EXTI5~EXTI9共用一个中断服务函数名,EXTI10~EXTI15共用一个中断服务函数名。
void EXTI0_IRQHandler(void) //中断线0的中断服务函数
{
if(EXTI_GetITStatus(EXTI_Line0) ! = RESET) //判断EXTI0线上的中断是否发生
{
//执行相关的中断程序
EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE上的中断标志位
}
}
四、使用GPIO口触发外部中断的一般步骤
1.开启时钟(系统配置控制器时钟、GPIO口时钟)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);;
2.初始化IO口为输入模式。
GPIO_Init();
3.设置GPIO与EXTI映射关系
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
4.EXTI初始化
EXTI_InitTypeDef EXTI_InitStructure; //定义结构体
EXTI_InitStructure.EXTI_Line = EXTI_Line0;//选择中断线0
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_Init();
6.编写中断服务函数
具体操作见下篇。

