EXTI由19个产生事件/中断请求的边沿检测器组成(互联型为20个),本篇主要针对前16个,即GPIO口产生的事件/中断请求。

由图中可知,PA0引脚只能由 EXTI0 作为中断/事件线,而不能用其他,对应的引脚只能用对应的中断/事件线。
原理
Cortex-M3内核中配备了 嵌套向量中断控制器 NVIC(Nested vectoredinterrupt controller),用于对所有中断进行分组,并分配优先级(抢占优先级和响应优先级)。

从图中可知,任何一个外设想要产生中断,必须先向 NVIC 发送一个中断请求。NVIC根据中断的优先级来分配中断的执行顺序,随后向内核指令执行单元汇报,内核指令执行单元再从 FLASH 存储的中断向量表中找到对应中断的地址,开始执行相应的程序(即产生一个事件)。
对应于 EXTI 而言,当检测到 GPIO口的 IDR寄存器 产生了上升沿 或 下降沿电平时(具体是上升沿还是下降沿由使用者自己设置决定,也可设置成上升沿和下降沿均可触发),便发送一个中断请求给 NVIC。
NVIC寄存器
注意:STM3210x中最多只有84个中断,其中固定有16个内核中断,所以可屏蔽中断最多有68个
注意:NVIC除IPR寄存器外所有寄存器均有八组,如ISER寄存器,有ISER[0]、ISER[1]、…… 、ISER[7]共8组,每组管理32个中断;而因为stm32f10x的可屏蔽中断最多只有68个,所以只需要用到前三组寄存器,如下图;




