一、EXTI

   EXTI:External interrupt / event controller 外部 中断/事件 控制器
   EXTI(External interrupt/event controller)—外部中断/事件控制器,管理了控制器的20个中断/事件线。
   每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。
   EXTI可以实现对每个中断/事件线进行单独配置, 可以单独配置为中断或者事件,以及触发事件的属性。

二、EXTI功能框图

   1、EXTI框图

  在这里插入图片描述

   2、EXTI框图详解

     编号1:输入线
       EXTI控制器有19个中断/事件输入线,这些输入线可以通过寄存器设置为任意一个GPIO,也可以是一些外设的事件。
       输入线一般是存在电平变化的信号。
     编号2:边沿检测电路
       根据上升沿触发选择寄存器(EXTI_RTSR)和下降沿触发选择寄存器(EXTI_FTSR)对应位的设置来控制信号触发。
       边沿检测电路以输入线作为信号输入端,如果检测到有边沿跳变就输出有效信号1给编号3电路,否则输出无效信号0。
       可以设置只有上升沿触发、只有下降沿触发或者上升沿和下降沿都触发。
     编号3:或门电路
       输入来自编号2电路,另外一个输入来自软件中断事件寄存器(EXTI_SWIER)。
       EXTI_SWIER允许我们通过程序控制就可以启动中断/事件线。
       或门电路作用就是有1就为1。
       这两个输入随便一个有有效信号1就可以输出1给编号4和编号6电路。
     编号4:与门电路
       一个输入是编号3电路,另外一个输入来自中断屏蔽寄存器(EXTI_IMR)。
       门电路要求输入都为1才输出1, 导致的结果是如果EXTI_IMR设置为0时,
       那不管编号3电路的输出信号是1还是0,最终编号4电路输出的信号都为0;
       如果EXTI_IMR设置为1时, 最终编号4电路输出的信号才由编号3电路的输出信号决定。
     编号5:输出到NVIC
       将EXTI_PR寄存器内容输出到NVIC内,从而实现系统中断事件控制。
     编号6:与门电路
       一个输入来自编号3电路, 另外一个输入来自事件屏蔽寄存器(EXTI_EMR)。
       如果EXTI_EMR设置为0时,那不管编号3电路的输出信号是1还是0,最终编号6电路输出的信号都为0;
       如果EXTI_EMR设置为1时,最终编号6电路输出的信号才由编号3电路的输出信号决定。
     编号7:脉冲发生器电路
       当它的输入端,即编号6电路的输出端,是一个有效信号1时就会产生一个脉冲;如果输入端是无效信号就不会输出脉冲。
     编号8:脉冲信号
       脉冲信号可以给其他外设电路使用,比如定时器TIM、模拟数字转换器ADC等。
     总结:
       EXTI可分为两大部分功能,一个是产生中断12345 ,另一个是产生事件 123678。

   3、中断/事件线

     EXTI有20个中断/事件线,每个GPIO都可以被设置为输入线,占用EXTI0至EXTI15, 还有另外七根用于特定的外设事件.
      在这里插入图片描述

     EXTI16-19,4根特定外设中断/事件线由外设触发。
     EXTI0-15用于GPIO,通过编程控制可以实现任意一个GPIO作为EXTI的输入源。
     EXTI0可以通过AFIO的外部中断配置寄存器1(AFIO_EXTICR1)的EXTI0[3:0]位选择配置为PA0、 PB0、PC0、PD0、PE0、PF0、PG0、PH0或者PI0。
      在这里插入图片描述

   4、EXTI结构体详解

		typedef struct {
		    uint32_t EXTI_Line;                 // 中断/事件线
		    EXTIMode_TypeDef EXTI_Mode;         // EXTI模式
		    EXTITrigger_TypeDef EXTI_Trigger;   // 触发类型
		    FunctionalState EXTI_LineCmd;       // EXTI使能
		} EXTI_InitTypeDef;

     XTI_Line:
       EXTI中断/事件线选择,可选EXTI0至EXTI19,可参考表 EXTI中断_事件线 选择。
     EXTI_Mode:
       EXTI模式选择,可选为产生中断(EXTI_Mode_Interrupt)或者产生事件(EXTI_Mode_Event)。
     EXTI_Trigger:
       EXTI边沿触发事件,可选上升沿触发(EXTI_Trigger_Rising)、 下降沿触发( EXTI_Trigger_Falling)或者上升沿和下降沿都触发( EXTI_Trigger_Rising_Falling)。
     EXTI_LineCmd:
       控制是否使能EXTI线,可选使能EXTI线(ENABLE)或禁用(DISABLE)。

