当前位置: 首页 > article >正文

中断-MCU

中断

目录

中断

中断的概念

中断的执行过程

中断服务函数

中断的部分专业术语 – 了解

STM32中的中断分类

嵌套向量中断控制器 NVIC

STM32中的中断优先级

中断编程

外部中断(单片机之外)之EXTI中断

相关寄存器

外部中断(EXTI)的配置过程


  • 上一章是采用轮询的方式去检测按键是否按下,但实验发现按键的检测并不灵敏 

    alt text

  • 所以要想要实现按键检测的灵敏,我们就需要增加按键检测占的时间,减小延时,可无论如何,延时不可能减到0,所以就需要用到中断的方式

中断的概念

对于几乎所有的微控制器,中断都是一种常见的特性。中断一般是由硬件(如外设和外部输入引脚)产生的事件,它会引起程序流偏离正常的流程(如给外设提供服务),转去执行其他的流程。

CPU在正常执行程序的过程中,由于内部/外部事件的触发或程序的预先安排引起CPU暂停当前正在运行的程序,而转去执行中断服务子程序,待中断服务子程序执行完毕后,CPU继续执行原来的程序,这一过程称为中断;

中断的执行过程

alt text

  • 1、外设发出中断请求
  • 2、处理器暂停当前执行的任务,保护现场,将当前位置的PC地址压栈; 

    alt text

  • 3、程序跳转到中断服务程序,执行中断服务程序;
  • 4、恢复现场,将栈顶的值回送给PC;
  • 5、跳转到被中断的位置开始执行下一个指令

中断服务函数

  • 中断服务函数:相对于正常子函数,中断服务函数有以下需要注意的地方

1、中断服务函数不能传入参数;
2、中断服务函数不能有返回值;
3、中断服务函数应该做到短小精悍,快入快出,禁止延时性的过程。
4、不要在中断函数中使用printf函数,会带来重入和性能问题。
中断重入:就是在一个中断程序执行过程中又被另一个中断打断,转而又去执行另一个中断程序。

alt text

中断的部分专业术语 – 了解

  • 中断源:引起中断的原因,或者能够发出中断请求信号的来源统称为中断源
  • 中断优先级:中断同时到来,谁先执行。数字越小,优先级越高。
  • 中断响应:中断事件发生,Cortex-M3内核准备执行该事件,即为中断响应。
  • 中断嵌套:可嵌套的内核 -- 中断可以被其他中断打断。(一般都是可嵌套内核)(Cortex-M)
  • 不可嵌套的内核 -- 不可以打断。
  • 中断挂起:中断事件发生了,但是Cortex-M内核还没准备去执行。
  • 中断服务函数: 中断发生后,要执行的程序。(固定格式)
  • 中断通道:对于 Cortex-M 内核所支持的 240 个外部中断,使用了“中断通道”这个概念,因为尽管每个中断对应一个外围设备,但该外围设备通常具备若干个可以引起中断的中断源或中断事件[外围设备与中断源的关系为1对N]。而该设备的所有的中断都只能通过该指定的“中断通道”向内核申请中断。因此,关于中断优先级的概念都是针对“中断通道”的。当该中断通道的优先级确定后,也就确定了该外围设备的中断优先级,并且该设备所能产生的所有类型的中断,都享有相同的通道中断优先级。至于该设备本身产生的多个中断的执行顺序,则取决于用户的中断服务程序。

STM32中的中断分类

