问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

STM32中的EXTI外部中断详解:从基础概念到代码实现

创作时间:
作者:
@小白创作中心

STM32中的EXTI外部中断详解:从基础概念到代码实现

引用
1
来源
1.
https://cloud.tencent.com/developer/article/2466501

STM32的EXTI(外部中断)模块是管理外部中断的重要组件,通过EXTI,当外部信号发生变化时,可以触发中断,使CPU暂停当前正在运行的程序,转而处理中断事件,处理完成后又返回原来被暂停的位置继续执行,极大地增强了单片机对外部事件响应的能力。本文将详细介绍STM32的EXTI外部中断的配置和使用方法,并提供详细的代码示例和图片说明。

STM32的EXTI外部中断介绍

STM32F10x 系列中的 EXTI 外部中断具有以下特点:

  • 支持16 个中断线(EXTI0 ~ EXTI15)。
  • 可以配置成上升沿触发、下降沿触发或双边沿触发。
  • 每条中断线可以分别映射到不同的 GPIO 引脚。

中断系统

  • 中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源。中断优先级是我们自己可以设置的。
  • 中断嵌套:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源。能否进行中断嵌套,也是由中断优先级来决定的。

外部中断工作原理

STM32 的 EXTI 外部中断模块基于 GPIO 管脚的电平变化来触发中断。通过配置 SYSCFG(系统配置控制器)寄存器,我们可以将某个 GPIO 引脚映射到指定的 EXTI 中断线上。随后,只需要在 NVIC(中断向量控制器)中使能对应的中断,就可以让单片机在发生外部事件时响应中断。

以下是 EXTI 外部中断的基本工作流程:

  1. GPIO 引脚初始化:将目标引脚配置为输入模式。
  2. EXTI 配置:指定中断触发条件(上升沿、下降沿或双边沿)。
  3. SYSCFG 配置:将 GPIO 引脚映射到 EXTI 中断线上。
  4. NVIC 配置:在 NVIC 中使能对应的中断优先级。
  5. 编写中断服务函数:在中断触发时处理相应的逻辑。

NVIC基本结构

NVIC是什么东西呢?它是用来统一分配中断优先级和管理中断的,是一个内核外设。STM32的中断非常的多,如果把中断全部接到cpu上面,那么就需要额外引出许多的线,而且要是很多中断同时申请,可能会造成拥堵,如果把这些事情都交给cpu的话,就浪费了CPU的资源,所以NVIC就是用来管理这些的。像下图的这些中断都是接在NVIC上面的,但是输出给CPU的就一条线,就是NVIC通过管理之后的中断表,根据中断的优先级分配先后的顺序,这样CPU按照这个顺序来执行操作即可。

4.1 NVIC优先级分组

NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级。抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队。

EXTI基本结构

下面这个是EXTI外部中断的基本结构图,最左边是GPIO口的外设,每个GPIO外设都有16根线,但是EXTI也只有16个GPIO的通道,所以通道是不够用的,那么就需要AFIO来进行引脚的复用,AFIO其实就是一个数据选择器,可以从前面的GPIO外设里面选择一个连接到后面的EXTI通道,这也就是相同的Pin不能同时触发的原因。

经过AFIO选择之后的16个通道,会被接到EXTI边沿检测以及控制电路上,下面的一些其他外设也是并列接过来的,加起来一共是20个输入通道,经过这个模块之后,分为了两种输出,上面的这一部分接到了NVIC,用来触发中断。注意外部中断的9-5,以及15-10分到了一个通道里,为了节省NVIC的资源。

AFIO复用

  • AFIO主要用于引脚复用功能的选择和重定义
  • 在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择
    这个结构比较简单,就是16个数据选择器,选择16个接到对应的EXTI上。

EXTI框图

