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

news/2024/6/3 18:12:07 标签: 单片机, stm32, 学习

文章目录

  • 一、前言
  • 二、NVIC中断控制器
    • 2.1、NVIC结构体成员
    • 2.2、抢占优先级和响应优先级
    • 2.3、NVIC的优先级组
  • 三、EXTI外部中断
  • 四、中断实战
    • 4.1、确定连线
    • 4.2、配置中断控制端口
    • 4.3、配置中断端口
    • 4.4、配置中断服务函数
    • 4.5、主函数调用

一、前言

单片机无系统执行逻辑: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、主函数调用

在这里插入图片描述


http://www.niftyadmin.cn/n/5342266.html

相关文章

SQL笔记 -- 数据库结构优化

1. 拆分表(冷热数据分离) 不常用的数据为冷数据,反之则为热数据。如果一个表中的数据存在明显的使用频率差异,那么可以将冷热数据分离。通过这种分解可以提高表的查询效率。对于字段很多且有些字段使用不频繁的表,可以…

tcpdump、wireshark 抓包分析(小白快速上手)

什么是抓包 网络世界中的数据包一般都是不可见的,导致在学习计算机网络的时候会觉得其非常抽象,加大了学习的难度。 自从有了网络包分析工具:tcpdump 和 Wireshark,使不可见的数据包得以可视化。 问题:tcpdump 和 wir…

【SpringBoot】SpringBoot引入接口文档生成工具(Swagger+Knife4j)

一、前言 由于目前工作项目写的接口越来越多了,为了能够更加方便地优化接口,以及整理接口文档,所以就考虑引入接口文档生成工具。目前的接口文档生成工具被提及较多的是Swagger,经过了引入尝试后,Swagger是比较轻松地…

Qt6入门教程 10:菜单栏、工具栏和状态栏

目录 一.菜单栏 1.Qt Designer 1.1添加菜单和菜单项 1.2添加二级菜单 1.3给菜单和菜单项添加图标 1.4给菜单项添加功能 2.纯手写 二.工具栏 1.Qt Designer 1.1添加工具栏按钮 1.2工具栏的几个重要属性 2.纯手写 三.状态栏 1.Qt Designer 2.纯手写 用Qt Creator新…

第二章第14节:EXCEL :计算Excel求平均函数函数AVERAGE 、AVERAGEIF、AVERAGEIFS函数

01,计算Excel求平均函数函数AVERAGE 、AVERAGEIF、AVERAGEIFS函数 它们分别是AVERAGE 、AVERAGEIF、AVERAGEIFS函数, 它们的区别是:AVERAGE是直接求平均值; AVERAGEIF单条件求平均值; AVERAGEIFS多个条件求平均值。 …

Go语言实现新年快乐的效果

在 Go 语言中,你可以使用 fmt 包来实现新年快乐的效果。以下是一个简单的例子: package mainimport ("fmt""time" )func printNewYear() {fmt.Println("\033[31m新年快乐!\033[0m")fmt.Println("\033[32…

日本那霸市最新倾斜模型3DTiles数据

一、简介 那霸市位于日本冲绳本岛南部的西海岸,是冲绳县的县厅所在地,也是冲绳县人口最多的城市那霸市是冲绳县的政治、经济、文化中心,拥有国际机场那霸机场和连接冲绳县外及附近离岛的那霸港,是冲绳县的玄关。那霸市是日本都道…

31、WEB攻防——通用漏洞文件上传JS验证mimeuser.ini语言特性

文章目录 文件上传一、前端验证二、.user.ini 文件上传 检测层面:前端、后端等检测内容:文件头、完整性、二次渲染等检测后缀:黑名单、白名单、MIME检测等绕过技巧:多后缀解析(php5、php7)、截断、中间件特…