(一)EXTI简介
外部中断/事件控制器(EXTI)由20个产生事件/中断请求的边沿检测器组成,对于其它 产品,则有19个能产生事件/中断请求的边沿检测器。每个输入线可以独立地配置输入类型(脉冲 或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以独立地被屏 蔽。挂起寄存器保持着状态线的中断请求。
(二)EXTI主要特性
● 每个中断/事件都有独立的触发和屏蔽
● 每个中断线都有专用的状态位
● 支持多达20个软件的中断/事件请求
● 检测脉冲宽度低于APB2时钟宽度的外部信号。
● 系统控制寄存器的实现; 嵌套向量中断控制器(NVIC)和处理器核的接口紧密相连,可以实现低延迟的中断处理和高效地 处理晚到的中断。
(三)外部中断/事件控制器框图
通过该图我们可以发现如果想产生一个中断,必须在EXTI的初始化前先配置好并使能中断线(也就是初始化GPIO口,并且通过AFIO将外部中断线映射到GPIO引脚),接着设置好触发选择寄存器(上升沿/下降沿)。
注:
上升沿触发:数字电平从低电平(数字“0”)变为高电平(数字“1”)的那一瞬间叫作上升沿。 上升沿触发是当信号有上升沿时的开关动作,当电位由低变高而触发输出变化的就叫上升沿触发。
下降沿触发:数字电平从高电平(数字“1”)变为低电平(数字“0”)的那一瞬间叫作下降沿。下降沿触发是当信号有下降沿时的开关动作,当电位由高变低而触发输出变化的就叫下降沿触发。
外部中断/事件线路映像:
通用I/O端口以下图的方式连接到16个外部中断/事件线上:
所以说相同的Pin只能选择一个输出,不能同时触发中断,这是我们就需要使用AFIO进行选择。
(四)嵌套中断向量控制器(NVIC)
在STM32中NVIC主要用来统一分配中断优先级和管理中断,为了实现EXTI中断的功能,在进行EXTI边沿检测和控制后还需要接入NVIC进行中断优先级的分组,然后输入cpu。
NVIC优先级分组
优先级分为抢占优先级和响应优先级。如果有多个中断同时响应,抢占优先级高的就会比抢占优先级低的优先得到执行,如果抢占优先级相同,就比较相应优先级。如果抢占优先级和响应优先级都相同的话,就按官方手册中的中断号排序,编号越小,优先级越高。
eg:假设设置中断优先级组为2(由上表可知组2中取值均只能为0-3),然后设置中断1的抢占优先级为2,响应优先级为1。 中断2的抢占优先级为3,响应优先级为0。中断3的抢占优先级为2,响应优先级为0。
那么优先级顺序为:中断3>中断1>中断2。
(五)如何使用外部中断
(1)配置RCC,打开所涉及的外设时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO的时钟
(2)配置GPIO,选择端口为输入模式
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
在这里我们我们将pin1引脚设置为了上拉输入(默认高电平输入)可以在官方手册查寻推荐模式。
(3)配置AFIO,选择中断引脚
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
(4)配置EXTI,选择边沿触发方式
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line1; //配置中断线
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //指定外部中断线为中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure);
这里选择的是上升沿触发(EXTI_Trigger_Falling),根据需求选即可(比如在上升沿和下降沿时执行不同的操作)。
(5)配置NVIC,选择分组,分配优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; //选择配置NVIC
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定NVIC线路的抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure);
根据上面的表格,在这里配置抢占优先级(NVIC_IRQChannelPreemptionPriority)范围为1-3,响应优先级(.NVIC_IRQChannelSubPriority)也同样如此,该代码中只有一个中断,随便即可,如果多个,注意排序。