EXTI,外部中断/事件控制器。管理了控制器的23个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿检测。
EXTI可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。
每个IO都可以作为外部中断输入。
中断/事件线:
EXTI有23个中断/事件线,每个GPIO都可被设置为输入线,占用EXTI0至EXTI15,还有另外7根用于特定的外设事件。
通过配置SYSCFG外部中断配置寄存器n(SYSCFG_EXTICRn)来选择输入线。(n = 1,2,3,4)
中断服务函数:
IO口外部中断在中断向量表中只分配了7个中断向量,也就是只能使用7个中断服务函数。
EXTI可分为两大部分功能:一个是产生中断,另一个是产生事件,这两个功能从硬件上就有所不同。
产生中断线路的目的是把输入信号输入到NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的。
产生事件线路的目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。
EXTI是在APB2总线上的。
编号1:是输入线,EXTI控制器有23个中断/事件输入线,这些输入线可以通过寄存器设置为任意一个GPIO,也可以是一些外设的事件。输入线一般是存在电平变化的信号。
编号2:是边沿检测电路,它会根据上升沿触发选择寄存器和下降沿触发选择寄存器对应位的设置来控制信号触发。边沿检测电路以输入线作为信号输入端,如果检测到有边沿跳变就输出有效信号1给编号3电路,否则输出无效信号0.。上升沿触发选择寄存器和下降沿触发选择寄存器可以检测哪些类型的电平跳变过程,可以是只有上升沿触发,只有下降沿触发或者上升沿和下降沿都触发。
编号3:是一个或门电路,一个输入来自编号2电路,另外一个输入来自软件中断事件寄存器。软件中断事件控制器允许我们通过程序控制就可以启动中断/事件线。
编号4:是一个与门电路,一个输入来自编号3电路,另外一个输入来自中断屏蔽寄存器。该电路输出的信号会被保存到挂起寄存器内。
编号5:将挂起寄存器内容输出到NVIC中,从而实现系统中断事件控制。
编号6:是一个与门电路,一个输入来自编号3电路,另外一个输入来自事件屏蔽寄存器。
编号7:是一个脉冲发生器电路,当它的输入端是一个有效信号1时就会产生一个脉冲;如果输入端是无效信号0时就不会输出脉冲。
编号8:是一个脉冲信号,就是产生事件的线路最终的产物,这个脉冲信号可以给其他外设电路使用。
三、结构体
typedef struct
{
uint32_t EXTI_Line; //中断线
EXTI_Line0 ~ EXTI_Line22
EXTIMode_TypeDef EXTI_Mode; //模式
EXTI_Mode_Interrupt (中断)
EXTI_Mode_Event (事件)
EXTITrigger_TypeDef EXTI_Trigger; //触发方式
EXTI_Trigger_Rising (上升沿)
EXTI_Trigger_Falling (下降沿)
EXTI_Trigger_Rising_Falling (上升沿与下降沿)
FunctionalState EXTI_LineCmd; //使能/失能
ENABLE(使能)
DISABLE(使能)
}EXTI_InitTypeDef;
四、常用库函数
(1)设置IO口与中断线的映射关系
void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex);
(2)初始化EXTI
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
(3)获取中断状态
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
(4)清除中断标志位
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
五、程序
#ifndef __EXTI_H__
#define __EXTI_H__
#include "stm32f4xx_conf.h"
void EXTI_Config(void);
#endif
#include "./EXTI/exti.h"
#include "./BEEP/beep.h"
#include "./LED/led.h"
/*
key1--->PF9
key2--->PF8
key3--->PF7
key4--->PE6
*/
/****************************
功能:配置EXTI
参数:无
返回值:无
*****************************/
void EXTI_Config(void)
{
GPIO_InitTypeDef initValue;
EXTI_InitTypeDef extiInitValue;
NVIC_InitTypeDef nvicInitValue;
/*1、打开时钟(GPIO和SYSCFG时钟)*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
/*2、配置GPIO的输入功能*/
initValue.GPIO_Mode = GPIO_Mode_IN;
initValue.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_8 | GPIO_Pin_7;
initValue.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOF,&initValue);
initValue.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOE,&initValue);
/*3、设置IO口与中断线的映射*/
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOF,EXTI_PinSource9);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOF,EXTI_PinSource8);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOF,EXTI_PinSource7);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource6);
/*4、初始化EXTI*/
extiInitValue.EXTI_Line = EXTI_Line8 | EXTI_Line7 | EXTI_Line6;
extiInitValue.EXTI_LineCmd = ENABLE;
extiInitValue.EXTI_Mode = EXTI_Mode_Interrupt;
extiInitValue.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&extiInitValue);
extiInitValue.EXTI_Line = EXTI_Line9 ;
extiInitValue.EXTI_LineCmd = ENABLE;
extiInitValue.EXTI_Mode = EXTI_Mode_Interrupt;
extiInitValue.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_Init(&extiInitValue);
/*5、初始化NVIC*/
nvicInitValue.NVIC_IRQChannel = EXTI9_5_IRQn;
nvicInitValue.NVIC_IRQChannelCmd = ENABLE;
nvicInitValue.NVIC_IRQChannelPreemptionPriority = 2;
nvicInitValue.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&nvicInitValue);
}
/****************************
功能:中断服务函数
参数:无
返回值:无
*****************************/
void EXTI9_5_IRQHandler(void)
{
if(GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_9) == 0) //key1按下
{
BEEP_ON();
}
if(GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_8) == 0) //key2按下
{
LED_ON(1);
}
if(GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_7) == 0) //key3按下
{
LED_ON(2);
}
if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_6) == 0) //key4按下
{
LED_OFF(1);
LED_OFF(2);
}
//清除中断标志位
EXTI_ClearITPendingBit(EXTI_Line9);
EXTI_ClearITPendingBit(EXTI_Line8);
EXTI_ClearITPendingBit(EXTI_Line7);
EXTI_ClearITPendingBit(EXTI_Line6);
}
#include "delay.h"
#include "stdio.h"
#include "./LED/led.h"
#include "./BEEP/beep.h"
#include "./KEY/key.h"
#include "./USART/usart.h"
#include "./EXTI/exti.h"
int main(void)
{
//配置EXTI
EXTI_Config();
while(1)
{
}
}