三、GPIO中断

   1、编程要点

     1,初始化要连接到EXTI的 GPIO。
     2,初始化EXTI用于产生中断事件。
     3,初始化NVIC,用于处理中断。
     4,编写中断服务函数。
     5,main函数。

   2、硬件设计

    在这里插入图片描述

   3、编程代码

     按键和EXTI宏定义
       按键和EXTI宏定义 EXTI.h文件内

			//引脚定义
			#define KEY1_INT_GPIO_PORT         GPIOA
			#define KEY1_INT_GPIO_CLK          (RCC_APB2Periph_GPIOA\
			                                    |RCC_APB2Periph_AFIO)
			#define KEY1_INT_GPIO_PIN          GPIO_Pin_0
			
			#define KEY1_INT_EXTI_PORTSOURCE   GPIO_PortSourceGPIOA
			#define KEY1_INT_EXTI_PINSOURCE    GPIO_PinSource0
			#define KEY1_INT_EXTI_LINE         EXTI_Line0
			#define KEY1_INT_EXTI_IRQ          EXTI0_IRQn
			
			#define KEY1_IRQHandler            EXTI0_IRQHandler
			
			#define KEY2_INT_GPIO_PORT         GPIOC
			#define KEY2_INT_GPIO_CLK          (RCC_APB2Periph_GPIOC\
			                                    |RCC_APB2Periph_AFIO)
			#define KEY2_INT_GPIO_PIN          GPIO_Pin_13
			
			#define KEY2_INT_EXTI_PORTSOURCE   GPIO_PortSourceGPIOC
			#define KEY2_INT_EXTI_PINSOURCE    GPIO_PinSource13
			#define KEY2_INT_EXTI_LINE         EXTI_Line13
			
			#define KEY2_INT_EXTI_IRQ          EXTI15_10_IRQn

     嵌套向量中断控制器NVIC配置
       嵌套向量中断控制器NVIC配置 EXTI.c文件内

			static void NVIC_Configuration(void)
			{
			    NVIC_InitTypeDef NVIC_InitStructure;
			
			    /* 配置NVIC为优先级组1 */
			    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
			
			    /* 配置中断源:按键1 */
			    NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;
			    /* 配置抢占优先级:1 */
			    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
			    /* 配置子优先级:1 */
			    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
			    /* 使能中断通道 */
			    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
			    NVIC_Init(&NVIC_InitStructure);
			
			    /* 配置中断源:按键2,其他使用上面相关配置 */
			    NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;
			    NVIC_Init(&NVIC_InitStructure);
			}

     EXTI中断配置.
       EXTI中断配置 EXTI.c文件内

			void EXTI_Key_Config(void)
			{
			    GPIO_InitTypeDef GPIO_InitStructure;
			    EXTI_InitTypeDef EXTI_InitStructure;
			
			    /*开启按键GPIO口的时钟*/
			    RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK,ENABLE);
			
			    /* 配置 NVIC 中断*/
			    NVIC_Configuration();
			
			    /*--------------------------KEY1配置---------------------*/
			    /* 选择按键用到的GPIO */
			    GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;
			    /* 配置为浮空输入 */
			    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
			    GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);
			
			    /* 选择EXTI的信号源 */
			    GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, \
			                        KEY1_INT_EXTI_PINSOURCE);
			    EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;
			
			    /* EXTI为中断模式 */
			    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
			    /* 上升沿中断 */
			    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
			    /* 使能中断 */
			    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
			    EXTI_Init(&EXTI_InitStructure);
			
			    /*--------------------------KEY2配置------------------*/
			    /* 选择按键用到的GPIO */
			    GPIO_InitStructure.GPIO_Pin = KEY2_INT_GPIO_PIN;
			    /* 配置为浮空输入 */
			    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
			    GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);
			
			    /* 选择EXTI的信号源 */
			    GPIO_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE, \
			                        KEY2_INT_EXTI_PINSOURCE);
			    EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE;
			
			    /* EXTI为中断模式 */
			    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
			    /* 下降沿中断 */
			    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
			    /* 使能中断 */
			    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
			    EXTI_Init(&EXTI_InitStructure);
			}

     EXTI中断服务函数
       EXTI中断服务函数 stm32f10x_it.c内

			void EXTI0_IRQHandler(void)
			{
			            //确保是否产生了EXTI Line中断
			    if (EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) {
			        // LED1 取反
			        LED1_TOGGLE;
			        //清除中断标志位
			        EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);
			    }
			}
			
			
			void EXTI15_10_IRQHandler(void)
			{
			            //确保是否产生了EXTI Line中断
			    if (EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) {
			        // LED2 取反
			        LED2_TOGGLE;
			        //清除中断标志位
			        EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);
			    }
			}

     Main函数

			int main(void)
			{
			    /* LED 端口初始化 */
			    LED_GPIO_Config();
			
			    /* 初始化EXTI中断,按下按键会触发中断,
			    *  触发中断会进入stm32f10x_it.c文件中的函数
			    *  KEY1_IRQHandler和KEY2_IRQHandler,处理中断,反转LED灯。
			    */
			    EXTI_Key_Config();
			
			    /* 等待中断,由于使用中断方式,CPU不用轮询按键 */
			    while (1) {
			    }
			}
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