嵌入式学习笔记——STM32的中断控制体系
创始人
2025-05-29 06:44:34
0

STM32的中断控制体系

  • 前言
  • STM32中断的概念
  • 中断类型
  • 中断控制
    • 常用控制函数
    • 区分中断源与中断信号
  • 配置中断
    • 优先级
    • 分组问题

前言

上一篇中,借着串口接受的问题,简要说了一下串口中断的作用和用法,本文将对STM32的中断控制体系做个介绍。

STM32中断的概念

关于中断的概念,在上一篇中已经做了介绍了,说通俗点就是程序正常情况下是在while(1)内运行着相关的任务,例如下图中的任务1,任务2,在没有中断的时候,整个代码的运行流程就是完成初始化,然后在while(1)内一直循环里面的任务,此时如果任务1内有大的阻塞延时,类似串口等待接收,LED灯while死等延时这些都会阻塞整个while(1)的运行时间,导致执行效率严重低下,这种情况是不能满足日常需求的,所以在实际产品中很少有使用阻塞式的延时和while死等的情况。为了解决这个问题,这时就需要有中断的加入了。
在这里插入图片描述
加入中断后的运行流程图就变成了下图的情况,首先,中断是一个内核功能,不属于片上外设,但是使用过程中也需要初始化;其次,初始化后,会有一个与之对应的中断服务函数,上面的那些具有阻塞的功能通过中断服务函数内的各种标志位就可以实现变阻塞为不阻塞了;当初始化中断对应的条件满足时就会产生一个中断信号,这时CPU会停止当前任务,转而去到对应的中断服务函数里面,将中断服务函数内的任务先完成,完成后再回来继续执行原本的任务。编程时只需要判断对应的标志位即可解决上面的阻塞问题。
需要注意的是,中断是可以解决阻塞的问题,但是中断服务函数的本身也不能有延时、循环、阻塞程序,紧急事件是实时响应的,紧急事件不能执行太久。
在这里插入图片描述
在这里插入图片描述
总的来说,中断对于正常运行的CPU来说就是一个异常事件,而且异常事件的优先级高于正常运行的事件的优先级,发生异常必须先解决异常才可以重新回到正常运行。上一篇中的空闲中断和接收中断就是这样,那么,STM32的中断到底是怎么运行和管理的呢。

中断类型

首先,中断的控制是在内核里面的,中断的相关内容是有ARM公司设计的,在处理器内部会有一个叫做嵌套向量中断控制器NVIC得中断处理器,他就是专门用来管理整个STM32的中断问题的,其中中断的主要来源有两个,一个是处理器的内核出现了故障会触发系统异常,进而进入中断二是片上外设触发了其相关的中断信号也会进入中断,像上一篇的出口接收中断和空闲中断就是属于后者,是外设产生的中断。
在这里插入图片描述

中断控制

在上一篇的配置中,已经使用到了NVIC的相关控制,关于这部分控制是官方封装好的函数,在使用过程中调用即可。也就是说,对于开发者来说,中断的控制只需要调用函数就可以了,这里借用上一篇调用的代码:
NVIC中断控制器做配置的时候流程:
第一步:配置优先级分组 (主函数配置)
第二步:合成优先级
第三步:分配优先级
第四步:使能对应的中断源 (在对应的片上外设初始化函数中)

//NVIC控制器配置
NVIC_SetPriorityGrouping(7-2);//设置中断的优先组别(111-110-101-100)
u32 pri=NVIC_EncodePriority(7-2,0,0);//设置抢占优先级为0,响应优先级为0
NVIC_SetPriority(USART1_IRQn,pri);   //将对应的优先级设置映射到对应的中断
NVIC_EnableIRQ(USART1_IRQn);         //使能中断源

在这里插入图片描述

常用控制函数

1.中断分组函数,此函数用于对整个工程进行中断分组
void NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
位置:core_cm4.h------1435行
返回值:空
参数:uint32_t PriorityGroup   分组中需要写入的值
传参:7-占先的位数
分组整个工程都要一样,可以只配置一次,只需要在主函数使用一次即可
2.使能中断源配置函数,此函数用于使能对应的中断源
void NVIC_EnableIRQ(IRQn_Type IRQn)
位置:core_cm4.h------1467行
返回值:空
形参:IRQn_Type IRQn很明显此处形参是个结构体,需要使用结构体内规定好的名称 
传入对应的片上外设中断源----放中断源名字  例如:串口:USART1_IRQn
作用:使片上外设的中断能够使用   核心级别中断使能