首先EXTI框图的右下角就是20根输入线,输入线接入边沿检测电路,然后在上面的触发选择寄存器选择是上升沿触发还是下降沿触发,或者都触发,接着触发信号到达一个或门的输入端。

  • 像这种弯月型的符号就是或门,就是凹进去的那一边可以有多个输入,但是凸出来的那一边只能有一个输出,执行或的逻辑,输入端有一个高电平1那么输出端就是高电平1,只有全部输入为低电平0输出才为低电平0.
  • 下图还有一种馒头型的符号是与门,执行与的逻辑,输入端只要有低电平0输出就是低电平0,输入端全部是高电平1输出端才是高电平1.
  • 还有一种非门的符号,如下图所示,只有一个输入和一个输出,执行非的逻辑,输出跟输入是完全相反的.
  • 下图这个就是AFIO的数据选择器,是一个梯形,有多个输入和一个输出,在侧面有选择控制端,根据选择控制端的数据,从输入选择一个接到输出.
  • 那么在下图是硬件触发和软件中断寄存器的值都接到了这个或门上,那么只要有一个是高电平1输出就是高电平1,所以EXTI支持的触发方式有4种,上升沿,下降沿,双边沿(上升沿和下降沿都触发),软件触发。通过这个或门之后,触发信号分为两个方向,往上是触发中断,往下是触发事件。向上首先触发一个挂起寄存器,就相当于一个中断标志位,我们可以通过读取这个标志位来判断是哪个通道出发的中断。如果读取之后返回的是1,那么继续往左走,与中断屏蔽寄存器一起进入一个与门,最后到NVIC中断控制器。这个与门的作用在这里就是一个开关控制,这个中断屏蔽控制器给1那么请求挂起寄存器就是直接输出,也就是允许中断。如果给0无论请求挂起寄存器给什么都是0,不允许中断。下面那一路首先也是中断屏蔽寄存器来进行开关控制,最后通过一个脉冲发生器到其他外设,作用是给一个电平脉冲,用来触发其他外设的动作。框图中的20代表的是20根线,也就是20个通道,最上面就是外设接口和APB总线,可以通过总线访问这些寄存器。

EXTI 外部中断的详细函数讲解

在 STM32 的固件库或 HAL 库中,外部中断的配置和使用主要包括以下几个步骤:

  1. GPIO 配置:将指定的 GPIO 引脚设置为外部中断模式。
  2. EXTI 配置:配置触发条件(上升沿、下降沿或双边沿)。
  3. NVIC 配置:使能中断,并配置优先级。
  4. 中断服务函数:在中断发生时执行用户自定义操作。

8.1开启时钟并配置

首先需要使能GPIO和AFIO的时钟,以便后续配置GPIO引脚和复用功能。

/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);		//开启AFIO的时钟,外部中断必须开启AFIO的时钟

8.2配置GPIO引脚

将要使用的GPIO引脚配置为输入模式,同时使能外部中断线。

/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);						//将PB14引脚初始化为上拉输入

8.3选择中断引脚

使用AFIO选择一个中断引脚,用来触发中断。

/*AFIO选择中断引脚*/
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);//将外部中断的14号线映射到GPIOB,即选择PB14为外部中断引脚

8.4配置EXTI线

选择要使用的中断线并配置其触发方式,例如上升沿触发、下降沿触发等。

EXTI_InitTypeDef EXTI_InitStructure;						//定义结构体变量
EXTI_InitStructure.EXTI_Line = EXTI_Line14;					//选择配置外部中断的14号线
EXTI_InitStructure.EXTI_LineCmd = ENABLE;					//指定外部中断线使能
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			//指定外部中断线为中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;		//指定外部中断线为下降沿触发
EXTI_Init(&EXTI_InitStructure);								//将结构体变量交给EXTI_Init,配置EXTI外设

8.5设置中断分组

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
//即抢占优先级范围:0~3,响应优先级范围:0~3

8.6配置NVIC中断优先级

NVIC用于统一管理和分配中断优先级,每个中断通道都有16个可编程的优先等级。

NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;		//选择配置NVIC的EXTI15_10线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设

8.7编写中断服务函数

中断函数都是固定的名字,我们可以在启动文件里面找到,由于我们选择的是14号通道,所以中断函数是15_10的这个函数。此函数为中断函数,无需调用,中断触发后自动执行。

这是一个中断函数的例子,我们可以先获取中断标志位,判断是不是14号线引起的中断,然后再执行任务。还需要注意的是中断标志位必须清除,不然中断一直在,程序会停这里。

void EXTI15_10_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line14) == SET)		//判断是否是外部中断14号线触发的中断
    {
        /*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0)
        {
            CountSensor_Count ++;					//计数值自增一次
        }
        EXTI_ClearITPendingBit(EXTI_Line14);		//清除外部中断14号线的中断标志位
                                                    //中断标志位必须清除
                                                    //否则中断将连续不断地触发,导致主程序卡死
    }
}

感谢大家的阅读,下期我给大家讲解TIM定时中断,希望大家三连支持一下。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号