1.0 EXTI 简介

EXTI(Extern Interrupt)外部中断

EXTI 可以监测指定 GPIO 口的电平信号,当其指定的 GPIO 口产生电平变化的时候,EXTI 立即向 NVIC 发出中断申请,经过 NVIC 裁决后即可中断 CPU 主程序,使得 CPU 执行 EXTI 对应的中断程序。

其中 EXTI 支持四种不同的触发方式。
  • 上升沿:数字电平从低电平 0 变化到高电平 1 的一瞬间叫做上升沿。
  • 下降沿:数字电平从高电平 1 变化到低电平 0 的一瞬间叫做下降沿。
  • 双边沿:上升沿和下降沿。
  • 软件触发:不需要硬件触发的外部中断,而由软件触发的中断。

2.0 EXTI 特性

  • EXTI 支持所有 GPIO 口,但是相同 Pin 的 IO 口不可以同时触发中断(比如PA0,PB0不能同时触发中断)。
  • EXTI 支持的通道数:16个GPIO_Pin、PVD输出、RTC时钟、USB唤醒、以太网唤醒(合计20个中断线路)。
  • 触发相应方式:中断响应、事件相应(事件响应不会触发中断,而是触发别的外设操作)。

3.0 STM32 标准库使用 EXTI

这里以 STM32F103C8T6 作为示例。

3.1 使能 RCC 时钟

由于NVIC和EXTI是默认开启时钟的外设,因此不需要开启这两个外设的时钟;需要开启的有GPIO时钟以及AFIO时钟。

RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOx, ENABLE);   // GPIO
RCC_APB2PeriphClockCmd (RCC_APB2Periph_AFIO, ENABLE);    // AFIO

3.2 配置 GPIO 工作模式

由于使用EXTI外部中断,因此需要使目标 GPIO 口工作在上拉输入 (GPIO_Mode_IPU) 的模式下。

GPIO_InitTypeDef GOIO_InitStrucuture;

GOIO_InitStrucuture.GPIO_Mode = GPIO_Mode_IPU;      // GPIO 上拉输入
GOIO_InitStrucuture.GPIO_Pin = GPIO_Pin_x;          // 配置需要使用的 Pin 口
GOIO_InitStrucuture.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOB,&GOIO_InitStrucuture);

3.3 配置 AFIO

通过 AFIO 将需要使用的 GPIO 口连接到 EXTI。

GPIO_EXTILineConfig (GPIO_PortSourceGPIOx, GPIO_PinSourcex);

3.4 配置 EXTI

选择中断触发方式。

EXTI_InitTypeDef EXTI_InitStructure;                        // EXTI初始化结构体

EXTI_InitStructure.EXTI_Line = EXTI_Linex;                  // 选择需要配置的中断线,这个与配置AFIO时所配置的中断线相同
EXTI_InitStructure.EXTI_LineCmd = ENABLE;                   // 选择指定中断线的状态
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;         // 指定模式(EXTI_Mode_Interrupt : 中断模式)
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;     // 指定触发信号的有效边沿

EXTI_Init(&EXTI_InitStructure);
EXTI 有如下三种触发设置
  1. EXTI_Trigger_Rising —— 上升沿触发
  2. EXTI_Trigger_Falling —— 下降沿触发
  3. EXTI_Trigger_Rsing_Falling —— 双边沿触发

3.5 配置 NVIC

为中断分配一个合适的优先级。

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
// 配置NCIV优先级分组(抢占优先级、响应优先级)
// 该函数在每一个芯片中只能使用一次

NVIC_TypeDef NVIC_InitStructure;                            // NCIV初始化结构体

NVIC_InitStructure.NCIV_IRQChannel = EXTI15_10_IRQn;        // 指定中断通道开启或者关闭
NVIC_InitStructure.NCIV_IRQChannelCmd = ENABLE;             // 指定通道使能还是失能(ENABLE,DISABLE)
NVIC_InitStructure.NCIV_IRQChannelPreemptionPriority =  1;  // 指定抢占优先级的优先级
NVIC_InitStructure.NCIV_IRQChannelSubPriority = 1;          // 指定响应优先级的优先级

NVIC_Init(&NVIC_InitStructure);
NVIC 优先级的几种分组
NVIC_PriorityGroup抢占优先级相应优先级
NVIC_PriorityGroup_000~15
NVIC_PriorityGroup_10~10~7
NVIC_PriorityGroup_20~30~3
NVIC_PriorityGroup_30~70~1
NVIC_PriorityGroup_40~150

3.6 EXTI 中断函数

在 EXTI 配置完毕后,当达到中断触发条件后就会自动执行中断函数中的代码。


//中断函数
void EXTI15_10_IRQHandler(void){
    if (EXTI_GetITStatus(EXTI_Linex) == SET ) {      // 判断中断标志位,判断是否为想要触发中断的通道

        /* 
         * 需要执行的函数 
        */

        EXTI_ClearITPendingBit(EXTI_Linex);         // 清除中断标志位,防止程序重复申请中断造成死循环
    }
}