关于此函数的形参:IRQn_Type IRQn很明显此处形参是个结构体,需要使用结构体内规定好的名称 需要用时直接跳转过去复制即可。
注意,此处的形参编程时一定要跳转到stm32f4xx.h中找到对应的,不可以自己随意修改。
在这里插入图片描述

3.中断优先级配置函数,此函数用于设置对应中断源的中单优先级
void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
位置:core_cm4.h------1550行
返回值:空
形参:IRQn_Type IRQn, uint32_t priority
IRQn_Type IRQn:中断源和上一个一样的中断源名称,需要去stm32f4xx.h复制
uint32_t priority:优先级(占先和次级一起的优先级)
4.  优先级合成函数,由于优先级写入时是一起写入的,但是分类时又是分开计算的,为了避免写入出错,官方给了一个合成函数,将分组、抢占优先级和响应优先级传入后此函数会返回需要写入的优先级值。
uint32_t  NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority)
位置:core_cm4.h------1592行
返回值:u32类型的值   优先级uint32_t priority
形参:uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority
uint32_t PriorityGroup:优先级分组
uint32_t PreemptPriority:占先优先级
uint32_t SubPriority:次级优先级用法:u32 pri= NVIC_EncodePriority(7-2,3,2);NVIC_SetPriority(USART1_IRQn, pri);

从上面的注释中,可以清除的看出NVIC控制器的作用:
①对中断优先级做分组
② 接收来自中断的请求
③ 配置中断的优先级
④ 使能外设的中断源
具体的代码在"core_cm4.h"中,查看步骤如下图所示,点击main.c前方1号框所在位置的"+“号,然后选择"core_cm4.h”,下滑就可以找到相关函数,对应的函数描述就在其上方注释。
在这里插入图片描述

区分中断源与中断信号

仔细回想上一篇中的配置过程,关于中断配置,除了上面的NVIC控制器的相关操作,还在USART的出事后配置中,使能了接收中断和空闲中断这两个控制位,那么这个使能与上面的中断源使能有什么区别呢。
中断源:一个片上外设 USART1独立的中断源 USART2也是独立的中断源
中断信号:指的是每一个中断源下,会有多个触发条件,例如串口1的接收中断和空闲中断。
也就是说,中断源相当于房子里的总电闸,而中断信号相当于房间里灯的开关,插座的开关,电视的开关。要开灯,不仅要打开总闸,还需要开启对应的分开关才行。
所以在中断配置过程中不仅需要配置对应的中断源使能,还需要使能具体的中断信号。
知道了中断的管理方式,接下来就是怎么管理的问题了。

配置中断

在上述管理的相关函数中,涉及了多个中断里面的名词,像分组,占先优先级、次级优先级、占先位数等等,看起来是有些混乱,接下来就来解释一下这些东西的具体作用。

优先级

首先,需要搞清楚优先级的定义,对于Cortex-M处理器的异常是否能被处理器接受以及何时被处理器接受并执行异常处理,是由异常的优先级和处理器当前的优先级决定的。
更高优先级的异常可以抢占低优先级的异常,这就是异常/中断嵌套的情形,也就是上面提及的占先优先级。
有些异常(例如:复位,Sys_Tick等)具有固定的优先级,其优先级由负数表示,这样,它们的优先级就会比其他的异常高。
在这里插入图片描述
其他异常则具有可编程的优先级﹐范围为0~255。依据以上描述优先级被分为三类:
1.占先优先级:程序员进行配置的,具备抢占功能
2.次级优先级:程序员进行配置的,不具备抢占功能
3.自然优先级:系统自己配置(不需要我们管)
优先级:数字越小,优先级越高

分组问题

解决了优先级,接下来就要高清楚分组的问题了。这个分组其实就是决定上面提到的占先优先级的在优先级控制寄存器中的位数和次级优先级在优先级控制寄存器的位数,先看看M3和M4的权威指南关于分组的描述:
在这里插入图片描述
在这里插入图片描述
ARM在涉及的时候一共预留了一个8位寄存器来实现优先级控制的编程,理论上占先优先级和次级优先级会有2^8=256种组合方式。
但是,由于过多的中断优先级分组会影响单片机的性能,所以ST公司在实际设计STM32芯片的时候就丢弃了LSB也就是这个八位寄存器的第四位,只保留了四位用来做优先级的控制编程,这样一来,STM32的优先级分组就只有2的四次方种,也就是16种组合。
在这里插入图片描述
ARM体系下优先级配置寄存器总共由8位,占先和次级同时使用这个寄存器
中断的优先级共有256种
ST体系下,ST公司对ARM公司的中断进行了裁剪,只是用寄存器的高4位
中断的优先级共有16种。
可能还是有点没说清楚,来看下表吧,由于舍去了第四位,占先优先级和次级优先级这两个一起瓜分这四位,通过这四位来配置中断的优先级,其中的配置方式如下表:

