STM32单片机学习5--STM32中断

发布时间:2024年01月23日

一、前言

单片机无系统执行逻辑:main函数–>while死循环

EXTI(External Interrupt):外部中断,通过GPIO检测输入脉冲,引起中断事件,打断原来的代码执行流程,进入到中断服务函数中进行处理,处理完后再返回到中断之前的代码中执行。

在这里插入图片描述


二、NVIC中断控制器

Cortex内核具有强大的异常响应系统,它把能够打断当前代码执行流程的事件分为异常中断,并把他们用一个表管理起来,编号为0 ~ 15的称为内核异常,而16以上的则称为外部中断,这个表称为中断向量表。

这个表可以从《STM32参考手册》找到,但是已办结建议从启动文件startup_stm32f10x_hd.s中查找,因为不同型号的STM32芯片,中断向量表稍微有点区别,在启动文件中,已经有相应芯片可用的全部中断向量。而且在编写中断服务函数时,需要从启动文件中定义的中断向量表查找中断服务函数名。

STM32的中断如此之多,配置起来并不容易,因此我们需要一个强大二方便的中断控制器:NVIC(Nested Vectored Interrupt Controller)

NVIC属于Cortex内核的器件,不可屏蔽中断(NMI)和外部中断都由它来处理。


2.1、NVIC结构体成员

对NVIC进行初始化,首先要定义一个NVIC_InitTypeDef类型的结构体:

结构体成员名称描述
NVIC_IRQChannel需要配置的中断向量
NVIC_IRQChannelCmd使能或关闭相应中断向量的中断响应,ENABLE or DISABLE
NVIC_IRQChannelPreemptionPriority配置相应中断向量抢占优先级
NVIC_IRQChannelSubPriority配置相应中断向量的响应优先级

2.2、抢占优先级和响应优先级

STM32的中断向量具有两个属性:一个为抢占属性,一个为响应属性

其属性编号越小,表明它的优先级别越高

抢占:打断其它中断的属性

响应:当抢占属性相同的情况下,如果中断同时到达,则优先处理响应优先级高的中断

例如:现在有3个中断向量,如下图所示:

在这里插入图片描述

  • 如果内核正在执行C的中断服务函数,则它能被抢占优先级更高的中断A打断;
  • 由于B和C的抢占优先级相同,所以C不能被B打断;
  • 但如果B和C中断是同时到达的,内核就会优先执行响应优先级更高的B中断;

2.3、NVIC的优先级组

在配置优先级的时候,还要注意一个很重要的问题,即中断向量的数量。

NVIC只可以配置16种中断向量的优先级,也就是说,抢占优先级和响应优先级的数量由一个4位的数字来决定;

把这个4位数字的位数分配成抢占优先级部分和响应优先级部分,有5组分配方式:

分配说明
第0组0位抢占优先级,4位响应优先级,NVIC_PriorityGroup_0
第1组1位抢占优先级,3位响应优先级,NVIC_PriorityGroup_1
第2组2位抢占优先级,2位响应优先级,NVIC_PriorityGroup_2
第3组3位抢占优先级,1位响应优先级,NVIC_PriorityGroup_3
第4组4位抢占优先级,0位响应优先级,NVIC_PriorityGroup_4

要配置这些优先级组,可以采用库函数:NVIC_PriorityGroupConfig(),可输入参数为NVIC_PriorityGroup_0 ~ NVIC_PriorityGroup_4

STM32单片机的所有I/O端口都可以配置为EXTI中断模式,用来捕捉外部信号,可以配置为:

  • 下降沿中断(EXTI_Trigger_Falling
  • 上升沿中断(EXTI_Trigger_Rising
  • 上升下降沿中断(EXTI_Trigger_Rising_Falling

三、EXTI外部中断

STM32的所有GPIO都引入到EXTI外部中断线上,使得所有的GPIO都能作为外部中断的输入源,它们以下图的方式连接到16个外部中断/事件线上:
在这里插入图片描述

PAx ~ PGx端口的中断事件都连接到了EXTIx外部中断线上,同一时刻只能响应一个端口的事件触发,不能同时响应所有GPIO端口的事件,但可以分时复用;

EXTI最普通的应用就是:接上一个按键,设置为下降沿触发,用中断来检测按键;


四、中断实战

4.1、确定连线

在这里插入图片描述
如上图所示:我将PA1配置为中断端口,将PB0配置为中断控制端口

期望效果:单片机上电,PB0小灯默认亮,按下PA1按钮,进入中断函数,翻转PB0电位,实现开-关小灯


4.2、配置中断控制端口

#include "led.h"

void LED_GPIO_Config(void)
{
	//定义一个GPIO_InitTypeDef类型的结构体
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//开启GPIOB和GPIOC的外设时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC,ENABLE);
	
	//选择要控制的GPIOC引脚
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8;
	//设置引脚模式:通用推挽输出
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	//设置引脚速率:50MHz
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	//调用库函数,初始化GPIOC13
	GPIO_Init(GPIOC,&GPIO_InitStructure);
	
	//选择要控制的GPIOC引脚
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	//设置引脚模式:通用推挽输出
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	//设置引脚速率:50MHz
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	//调用库函数,初始化GPIOC13
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
}

在这里插入图片描述


4.3、配置中断端口

#include "exit.h"

//NVIC初始化
static void NVIC_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	//设置优先级组为高1位为抢占优先级,低3位为响应优先级
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	
	//配置中断源
	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;	//因为我们使用的是PA1,所示是EXTI1_IRQn
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;			//响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//使能
	NVIC_Init(&NVIC_InitStructure);								//初始化NVIC控制器
}

void EXIT_PA1_Config(void)
{
	//定义结构体
	//-------------------------------------
	GPIO_InitTypeDef GPIO_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;
	
	//开启外设时钟
	//-------------------------------------
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);
	
	//配置NVIC
	//-------------------------------------
	NVIC_Configuration();
	
	//中断端口GPIO配置(PA1)
	//-------------------------------------
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//中断线模式配置
	//-------------------------------------
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);
	EXTI_InitStructure.EXTI_Line = EXTI_Line1;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;	//下降沿触发
	
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
}


4.4、配置中断服务函数

中断服务函数必须定义在stmf10x_it.c文件中,中断服务函数的名字必须要与启动文件startup_stm32f10x_hd.s中的中断向量表定义一致

一般来说:

  • EXTI0对应的中断函数为EXTI0_IRQChannel;
  • EXTI1对应的中断函数为EXTI1_IRQChannel;
  • EXTI2对应的中断函数为EXTI2_IRQChannel;
  • EXTI3对应的中断函数为EXTI3_IRQChannel;
  • EXTI4对应的中断函数为EXTI4_IRQChannel;
  • EXTI5 -> EXTI9对应的中断函数为EXTI9_5_IRQHandler;
  • EXTI10 ->EXTI15对应的中断函数为EXTI15_10_IRQHandler;

在这里插入图片描述

//定义中断服务函数
void EXTI1_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line1) != RESET)
	{
		GPIO_WriteBit(GPIOB, GPIO_Pin_0,
			(BitAction)((1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0))));
		EXTI_ClearITPendingBit(EXTI_Line1);
	}
}

在这里插入图片描述


4.5、主函数调用

在这里插入图片描述

文章来源:https://blog.csdn.net/Mr_robot_strange/article/details/135774293
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。