在学习的过程,想到哪里写到哪里,并不仅限EXTI,前后看的东西进行融汇贯通,能更好的理解。
可能理解有所偏差,先暂且这么理解,后面再更正。
首先看EXTI的全称是什么,简单的查了一下EXT应该是external,I应该是interrupt,所以EXTI是external interrupt是外部中断的意思,实际上这是一个STM32提供的一个硬件芯片,芯片当然有寄存器喽,看芯片重点看寄存器的功能。
EXTI实际上的中文名是:外部中断/事件控制器。所以EXTI是用来管理外部中断和事件的。外部中断有82个,EXTI只管理其中的7个,事件的话管理了7个事件,如图1所示。
事件和中断的区别与联系:共同点就是都是对外界的突发事件进行处理,区别就是产生中断会经过cpu处理调用中断处理函数处理然后输出结果,事件完全由内部已设计好的硬件处理然后输出结果。所以中断可编程,事件不可编程只可以获取到输出的结果。
EXTI的物理结构图如图2所示。解释一下23根线,有7根是事件线对应7个事件,有16根是中断线,16个中断线能产生7个中断,其中第一根产生的中断号是6,第二根是7号,第三根是8号,第四根是9号,第五根是10号,第六到第十根都是23号,第11根到第十六根都是40号。具体可查STM32F4XX参考手册的10.1节。EXTI的16根中断线被映射到了GPIO上,具体映射如图3所示。
#define EXTI_BASE (APB2PERIPH_BASE + 0x3C00)
从库函数的代码上可以看出,EXTI寄存器需要使能APB2总线,基址为0x40013C00。大概位置如图4所示。
EXTI自身的寄存器有6个,还涉及到4个SYSCFG的寄存器。
中断屏蔽寄存器(Interrupt mask register):
23根线,写0就屏蔽中断,写1不屏蔽。屏蔽中断用的,后面7根事件线的用不到。
事件屏蔽寄存器(Event mask register):
23根线,写0就屏蔽事件,写1不屏蔽。屏蔽事件用的,前面16根中断线的用不到。
上升沿触发选择寄存器(Rising trigger selection register):
写0:禁止上升沿触发。写1:允许上升沿触发。
下降沿触发选择寄存器(Falling trigger selection register):
写0:禁止下降沿触发。写1:允许下降沿触发。
挂起寄存器(Pending register):
写1:清除产生的中断。若不清除中断产生后将会一直执行中断处理函数。
这个寄存器要好好说道说道,这个寄存器是EXTI中中断流经的最后一个寄存器, 该寄存器有23个位,只说低16位,这个寄存器中的值是会被循环检测的,如果检测到比如PR0为1,PR0连的第一根中断线,那么就会触发6号外部中断,调用对应的处理函数,处理完成后,由于是循环检测检测到PR0若还是为1,那么将会继续执行6号外部中断的处理函数,所以相当于一次中断过后会一直反复执行中断处理函数,若想一次中断就执行一次,在中断处理函数中需要将对应的位清0,清0的方式是写1,rc_w1的含义为可读可写,写1为0。
SYSCFG 外部中断配置寄存器 1(SYSCFG external interrupt configuration register 1):
SYSCFG 外部中断配置寄存器 2(SYSCFG external interrupt configuration register 2):
SYSCFG 外部中断配置寄存器 3(SYSCFG external interrupt configuration register 3):
SYSCFG 外部中断配置寄存器 4(SYSCFG external interrupt configuration register 4):
这几个寄存器功能一样,一起说,基址也很容易找到,功能是配置EXTI的16根中断线与112的GPIO引脚的映射关系,比如EXTI0可以映射到GPIOA0 ,GPIOB0 ,GPIOC0 ,GPIOD0 ,GPIOE0 ,GPIOF0 ,GPIOG0 ,GPIOH0,GPIOI0其中的一个。1个 SYSCFG外部中断配置寄存器可以设置4根线的映射,那么4个就可以设置16根中短线的映射了。
与EXTI相关的代码在stm32f4xx_exti.c和stm32f4xx_exti.h中。
函数原型:
/*
EXTI_PortSourceGPIOx:GPIO的组号,比如GPIOA。
EXTI_PinSourcex:指出映射到EXTI16个中断线的哪根线,注意不同的线可能会对应不同的中断处理函数。比如第一根线是6号外部中断,第二根线是7号外部中断。
*/
void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex);
相关数据结构和宏:
//这就是上面函数原型的参数1
#define EXTI_PortSourceGPIOA ((uint8_t)0x00)
#define EXTI_PortSourceGPIOB ((uint8_t)0x01)
#define EXTI_PortSourceGPIOC ((uint8_t)0x02)
#define EXTI_PortSourceGPIOD ((uint8_t)0x03)
#define EXTI_PortSourceGPIOE ((uint8_t)0x04)
#define EXTI_PortSourceGPIOF ((uint8_t)0x05)
#define EXTI_PortSourceGPIOG ((uint8_t)0x06)
#define EXTI_PortSourceGPIOH ((uint8_t)0x07)
#define EXTI_PortSourceGPIOI ((uint8_t)0x08)
#define EXTI_PortSourceGPIOJ ((uint8_t)0x09)
#define EXTI_PortSourceGPIOK ((uint8_t)0x0A)
//这是参数2
#define EXTI_PinSource0 ((uint8_t)0x00)
#define EXTI_PinSource1 ((uint8_t)0x01)
#define EXTI_PinSource2 ((uint8_t)0x02)
#define EXTI_PinSource3 ((uint8_t)0x03)
#define EXTI_PinSource4 ((uint8_t)0x04)
#define EXTI_PinSource5 ((uint8_t)0x05)
#define EXTI_PinSource6 ((uint8_t)0x06)
#define EXTI_PinSource7 ((uint8_t)0x07)
#define EXTI_PinSource8 ((uint8_t)0x08)
#define EXTI_PinSource9 ((uint8_t)0x09)
#define EXTI_PinSource10 ((uint8_t)0x0A)
#define EXTI_PinSource11 ((uint8_t)0x0B)
#define EXTI_PinSource12 ((uint8_t)0x0C)
#define EXTI_PinSource13 ((uint8_t)0x0D)
#define EXTI_PinSource14 ((uint8_t)0x0E)
#define EXTI_PinSource15 ((uint8_t)0x0F)
使用示例:
//将GPIOA0连接到第一根中断线
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
结构体:
typedef struct{
uint32_t EXTI_Line; //选择23根线中的一根
EXTIMode_TypeDef EXTI_Mode; //选择是配置中断还是事件,设置这里在初始化的时候将会去寻找对应的中断或事件的寄存器进行配置
EXTITrigger_TypeDef EXTI_Trigger; //上升还是下降沿触发(涉及两个寄存器)
FunctionalState EXTI_LineCmd; //屏蔽寄存器,是中断还是事件屏蔽由EXTI_Mode决定。 ENABLE使能,DISABLE屏蔽。
}EXTI_InitTypeDef;
相关数据结构和宏:
//这里就是上面EXTI初始化结构体的第一个参数的可选值
#define EXTI_Line0 ((uint32_t)0x00001) /*!< External interrupt line 0 */
#define EXTI_Line1 ((uint32_t)0x00002) /*!< External interrupt line 1 */
#define EXTI_Line2 ((uint32_t)0x00004) /*!< External interrupt line 2 */
#define EXTI_Line3 ((uint32_t)0x00008) /*!< External interrupt line 3 */
#define EXTI_Line4 ((uint32_t)0x00010) /*!< External interrupt line 4 */
#define EXTI_Line5 ((uint32_t)0x00020) /*!< External interrupt line 5 */
#define EXTI_Line6 ((uint32_t)0x00040) /*!< External interrupt line 6 */
#define EXTI_Line7 ((uint32_t)0x00080) /*!< External interrupt line 7 */
#define EXTI_Line8 ((uint32_t)0x00100) /*!< External interrupt line 8 */
#define EXTI_Line9 ((uint32_t)0x00200) /*!< External interrupt line 9 */
#define EXTI_Line10 ((uint32_t)0x00400) /*!< External interrupt line 10 */
#define EXTI_Line11 ((uint32_t)0x00800) /*!< External interrupt line 11 */
#define EXTI_Line12 ((uint32_t)0x01000) /*!< External interrupt line 12 */
#define EXTI_Line13 ((uint32_t)0x02000) /*!< External interrupt line 13 */
#define EXTI_Line14 ((uint32_t)0x04000) /*!< External interrupt line 14 */
#define EXTI_Line15 ((uint32_t)0x08000) /*!< External interrupt line 15 */
#define EXTI_Line16 ((uint32_t)0x10000) /*!< External interrupt line 16 Connected to the PVD Output */
#define EXTI_Line17 ((uint32_t)0x20000) /*!< External interrupt line 17 Connected to the RTC Alarm event */
#define EXTI_Line18 ((uint32_t)0x40000) /*!< External interrupt line 18 Connected to the USB OTG FS Wakeup from suspend event */
#define EXTI_Line19 ((uint32_t)0x80000) /*!< External interrupt line 19 Connected to the Ethernet Wakeup event */
#define EXTI_Line20 ((uint32_t)0x00100000) /*!< External interrupt line 20 Connected to the USB OTG HS (configured in FS) Wakeup event */
#define EXTI_Line21 ((uint32_t)0x00200000) /*!< External interrupt line 21 Connected to the RTC Tamper and Time Stamp events */
#define EXTI_Line22 ((uint32_t)0x00400000) /*!< External interrupt line 22 Connected to the RTC Wakeup event */
#define EXTI_Line23 ((uint32_t)0x00800000) /*!< External interrupt line 23 Connected to the LPTIM Wakeup event */
//第二个字段的可选参数
typedef enum{
EXTI_Mode_Interrupt = 0x00, //中断
EXTI_Mode_Event = 0x04 //事件
}EXTIMode_TypeDef;
//第三个字段的可选参数
typedef enum{
EXTI_Trigger_Rising = 0x08, //上升沿触发
EXTI_Trigger_Falling = 0x0C, //下降沿触发
EXTI_Trigger_Rising_Falling = 0x10 //上升下降都触发
}EXTITrigger_TypeDef;
使用示例:
EXTI_InitTypeDef EXTI_InitStructure; //申请结构体
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); //初始化第一根线的中断
EXTI_InitStructure.EXTI_Line = EXTI_Line1; //选择第二根中断线
EXTI_Init(&EXTI_InitStructure); //初始化第二根线的中断配置都与第一根线一样