alt text

  • 内核(CPU)对中断的管理(内核只是一个处理数据的地方,NVIC才是管理中断的地方

NVIC(嵌套向量中断控制器),支持256个中断(240(内核之外(内核之外就是单片机)的中断)+16(异常:内核自身的中断)),对应的中断通道256个, 对应的中断优先级256个(优先级指的是中断通道的优先级),数字越小,优先级越高,8位数
优先级分组:8组

  • 单片机对中断的管理(单片机没有管理中断的地方,单片机只能产生中断

单片机只能产生中断,(对于中断来说)单片机就是一个大的中断源
并不是所有单片机都能产生240个中断,
例如STM32F103CET6只能产生68个中断,
中断优先级16个
中断,允许优先级相同(优先级相同,谁先发生,谁先处理)
优先级:由两部分组成,抢占和响应
抢占优先级:是否能够发生中断打断的情况(抢占优先级高的能够打断抢占优先级低的,两个抢占优先级一样的不能打断)
响应优先级:抢占优先级一致的中断同时发生。响应优先级高的先执行。(正常情况下没作用,只有一种情况。)
如果两个中断同时发生,两个优先级(抢占和响应)都一样,执行顺序按照表格的顺序,谁在前,谁执行。 优先级分组:5组(内核的3,4,5,6,7) 

alt text


  • 内核优先级是8位数构成,单片机是4位,那么这4位哪几位是抢占,哪几位是响应,引出中断优先级分组

  • 优先级分组:抢占和响应各自占据的位数

  • 已知,内核优先级是8位数组成,高四位是单片机的优先级(也就是单片机的优先级是4位) 

    alt text

  • 中断:异常(内核里的中断)+外部(片上外设)中断

嵌套向量中断控制器 NVIC

  • NVIC :嵌套向量中断控制器,属于内核外设,管理着包括内核和片上所有外设的中断相关的功能。

  • 这里解释一下片上外设与内核外设他们都在芯片里面,但内核外设是在内核CPU里面,片上外设就是内核之外咯。

alt text

alt text

异常是指由于执行指令时的一个错误条件而产生的故障。按照ARM的说法,中断也是与一种异常。
异常:可以理解为是Cortex-M内核的中断,包含错误异常以及其他用于OS支持的系统异常。Stm32中的Cortex-M处理器的异常架构具有多种特性,支持多个系统异常和外部中断。编号1~15的为系统异常,16及以上的则为中断输入(处理器的输入,不必从封装上的I/O引脚上访问)。包括所有中断在内的多数异常﹐都具有可编程的优先级,一些系统异常则具有固定的优先级。
不同Cortex-M3或Cortex-M4微控制器的中断源的编号(1~240)可能会不同,优先级也可能会有所差异。这是因为为了满足不同的应用需求,芯片设计者可能会对Cortex-M3或Cortex-M4设计进行相应的配置。

  • 内核的中断

alt text

  • 外部中断

alt text

STM32中的中断优先级

对于Cortex-M处理器(包括ARMv6-M和ARMv7-M)异常是否能被处理器接受以及何时被处理器接受并执行异常处理,是由异常的优先级和处理器当前的优先级决定的。
更高优先级的异常(优先级编号更小)可以抢占低优先级的异常(优先级编号更大),这就是异常/中断嵌套的情形。
有些异常(复位,NMI和 HardFault)具有固定的优先级,其优先级由负数表示,这样,它们的优先级就会比其他的异常高。其他异常则具有可编程的优先级﹐范围为0~255。
NVIC 支持由软件指定的优先级。通过对中断优先级寄存器的8位 IPR_N 区执行写操作,来将中断的优先级指定为 0~255,见中断优先级寄存器。硬件优先级随着中断号的增加而降低。 0 优先级最高, 255 优先级最低。指定软件优先级后,硬件优先级(默认优先级)无效。

利用系统控制块(SCB)中一个名为优先级分组的配置寄存器(属于SCB中的应用中断和复位控制寄存器)将每个具有可编程优先级的优先级配置寄存器可被分为两部分。
上半部分(左边的位)为分组(抢占)优先级﹐而下半部分(右边的位)则为子优先级。事实上stm32(单片机)只用了4位优先级(内核的高4位),分组时从优先级高位向低位方向分组。

alt text

子优先级就是响应优先级 抢占和响应各自占据的位数,例如0分组,抢占7位(0~2^7-1),响应是1位(0-1)

单片机的优先级分组是在内核分组的基础上开始分组的,因为单片机优先级的位数是内核优先级位数的高4位,也就是4~7,所以单片机优先级分组从第三组开始,3~7(一共5组),如第三个分组,在单片机上给抢占的是4位,响应的是0位

中断编程

  • 一般中断使能一般有两个门,外设使能相应的中断然后送入NVIC再使能,外设使能中断是小门,NVIC使能中断是大门,只有都使能才能响应中断。

-- 1.使能外设某个中断,这个具体由每个外设的相关中断使能位控制。

-- 2.配置中断优先级分组,然后初始化 NVIC_InitTypeDef 结构体,设置抢占优先级和子优先级,使能中断请求。NVIC_InitTypeDef 结构体在固件库头文件 misc.h 中定义。

1、配置中断优先级分组 

alt text

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

2、初始化 NVIC_InitTypeDef 结构体

alt text

-- NVIC_IROChannel:用来设置中断源,不同的中断中断源不一样,且不可写错,即使写错了程序也不会报错,只会导致不响应中断。具体的成员配置可参考stm32f10x.h 头文件里面的 IRQn_Type 结构体定义,这个结构体包含了所有的中断源。 

alt text

NVIC_IRQChannelPreemptionPriority:抢占优先级,具体的值要根据优先级分组来确定。
NVIC_IRQChannelSubPriority:子优先级(响应优先级),具体的值要根据优先级分组来确定 。
NVIC_IRQChannelCmd:中断使能(ENABLE)或者(DISABLE)。操作的是 NVIC_ISER 和 NVIC_ICER 这两个寄存器。

   NVIC_InitTypeDef NVIC_InitStructure = {0}; 
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能(使能哪个中断通道,就要写哪个(必须写)中断服务函数)
	NVIC_Init(&NVIC_InitStructure);

外部中断(单片机之外)之EXTI中断

-- 这里的外部中断是指由外部条件触发例如按键触发(GPIO),对于互联型产品(F107),外部中断/事件控制器由20个产生事件/中断请求的边沿检测器组成,对于其它产品(我们这里是F103),则有19个能产生事件/中断请求的边沿检测器。 

alt text

-- 中断线每次只能连接到 1 个 IO 口上,这样就需要通过配置来决定对应的中断线配置到哪个 GPIO 上了。112通用I/O端口以下图的方式连接到16个外部中断/事件线上:

alt text

-- 16个中断线的不是每个中断都有独立的中断服务函数,IO口外部中断在中断向量表中只分配了7个中断向量,也就是只能使用7个中断服务函数

-- 对应的中断服务函数,直接去启动文件里面找以防写错。 

alt text

-- 信号线上打一个斜杠并标注“20”字样,这个表示在控制器内部类似的信号线路有 20 个,这与 EXTI 总共有 20 个中断/事件线是吻合的。所以我们只要明白其中一个的原理,那其他 19 个线路原理也就知道了

alt text

alt text

中断与事件的区别:

中断:需要CPU参与,需要调用软件的中断服务函数才能完成中断后产生的结果
事件:靠脉冲发生器产生一个脉冲,进而由硬件自动完成这个事件产生的结果,当然相应的联动部件需要先设置好,触发TIM计时,AD转换等,事件不要软件的参与,降低了CPU的负荷,而且硬件速度快于软件速度

相关寄存器

  • 外部中断配置寄存器 

    alt text

  • 选择中断线

-- 在配置中断线时一定要先使能AFIO外设的时钟,因为配置中断线是用到AFIO外设的寄存器,我们知道配置寄存器必须要有时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);	//exti的时钟(外设也有自己的时钟)

外部中断(EXTI)的配置过程

  • 1、配置要中断检测的IO引脚模式为:浮空输入模式,具体查阅参考手册8.1.11以及自己的硬件电路来设置

  • 2、把要中断检测的IO引脚映射到对应的EXTI中断线上,通过AFIO来设置。 

    alt text

  • 3、配置对应的EXTI中断线,触发的边沿、使能屏蔽位

  • 4、通过NVIC配置EXTI中断的优先级、使能NVIC的EXTI中断 

    alt text

  • exti.c

#include "exti.h"

void exti_init(void)
{
	//时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);	//exti的时钟(外设也有自己的时钟)
	//IO
	GPIO_InitTypeDef GPIO_InitStructure = {0};						//定义结构体变量,并且将结构体变量赋初值
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; 						//引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;			//速度
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	//浮空模式
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//外设	EXTI
	
	EXTI_InitTypeDef EXTI_InitStructure = {0};//初始化
	EXTI_InitStructure.EXTI_Line = EXTI_Line0;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//EXTI比较特殊,这里设置为中断模式,就不用设置中断源了
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	
	//中断 NVIC
	
	NVIC_InitTypeDef NVIC_InitStructure = {0}; 
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能(使能哪个中断通道,就要写哪个(必须写)中断服务函数)
	NVIC_Init(&NVIC_InitStructure);
	
	//其他
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
	
}
//只要使能中断通道,就一定要写中断服务函数

uint8_t key_it_flag = 0;
//中断服务函数
void EXTI0_IRQHandler(void)
{
	//1.判断哪个中断发生
	if(EXTI_GetITStatus(EXTI_Line0)  == SET)//SET就是1
	{
		//2.处理中断
		key_it_flag = 1;
		//3.清理中断 	(一定要清除,否则中断会一直触发)
		EXTI_ClearITPendingBit(EXTI_Line0);
	}
	
}


  • main.c
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置优先级分组(相当于内核的第五组)因为在整个工程里只用分一次,所以写在main函数

http://www.kler.cn/a/314760.html

相关文章:

  • Linux设置socks代理
  • 【教程】华南理工大学国际校区宿舍门锁声音设置
  • OpenHarmony4.1蓝牙芯片如何适配?触觉智能RK3568主板SBC3568演示
  • Dial-insight:利用高质量特定领域数据微调大型语言模型防止灾难性遗忘
  • 洞察鸿蒙生态,把握开发新机遇
  • 常用中间件介绍
  • HTML粉色烟花秀
  • python新手的五个练习题
  • MySQl索引事务(B树)
  • 基于 K8S kubernetes 的常见日志收集方案
  • 大模型如何学习数据
  • NLP 文本分类核心问题
  • LangChain教程 - 构建一个检索增强生成 (RAG) 应用程序
  • 面试金典题8
  • go webapi上传文件
  • 【Linux】Docker:离线主机部署
  • 【Temporal】日志打印控制
  • 【AI视频】AI虚拟主播制作网站推荐
  • 深度学习02-pytorch-06-张量的形状操作
  • 基于深度学习的智能电网优化
  • Java异常架构与异常关键字
  • Spring后端直接用枚举类接收参数,自定义通用枚举类反序列化器
  • IT行业:未来发展的无限可能
  • 【医学半监督】置信度指导遮蔽学习的半监督医学图像分割
  • 51单片机-系列-数码管中断和定时器
  • Lsposed Java HOOK原理及检测