-
中断使能寄存器 --- ISER(Interrupt set-enable registers):使能相应的中断;
- 作用---使能中断:位31:0,置 1 时中断使能;
- 复位值:0x0000 0000
-
中断清除使能寄存器 --- ICER(Interrupt clear-enable registers):使能相应的中断;
- 作用---使能中断:位31:0,置 1 时中断使能;
- 复位值:0x0000 0000
-
中断设置挂起寄存器 --- ISPR(Interrupt set-pending registers):将相应的中断挂起;
- 作用---挂起中断:位31:0,置 1 时将相应的中断挂起;
- 复位值:0x0000 0000
-
中断清除挂起寄存器 --- ICPR(Interrupt clear-pending registers):将相应的中断取消挂起状态;
- 作用---清除挂起:位31:0,置 1 时将相应的中断取消挂起状态;
- 复位值:0x0000 0000
-
中断运行标志位寄存器 --- IABR(Interrupt active bit registers):中断是否激活的标志位;
- 作用---读取标志位:位31:0,读取为 1 时表明相应的中断已经激活;
- 复位值:0x0000 0000
-
中断优先级寄存器 --- IPR(Interrupt priority registers):表明中断的优先级;
注意:每有一个中断就有该中断对应的优先级寄存器,cortex-M3允许 低8位(位7:0) 表示优先级,而stm32只用了低4位表示优先级;
-
优先级规则:stm32规定中断有5个抢断优先级分组,需要先配置优先级分组(外设的优先级分组在SCB的AIRCR寄存器中设置),再分配抢断优先级和子优先级;
优先级分组规则 复位值:0x0000 0000
-
软件触发中断寄存器 --- STIR(Software trigger interrupt register):使用软件触发中断;
- 作用---触发中断:低8位(位7:0) 有效,值 为要软件触发的中断的序号;
- 复位值:0x0000 0000
EXTI寄存器
-
中断屏蔽寄存器 --- IMR(Interrupt mask register):屏蔽来自EXTI上的中断请求;
- 作用---屏蔽中断请求:位0:19 ,屏蔽 EXTIx 上的中断请求;(比如位0 置1,则EXTI0 线上的中断请求不被响应)
- 复位值:0x0000 0000
-
事件屏蔽寄存器 --- EMR(Event mask register):屏蔽来自EXTI上的事件请求;
- 作用---屏蔽事件请求:位0:19 ,屏蔽 EXTIx 上的事件请求;(比如位0 置1,则EXTI0 线上的事件请求不被响应,即虽然产生了中断但是该中断对应的程序不被执行)
- 复位值:0x0000 0000
-
上升沿触发选择寄存器 --- RTSR(Rising trigger selection register):允许来自EXTI上的上升沿触发;
- 作用---开启上升沿触发:位0:18 ,允许 EXTIx 上的上升沿触发;
- 复位值:0x0000 0000
-
下降沿触发选择寄存器 --- FTSR(Falling trigger selection register):允许来自EXTI上的下降沿触发;
- 作用---开启下降沿触发:位0:18 ,允许 EXTIx 上的下降沿触发;
- 注意:可同时开启上升沿触发和下降沿触发;
- 复位值:0x0000 0000
-
软件中断事件寄存器 --- SWIER(Software interrupt event register):产生软件中断;
- 作用---产生软件中断:(在IMR和EMR置1的情况下)位0:18 ,在 EXTIx 上产生一个软件中断(软件中断:即GPIO口未检测到边沿电平,人为触发中断);
- 复位值:0x0000 0000
-
挂起寄存器 --- PR(Pending register):标志位,判断事件是否发生;
- 作用---判断事件是否发生:位0:18 ,为 1 则事件发生,为 0 则表示在挂起状态;
- 挂起:当低优先级中断执行时,触发了高优先级中断,则低优先级中断挂起,优先执行高优先级中断,执行完毕后再继续执行低优先级中断;
- 复位值:0x0000 0000
常用NVIC固件库函数(misc.h)
要先使能对应的中断,再配置中断优先级
NVIC优先级分组函数 --- NVIC_PriorityGroupConfig
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
- NVIC_PriorityGroup_x:优先级分组,x 的值可为 (0~4);
NVIC初始化函数 --- NVIC_Init
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
-
NVIC_InitStruct:NVIC_InitTypeDef 结构体
- NVIC_IRQChannel:需要配置的中断,如 EXTI0_IRQn;
- NVIC_IRQChannelPreemptionPriority:抢断优先级的值,根据优先级分组有不同的选择;
-
NVIC_IRQChannelSubPriority:子优先级的值,根据优先级分组有不同的选择;
优先级分组规则
示例:
//创建 NVIC 初始化结构体
NVIC_InitTypeDef NVIC_InitStructure;
//初始化NVIC
//设置优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//选择需要初始化的中断 为 EXTI0
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);
常用EXTI固件库函数(stm32f10x_exti.h 和 stm32f10x_gpio.h)
使用EXTI时仍然要初始化GPIO口,并且要打开AFIO!!!
选择 GPIO 作为 EXTI线 函数 --- GPIO_EXTILineConfig
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
- GPIO_PortSource:对应的 GPIO 端口,如 GPIO_PortSourceGPIOA ;
- GPIO_PinSource:对应的 GPIO 端引脚,如 GPIO_PinSource0;
- 示例:
//选择 GPIOA 口的 Pin0 脚作为 EXTI线
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI初始化函数 --- EXTI_Init
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
-
EXTI_InitStruct:EXTI_InitTypeDef 结构体
- EXTI_Line:选择哪个线设置成EXTI,如EXTI_Line0;
- EXTI_Mode:可以选择EXTI是中断请求还是事件请求,如EXTI_Mode_Interrupt;
- EXTI_Trigger:EXTI的触发方式,如EXTI_Trigger_Rising_Falling(上升沿和下降沿均可触发);
- EXTI_LineCmd:ENABLE 表示使能,DISABLE 表示关闭;
//创建 EXTI 初始化结构体
EXTI_InitTypeDef EXTI_InitStructure;
//初始化EXTI
//选择 Line0 为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(&NVIC_InitStructure);
判断EXTI中断是否挂起函数--- EXTI_GetITStatus
typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
- EXTI_Line:对应的EXTI,如EXTI_Line0;
- 返回值:SET 表示中断未挂起, RESET 表示中断挂起;
- 示例:
//判断 EXTI0 是否被挂起
if( EXTI_GetITStatus(EXTI_Line0) != RESET )
{
//中断未挂起执行的程序
}
EXTI清除中断标志位函数--- EXTI_ClearITPendingBit
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
- EXTI_Line:对应的EXTI,如EXTI_Line0;
- 示例:
//在中断函数末使用;
//清除 EXTI0 标志位;
EXTI_ClearITPendingBit(EXTI_Line0);
