7.1 简介
7.1.1 概述
每个EXTI线都可以单独进行配置,以选择请求类型和相应的触发事件(上升沿触发、下降沿触发和双边沿触发)。
EXTI可以是用户处理一些自定义的紧急事件,从而及时的有针对性的处理特殊事件。(比如温度电路检测,说白了也就是:
每个外部中断线可以独立的配置触发方式(上升沿,下降沿或者双边沿触发),触发/屏蔽,专用的状态位。
)
操作图示就是这样的如图1:
通过外部信号触发一个中断,从而启动一个对应于外部信号的服务。
具体的可以有一下两种作用:
1、STM32F4的每个IO都可以作为外部中断输入。
2、STM32F4的中断控制器支持22个外部中断/事件
EXTI可以处理23个事件:
EXTI线0~15:对应外部IO口的输入中断。
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唤醒事件。
7.1.2 结构
1.中断请求
请求信号通过下图中的①②③④⑤的路径向NVIC产生中断请求。
对于每个中断线,我们可以设置相应的触发方式(上升沿触发,下降沿触发,边沿触发)以及使能。
EXTI有两种功能:产生中断请求和触发事件。
请求信号通过上图中的①②③④⑤的路径向NVIC产生中断请求。
图中,
①是EXTI线。
②是边沿检测电路,可以通过上升沿触发选择寄存器(EXTI RTSR)和下降沿触发选择寄存器(EXTIFTSR)选择输入信号检测的方式——上升沿触发、下降沿触发和上升沿下降沿都能触发(双沿触发)。
③是一个或门,它的输入是边沿检测电路输出和软件中断事件寄存器(EXTISWIER),也就是说外部信号或人为的软件设置都能产生一个有效的请求。
④是一个与门,在此它的作用是一个控制开关,只有中断屏蔽寄存器(EXTI_IMR)相应位被置位,才能允许请求信号进入下一步。
⑤在中断被允许的情况下,请求信号将挂起请求寄存器(EXTIPR)相应位置位,表示有外部中断请求信号。之后,挂起请求寄存器相应位置位,在条件允许的情况下,将通知NVIC产生相应中断通道的激活标志。
2、触发事件
请求信号通过图中的①②③⑥⑦的路径产生触发事件。
图中,
⑥是一个与门,它是触发事件的控制开关,当事件屏蔽寄存器(EXTI_EMR)相应位被置位时,它将向脉冲发生器输出一个信号,使得脉冲发生器产生一个脉冲,触发某个事件。
例如,可以将EXTI线I1和EXTI线15分别作为ADC的注入通道和规则通道的启动触发信号。
⑦是一个脉冲发生器电路,当它的输入端,即编号 ⑥ 电路的输出端,是一个有效
信号 ① 时就会产生一个脉冲;如果输入端是无效信号就不会输出脉冲。
7.1.3 GPIO相关EXTI线
XTI线0~15的请求信号通过GPIO引脚输入到芯片内部。每一根EXTI线,由Pxy(x是GPIO端口号,y是引脚号)作为输入引脚,引脚的选择由 SYSCFG_EXTICR1~SYSCFG_EXTICR4来控制。EXTI线如图:
GPIOx.0映射到EXTI0
GPIOx.1映射到EXTI1
…
GPIOx.15映射到EXTI15
另外七根 EXTI 线连接方式如下:
● 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 唤醒事件
外部中断服务1、16个中断线没有对应16个独立的中断服务;
2、IO口外部中断在中断向量表中只分配了7个中断向量,也就是 只能使用7个中断服务函数
3、
外部中断线5~9分配一个中断向量,共用一个服务函数;
外部中断线10~15分配一个中断向量,共用一个中断服务函数。
4、中断服务函数列表
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
EXTI9_5_IRQHandler
EXTI15_10_IRQHandler
7.2典型应用步骤及常用库函数
7.2.1 典型应用步骤
7.2.2 常用库函数
与EXTI相关的函数和宏都被定义在以下两个文件中。
头文件:stm32f4xx_exti.h.
源文件:stm32f4xx_exti.c.
1.设置GPIO引脚与EXTI线的映射函数
void SYSCFG_EXTILineConfig(uint8_t EXTI_PorlSourceGPIOx, uint8_t EXTI _PinSourcex),参数I: uint8_tEXTI_PortSoureeGPIOx,选择的GPIO端口,以宏定义形式定义在stm32f4xx_syscfg.h文件中。例如:Fdefine EXTI_PortSourceGPIOA ((uint8_t)0x00)#define EXTI_PortSourceGPIOB ((uint8_t)0x01)#define EXTI_PortSourceGPIOC ((uint8_t)0x02);.....adefine EXTI_PortSourceGPIOK ((uint8_t)0x0A)参数2: uint8_tEXTI_PinSourcex,选择的引脚号,以宏定义形式定义在stm32f4xx_syscfgh文件中。例如:#define EXTI_PinSource0 ((uint8_t)0x00)#define EXTI_PinSourcel ((uint8_t)0x01)#define EXTI_PinSource2 ((uint8_t)0x02);.....#define EXTI PinSourccl5 ((uint8_t)0x0F)例如,将GPIOE的2号引脚作为EXTI线2的信号输入引脚。SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2):
2.初始化EXTI线(选择中断源、中断模式、触发方式、使能等)函数
void EXTI_ Init(EXTI_ InitTypeDef" EXTI_ InitStruct);参数:EXTI_InitTypeDef*EXTI_InitStruct,EXTI初始化结构体指针,定义在stm32fxx_exti.h文件中。例如:typedef struct{uunt12_t EXTI_L.ine; //指定要配置的EXT1线EATIMode_ TypeDef EXTI_ Mode;//中断模式:事件或中断ENTITrigger_TypeDef EXTI_Trigger: ///触发方式:上升沿/下降沿/双边沿触发FunctionalState EXTI_LineCmd; ///使能成禁止}EXTl_InitTypeDef;成员l:uint32_t EXTI_Line.指定要配置的EXTI线,以宏定义形式定义在stm32f4xx_exih文件中、例如:#define EXTI_ Line0 ((uint32_t)0x00001)#define EXTI Line22 ((uint32_t)0x00400000)成员2:EXTIMode_TypeDef EXTI_Mode,模式(事件或中断)选择,以枚举形式定义在stm32f4xx_exti.h文件中。例如:typedef enumEXTI_Mode_Interrupt=Ox00,EXTI_Mode_Event=0x041EXTIMode_TypeDef;成员3:EXTITrigger_TypeDef EXTI_Trigger,选择触发方式,有三种方式:上升沿、下降沿和双边沿触发,以枚举形式定义在stm32f4xx_exti.h文件中。例如:typedef enum{EXTI_Trigger_Rising=0x08,EXTI_Trigger_Falling=0x0C.EXTI_Trigger_Risíng_Falling=0x10}EXTITrigger_TypeDef:
具体的看图:如下图说明了配置过程以及介绍:
7.3 举个例子
要求:
按照图中的控制电路,编写程序将PA0配置为外部中断输入,将中断输入触发方式配置为上升沿触发,并编写中断服务程序,实现LED灯的控制。检测到按键动作将LED灯状态反转(忽略去抖动操作)。
1.编程要点
(1)使能GPIOA时钟和SYSCFG时钟。调用函数:
RCC_AHB1PeriphClockCmd();
(2)初始化PA0为输入模式。
(3)设置EXTI线0的工作模式、触发方式和使能。
(4)设置NVIC中断组和EXTI线0中断通道的优先级和使能状态。
(5)编写中断服务程序。需要判断中断线状态,在确认后,清除中断挂起标志。添加一个函数
RCC_APB2PeriphClockCmd();
2-主程序:
int main(void){ /* LED 端口初始化 */ LED_Config(); /* 初始化EXTI中断,按下按键会触发中断, * 触发中断会进入stm32f4xx_it.c文件中的函数,反转LED灯。 */ EXTI_Key_Config(); /* 等待中断,由于使用中断方式,不用扫描按键 */ while(1) { }}
在函数中,首先初始化LED灯的GPIO引脚,然后初始化EXTI中断相关所有内容,最后在while(1)的空循环中等待中断。
3.EXTI中断初始化函数
void EXTI_Key_Config(void){ GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; //-------------------第一步-------------------- /*开启按键GPIO口的时钟*/ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA ,ENABLE); /* 使能 SYSCFG 时钟 ,使用GPIO外部中断时必须使能SYSCFG时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //-------------------第二步-------------------- /* 选择按键1的引脚 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; /* 设置引脚为输入模式 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; /* 设置引脚不上拉也不下拉 */ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; /* 使用上面的结构体初始化按键 */ GPIO_Init(GPIOA, &GPIO_InitStructure); //-------------------第三步-------------------- /* 连接 EXTI 中断源 到key1引脚 */ SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0); //-------------------第四步-------------------- /* 选择 EXTI 中断源 */ EXTI_InitStructure.EXTI_Line = EXTI_Line0; /* 中断模式 */ EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; /* 上升沿触发 */ EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; /* 使能中断/事件线 */ EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); //-------------------第五步-------------------- /*配置NVIC为优先级组1,保证整个程序使用的中断处于同一组*/ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); /*配置中断源:按键1*/ NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; /*配置抢占优先级:1*/ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; /*配置响优先级:1*/ NVIC_InitStructure.NVIC_IRQChannelSubPriority=1; /*使能中断通道*/ NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); //----------其他的外部中断 配置过程一样---------------} //初始化结束
4.中断服务程序