STM32---外部中断EXTI

发布于:2025-04-22 ⋅ 阅读:(15) ⋅ 点赞:(0)

目录

一、中断向量表

二、EXTI工作原理图

三、NVIC模块

四、GPIO设置为EXTI的结构

五、C语言示例代码


        在STM32中,中断是一个非常重要的结构,他能让我们在执行主函数的时候,由硬件检测一些外部或内部产生的中断信号,跳转到中断函数,从而提高CPU用于运算的时间占比,提高了效率。举个例子,如果没有中断的存在,则CPU需要一直循环遍历每一个寄存器,查看是否产生了某些信号,就无法专心处理运算逻辑。

一、中断向量表

        中断向量表(Interrupt Vector Table, IVT)是嵌入式系统(尤其是ARM Cortex-M系列处理器)中用于管理中断的核心数据结构(函数指针数组)。它通过固定地址映射将中断号与中断服务函数(ISR, Interrupt Service Routine)关联,确保中断发生时处理器能快速跳转到正确的处理逻辑。

        我们写的中断服务函数是保存在Flash中的,当一个外部中断信号来临的时候,CPU会跳转到该函数并执行。这是什么原理呢?

        由于硬件原因CPU只能从某些特定的地址处访问中断函数,即只能从中断向量表中的地址去访问。所以一定要把中断服务函数和中断号一一对应,否则就会出问题,中断源触发跳转到错误的函数的问题。(因为编译器是根据中断号来找到数组下标,填写函数的地址的)

        举个例子如果将 EXTI0_IRQHandler 配置到中断号 5,而硬件上的中断号 5 对应的是另一个中断源(如 RTC Alarm),那么当该中断触发时,CPU 会错误地调用 EXTI0_IRQHandler,二EXTI0发生中断的时候,会到表中找,发现并没有任何函数地址被填写进来,导致程序行为异常。

中断触发流程

  1. 中断发生:外设或异常触发中断。
  2. 中断号确定:处理器根据中断源确定中断号。
  3. 向量表查询:处理器从向量表中读取对应中断号的条目,获取中断服务函数的地址。
  4. 跳转执行:处理器跳转到该地址,执行中断服务函数。
  5. 返回:中断处理完成后,处理器返回主程序继续执行。

二、EXTI工作原理图

         其中按照控制功能划分,共分为4个部分;有两条主线,一条是由输入线到 NVIC 中断控制器,一条是由输入线到脉冲发生器。

        输入线:是线路的信息输入端,它可以通过配置寄存器设置为任何一个 GPIO 口,或者是一些外设的事件。输入线一般都是存在电平变化的信号。

(1)上升/下降沿触发选择寄存器:对边沿检测电路进行设置,当输入线有信号的时候并不会走到这里,他仅仅是在信号来临之前进行配置。

(2)边沿检测电路:对信号进行检测,符合上一条配置的则向或门输出1

(3)或门电路:两个信号输入端分别是软件中断事件寄存器和边沿检测电路的输入信号。或门电路只要输入端有信号1,就会输出1。所以可以同时检测软件中断和硬件中断。

(4)与门电路(标号3):两个信号输入端分别是中断屏蔽寄存器和标号2电路信号。如果中断屏蔽寄存器设置为 0 时,不管从标号2电路输出的信号特性如何,最终标号3电路输出的信号都是 0;假如中断屏蔽寄存器设置为 1 时,最终标号3电路输出的信号才由标号2电路输出信号决定,这样子就可以简单控制 中断屏蔽寄存器 来实现屏蔽或者开放中断的目的。

(5)与门电路(标号4):输入端来自标号2电路以及来自于事件屏蔽寄存器。可以简单的控制事件屏蔽寄存器来实现是否产生事件的目的。标号4电路输出有效信号 1 就会使脉冲发生器电路产生一个脉冲,而无效信号就不会使其产生脉冲信号。脉冲信号产生可以给其他外设电路使用,例如定时器,模拟数字转换器等,这样的脉冲信号一般用来触发 TIM 或者 ADC 开始转换。

        产生中断线路目的使把输入信号输入到 NVIC或者其他外设,进一步运行中断服务函数,实现功能。

三、NVIC模块

        NVIC位于处理器的核心外围设备中,负责接收来自各种外设的中断请求,并根据预设的优先级对这些请求进行排序和处理。它使用向量表来记录每个中断源的中断服务程序(ISR)的地址,确保中断发生时能迅速跳转到正确的处理位置。

        当中断信号来临的时候,首先会交付给NVIC模块,由NVIC裁决(看你的优先级是否足够高)选择是交付给CPU,还是挂起在NVIC等待队列中。

这幅图表示了各种外设产生中断信号的时候,首先要交付给NVIC,经过裁决才能交付给CPU。

        注意:NVIC可以设置优先级为抢占优先级和排队优先级。抢占优先级可以进行中断嵌套,如果抢占优先级相同则只能在NVIC中排队。但是如果排队优先级比别人高,是可以插队的。所以STM32的中断优先级不遵循先来后到,而是谁紧急优先处理谁。

四、GPIO设置为EXTI的结构

        从下图中可以看到如果GPIO被设置为中断源的话,需要经过AFIO进行引脚选择的,而同为外部中断的其他几个模块(PVD、RTC、USB、ETH)则不需要经过AFIO,直接连接到EXTI边沿检测模块。

        当EXTI从左端收到了中断信号之后,会向下层NVIC传递到CPU、或者通过脉冲发射器向其他外设(取决于你配置的是中断还是事件)。

AFIO设置EXTI0的示意图:

配置GPIO为EXTI外部中断的过程图示:

五、C语言示例代码

void EXTI_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);		//开启AFIO的时钟,外部中断必须开启AFIO的时钟
	
	/*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引脚初始化为上拉输入
	
	/*AFIO选择中断引脚*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);//将外部中断的14号线映射到GPIOB,即选择PB14为外部中断引脚
	
	/*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外设
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
																//即抢占优先级范围:0~3,响应优先级范围:0~3
																//此分组配置在整个工程中仅需调用一次
																//若有多个中断,可以把此代码放在main函数内,while循环之前
																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	
	/*NVIC配置*/
	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外设
}
void EXTI15_10_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line14) == SET)		//判断是否是外部中断14号线触发的中断
	{
		/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0)
		{
			
            //这里填入处理逻辑

		}
		EXTI_ClearITPendingBit(EXTI_Line14);		//清除外部中断14号线的中断标志位
													//中断标志位必须清除
													//否则中断将连续不断地触发,导致主程序卡死
	}
}

 在这里给出csdn上别人封装的代码链接:STM32外部中断封装函数_如何封装stm32的中断,进行更高级的抽象-CSDN博客


网站公告

今日签到

点亮在社区的每一天
去签到