STM32之三:中断&&外部中断

目录

[1. 什么是中断](#1. 什么是中断)

[1.1 中断概念](#1.1 中断概念)

[1.2 中断优先级](#1.2 中断优先级)

[1.3 中断嵌套](#1.3 中断嵌套)

2.STM32中断

[2.1 NVIC中断优先级](#2.1 NVIC中断优先级)

[3 外部中断](#3 外部中断)

[3.1 EXTI简介](#3.1 EXTI简介)

[3.2 EXTI中断/事件线](#3.2 EXTI中断/事件线)

[3.3 EXTI功能框图](#3.3 EXTI功能框图)

[3.4 中断和事件的区别?](#3.4 中断和事件的区别?)

[3.5 什么时候用外部中断?](#3.5 什么时候用外部中断?)

3.怎么使用STM32中断

[3.1 STM32外部中断编程要点](#3.1 STM32外部中断编程要点)

[3.2 GPIO&AFIO](#3.2 GPIO&AFIO)

[3.3 EXTI初始化](#3.3 EXTI初始化)

[3.4 配置NVIC](#3.4 配置NVIC)

[3.5 编写中断服务函数](#3.5 编写中断服务函数)

[3.6 清除中断标志位](#3.6 清除中断标志位)


1. 什么是中断

1.1 中断概念

中断是计算机的一种机制,描述了这样一种场景:CPU暂停当前正在处理的程序,转而去处理紧急的事情,这种场景就叫中断。

中断其实很好理解,因为这样的场景经常发生在我们日常生活中。比如小李正在写作业,但是电话铃声响了,他转而去接电话,接完电话回来后继续写作业。在这个情境中,小李就完成了一次中断,下图根据现实生活的中断场景形象的表示了CPU中断过程,便于理解。
图1 中断场景概念

1.2 中断优先级

中断优先级即当有多个中断源请求中断时,CPU会根据中断优先级来判断首先执行那个中断。

1.3 中断嵌套

这个和中断优先级一起适配。当CPU正在相应中断,执行中断服务程序,此时又来了一个比当前中断优先级还高的中断,则此时CPU会停下当前执行的中断服务程序,转而去响应中断优先级更高的中断,等执行高优先级的中断后,回来继续执行未执行完的中断服务程序。中断可以有多个嵌套,有点套娃的意思。

2.STM32中断

STM32共有6个内核中断,68个可屏蔽中断。可见下图。
图2 互联型产品的向量表

STM32中断使用嵌套向量中断控制器NVIC管理包括内核异常等中断,NVIC和处理器核的接口紧密相连,可以实现低延迟和高效的中断处理。

使用NVIC,主要使其ISER(使能中断)、ICER(失能中断)、IP(中断优先级)三个寄存器。

2.1 NVIC中断优先级

NVIC有一个寄存器来进行优先级设置:中断优先级寄存器NVIC_IPRx。NVIC的中断优先级分为抢占优先级和响应优先级。抢占优先级即可以进行中断嵌套的一种优先级,CPU会优先处理抢占优先级高的中断。而响应优先级只在抢占优先级相同的时候才会触发,相同抢占优先级下,优先执行相应优先级的高的中断。如果抢占优先级和响应优先级都相同,则比较中断的硬件中断编号(图2所示优先级),编号越小,优先级越高。

如何配置优先级?

NVIC的中断优先级由优先级寄存器的4位(0~15)决定 ,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级(n的取值由用户在程序中进行选择 )。抢占优先级高的可以中断嵌套 (低优先级中断在占用CPU时,抢占优先级高的中断可以抢占低优先级中断的CPU,让低优先级中断暂停执行),响应优先级高的可以优先排队抢占优先级和响应优先级均相同的按中断号排队
图3 NVIC优先级分组(来源: STM32入门教程(EXTI外部中断篇)_请求挂起寄存器和中断标志位一样吗-CSDN博客 侵删,博主写的很清晰很详细,推荐看)

总结下NVIC、中断和CPU之间的关系
图4 NVIC基本结构 来源(B站江协科技STM32视频,推荐大家看)

3 外部中断

3.1 EXTI简介

EXTI(External interrupt/event controller)外部中断/事件控制器由20个产生事件/中断请求的边沿检测器组成。每个输入线可以独立的配置、触发和屏蔽。

3.2 EXTI中断/事件线

EXTI支持20个中断/事件线,其中前16根为GPIO输入线,另外4根用于特定的外设事件,可参考下图。
图5 EXTI 中断/事件线(来源:野火STM32库开发实战指南 18. EXTI---外部中断/事件控制器 --- [野火]STM32库开发实战指南------基于野火指南者开发板 文档

由上图可以看到,EXIT支持所有的GPIO口产生中断,但是相同的Pin不能同时触发中断(比如PA0和PB0不能同时使用,但PA0和PB1可以同时使用)。因为EXTI0线同时只能选择其中1个进行中断输出,可以看下图,PA0、PB0、PC0、PD0、PE0、PF0、PG0都输入到同一个数据选择器,EXTI0线输出的信号通过AFIO_EXTICR1寄存器的EXTI0[3:0]位来配置。
图6 外部中断IO映射

外部中断配置寄存器共有4个,即AFIO_EXTICRx[x=1,2,3,4],其中每个AFIO_EXTICRx中管理4个EXTI中断,因此共有16个GPIO对应的EXTI中断/事件线。外部中断配置寄存器可以看下图:
图7 外部中断配置寄存器

图4中外部中断配置寄存器和图3中EXTI0---EXTI15是对应上的,AFIO中有16个数据选择器,以0号数据选择器为例,它负责选择PA0、PB0......PG0中的其中一个引脚,在写程序时如果想选择PB0作为中断引脚,就需要对AFIO的0号数据选择器进行配置,让它选择GPIOB的0号引脚。另外注意图3中最后一句话,通过AFIO_EXTICRx配置GPIO线上的外部中断/事件,必须先使能AFIO的时钟。

3.3 EXTI功能框图

图8 EXTI功能框图

这个框图可以从右往左看,分为两路,其中红色表示产生中断,绿色表示产生事件。1、2、3号电路是产生中断和产生事件共用的,到3号电路输出信号分开,一路走至NCIV产生中断信号,一路走至脉冲发生器产生事件。框图中"/20"表示线路有20个,这和3.2章节有20根中断/事件线,并且每个线路都是可以独立配置、屏蔽、触发是相一致的。

我们首先来看红色部分产生中断信号的流程。其中1号电路输入线即为3.2章节介绍的EXTI中断/事件线,一般是传入电平变化的信号。之后往左将该信号传递到2号边沿检测电路。该电路连接了两个寄存器,分别是上升沿触发选择寄存器和下降沿触发选择寄存器,这两个寄存器用来判断2号边沿检测电路检测哪些类型的电平信号,即上升沿触发或者下降沿触发,或者上升沿下降沿都触发。

之后继续往左,来到3号电路,是一个或门,或门的意思是有1即1。或门的两个输入端分别是来自2号电路边沿检测电路的信号和软件中断/事件寄存器。由此可见,产生中断信号可以有两个方式,其一即20跟输入线产生电平跳变信号,其二即在软件中断事件寄存器进行配置,也可达到产生中断/事件的效果。

3号电路输出的信号就表示是否有中断/事件信号,从图中可以看出该输出也兵分两步:其一往上输入到请求挂起寄存器,其二输入到4号与门电路中。我们先看上面部分。

当在外部中断线上发生了选择的边沿跳变,则请求挂起寄存器的相应中断线位置会被置1、之后继续往左,走到7号电路,该电路是一个与门,共有两个输入端,其一为请求挂起寄存器的输出信号,其二为中断屏蔽寄存器。中断屏蔽寄存器[19:0]位为1则表示可以该中断线可以产生中断,否则将屏蔽该中断线上的请求。

之后往左,可以看到与门输出为NVIC中断控制器,可以知道经过一系列判断最终输入线产生的中断被送往NVIC中断控制器。至此,外部中断信号产生过程已介绍完毕。

接着看下面部分,事件产生过程,3号电路输出信号输入到4号电路中,该电路与7号电路作用一致,也是一个与门,通过事件屏蔽寄存器来决定是否能产生事件,相应位置1表示可以产生事件,置0则表示屏蔽该线路中断。

4号电路信号输出到5号电路脉冲发生器中,4号电路是一个有效信号,则此时5号电路就会产生一个脉冲;否则不会产生脉冲。脉冲信号就是产生事件的意思,因为这个脉冲信号可以给其他外设发送信息,即可以通过该脉冲信号来触发TIM、ADC等外设。

这个框图比较复杂,我们抽取一些有用的信息来记忆:

1.要想产生某个线路的中断/事件,必须将该线路的中断/事件屏蔽寄存器响应位置位。

2.20个中断/事件线是独立的,有各自独立的边沿触发寄存器、屏蔽寄存器。

3.中断/事件产生可以通过20个输入线来产生,也可以通过软件来产生。通过软件来产生需要置位软件中断/事件寄存器相应位为1。

4.20个输入触发中断/事件的方式有:上升沿、下降沿、上升沿+下降沿。

3.4 中断和事件的区别?

产生事件的目的是传送一个脉冲信号给其他外设使用。

产生中断是把中断信号传递给NVIC,NVIC会通过优先级配置最终传递给CPU,让CPU去执行中断服务函数,实现中断功能。这就是产生事件和产生中断的区别。

3.5 什么时候用外部中断?

对于由外部触发的一些场景,例如遥控器,调整声音的按钮等,这些不是时时刻刻发生,而是由人为(外部信号)发出,并且发生后需要立即捕获其信号的场景,可以使用外部中断来进行捕获。

3.怎么使用STM32中断

3.1 STM32外部中断编程要点

  1. 明确中断源(一般是GPIO),开启GPIO时钟,初始化要产生中断的GPIO。此步骤需注意,复用AFIO,需开启AFIO时钟,并且选择AFIO中断引脚【GPIO_EXTILineConfig()】。

2.初始化EXTI,主要是EXTI_InitTypeDef结构体。

3.经前面介绍,中断过后会到NVIC控制器中,所以需要配置NVIC相应寄存器【NVIC中断分组、NVIC配置】。

4.编写中断服务函数。

5.清除中断标志位

3.2 GPIO&AFIO

GPIO时钟和配置此处就省略了,重点关注开启IO复用时钟。查看stm32f10x_rcc.h,RCC_APB2PeriphResetCmd()函数用来开启APB2总线上的时钟。

cpp 复制代码
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //开启IO口复用时钟

之后,需要设置IO口与中断线的映射关系。查看stm32f10x_gpio.h,GPIO_EXTILineConfig()函数用来选择在EXTI中断线的GPIO引脚。

cpp 复制代码
//例如,将外部中断的0号线映射到GPIOB,即选择PB0作为外部中断引脚
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);

3.3 EXTI初始化

我们来看下EXTI初始化结构体,配置EXTI初始化结构体可以配置中断/事件线、产生中断还是产生事件、边沿触发方式、使能EXTI线。

cpp 复制代码
//EXTI初始化结构体
//配置EXTI初始化结构体可以配置中断/事件线、产生中断还是产生事件、边沿触发方式、使能EXTI线
typedef struct
{
  uint32_t EXTI_Line;               //中断/事件线
   
  EXTIMode_TypeDef EXTI_Mode;       //中断/事件模式,可选为产生中断(EXTI_Mode_Interrupt)或               者产生事件(EXTI_Mode_Event)

  EXTITrigger_TypeDef EXTI_Trigger;  //EXTI边沿触发方式。上升沿触发(EXTI_Trigger_Rising)、下降沿触发(EXTI_Trigger_Falling)、上升沿下降沿都触发(EXTI_Trigger_Rising_Falling)

  FunctionalState EXTI_LineCmd;     //是否使能EXTI线
}EXTI_InitTypeDef;

示例代码如下:

cpp 复制代码
/*EXTI初始化*/
	EXTI_InitTypeDef EXTI_InitStructure;						//定义结构体变量
	EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;		//选择配置外部中断的0号线和1号线
	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外设
	

3.4 配置NVIC

cpp 复制代码
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
																//即抢占优先级范围:0~3,响应优先级范围:0~3
																//此分组配置在整个工程中仅需调用一次
																//若有多个中断,可以把此代码放在main函数内,while循环之前
																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			//选择配置NVIC的EXTI0线
	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外设

3.5 编写中断服务函数

cpp 复制代码
void EXTI0_IRQHandler(void){}

3.6 清除中断标志位

cpp 复制代码
EXTI_ClearITPendingBit(EXTI_Line0);			//清除外部中断0号线的中断标志位
													//中断标志位必须清除
													//否则中断将连续不断地触发,导致主程序卡死

至此,STM32外部中断部分介绍完毕。

相关推荐
番茄灭世神8 小时前
利用STM32的定时器输出PWM方波
stm32·单片机·嵌入式硬件
m0_644222618 小时前
HarmonyOS开发实战:UDP通讯示例规范
网络·驱动开发·嵌入式硬件·udp·harmonyos·鸿蒙·harmonyos next
人才程序员9 小时前
【51单片机入门】速通定时器
c语言·c++·单片机·嵌入式硬件·mcu·51单片机·proteus
XD74297163612 小时前
【TB作品】步进电机控制器,ATMEGA16单片机,Proteus仿真
单片机·proteus·仿真·步进电机·atmega16
南耿先生12 小时前
我在高职教STM32——LCD液晶显示(1)
stm32·单片机·嵌入式硬件
xiaoyaoyou.xyz12 小时前
嵌入式UI开发-lvgl+wsl2+vscode系列:5、事件(Events)
单片机·ui·lvgl
莫邪博客13 小时前
【STM32修改串口波特率】
stm32·单片机·嵌入式硬件
电气_空空14 小时前
基于单片机技术的按键扫描电路分析
单片机·嵌入式硬件·毕业设计·毕设
XD74297163614 小时前
【TB作品】密码锁,数码管,ATMEGA16单片机,Proteus仿真
单片机·proteus·密码锁
极客小张15 小时前
高性价比 ESP32 网络收音机:OLED 显示+编码器控制 (源码开源)
单片机·嵌入式硬件·mcu·物联网·硬件工程·智能家居