写入的分组数占先在优先级寄存器中的位数次级在优先级寄存器中的位数此模式下中断的具体优先级数
7(111)0位 (范围:无)4位(范围:0-15)16种
6(110)1位 (范围:0-1)3位(范围:0-7)16种
5(101)2位 (范围:0-3)2位(范围:0-3)16种
4(100)3位(范围:0-7)1位(范围:0-1)16种
3(011)4位(范围:0-15)0位(范围无)16种
2(011)4位(范围:0-15)0位(范围无)16种
1(011)4位(范围:0-15)0位(范围无)16种
0(011)4位(范围:0-15)0位(范围无)16种

举几个栗子吧:
1.假设在这个系统中,我们不需要占先优先级,此时就可以将占先的位置零,让优先级控制寄存器独享四位,这样的话,整个系统的中断之间就不会出现打断和抢占,当同一时刻有多个中断到来时,会优先执行次级优先级高的中断,执行完毕后才会转去下一个优先级相对高的中断。
2.假设我们在整个系统中需要各种中断嵌套,这时就可以不为次级优先级分配优先级控制寄存器的位数,让占先优先级独享四位,这样就可以有(0-15)16种中断嵌套,其中优先级最高的可以打断任意中断。

相关内容

热门资讯

Altium Designer... 目录Altium Designer(AD)软件使用记录15-PCB布线部分之优化和DRC处理一、线路...
通俗易懂了解Hadoop(更新... 从本书第5、6、7、8章,学习云计算开发相关知识 这是第五章 文章目录Hadoo...
LeetCode-198. 打... 目录暴力递归动态规划 题目来源 198. 打家劫舍 暴力递归 class Solution {pub...
js学习11(客户端存储) 目录 web storage IndexDB   web storage ### 前言࿱...
target.closest妙... 首先看下MDN:Element.closest() - Web APIs | MDN ...
并发编程(一)-Thread ... 一、什么是线程线程(英语:thread)是操作系统能够进行...
小白学Pytorch系列--T... 小白学Pytorch系列–Torch API (9) Spectral Ops stft 短时傅立...
Java二叉树的前中后序遍历 Java二叉树的前中后序遍历1.前序遍历1.1前序遍历概念1.2前序遍历习题2.中序遍历2.1中序遍...
遗传算法原理及案例解析 一、遗传算法原理 遗传算法—进化算法(Genetic Algorithm GA...
朴素贝叶斯学习报告 报告 朴素贝叶斯算法描述公式:  案例计算步骤: 一个数据集中有两个样本...
算法小课堂(一)暴力枚举 、 目录 一、概念 1.1相关概念 1.2应用场景 1.3局限性 二、相关问题 2.1例题1:统计 ...
OpenHarmony之doc... Docker使用示例 docker移植至OpenHarmony的过程可参考:https...
懒人专用高并发:Actor模型 传统多线程实现方式 public class MultiThreadExample implemen...
WEB安全 HTML基础 1.简单的HTML页面架构 charset  编码 gbk gbk2...
算法基础---基础算法(二) 文章目录 高精度         高精度加法高精度减法高精度乘法高精度除法前缀和 一维前缀和二维前缀...
【Docker】镜像的原理定制... 文章目录镜像是什么UnionFS(联合文件系统)Docker镜像加载原理...
vue3常用 Composit... 二、常用 Composition API 官方文档 1.拉开序幕的setup语法糖 理解࿱...
【MySQL】实验二 简单查询 目录 1. 查询课程代号为1301的成绩不及格的成绩信息 2. SQL查询:查询employee的j...
spring启动时加载外部配置... 平常同学们使用spring搭建工程时一些应用配置信息(例如数据库的连接配置、中间件的连...
《他是谁》爆火,优酷的成功并非... 今年国产电视剧市场又进入了新一轮的爆款时代,观众在前面刚送走《三体》《狂飙》ÿ...