当前位置:网站首页>NVIC中断优先级管理
NVIC中断优先级管理
2022-07-07 06:26:00 【一只大喵咪1201】
作者:一只大喵咪1201
专栏:《STM32学习》
格言:你只管努力,剩下的交给时间!
描述
中断可以看作是一个事件。
比如,你正在家里学习,突然来了电话,你只能停下当前的学习去接电话,在接电话的过程中又有人敲门,你只好放下电话去开门,然后再拿起电话继续打电话,当挂掉电话后又继续前面的学习。
在上面的例子中,学习是一直在进行的事件,而打电话是一个中断事件,在打电话过程中有人敲门又是一个中断事件。
STM32中的中断也是这个道理,在执行主程序的过程中会有其他事件打断这个过程,进入到事件中的程序去执行,执行完中断程序后再返回主程序继续执行,这样就是中断。
🦔中断类型
- CM3内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。
- STM32F10系列并没有使用CM3内核的全部东西,而是只用了它的一部分。
- STM32F10系列有84个中断,包括16个内核中断和68个可屏蔽中断,具有16级可编程的中断优先级。
- STM32F103系列上面,又只有60个可屏蔽中断(在107系列才有68个)。
这里的外部中断和可屏蔽中断都是一个意思,是指不包括内核中断的所有中断。
此图便是本喵使用的STM32F103ZET6的60个外部中断。
中断优先级分组
有这么多类型的中断,是怎么管理的呢?STM32通分组的方式来管理这些中断。
该分组的设置是由 SCB->AIRCR 寄存器的 bit10~8 来定义的。
通过赋予SCB->AIRCR寄存器中第8位到第10位的值将这些中断类型分为5个组。
不同的分组中,AIRCR寄存器中的第4位到第8位管理优先级的情况不同。
比如常用的第2组,这4位中两位是管理抢占优先级的,两位是管理响应优先级的。按照从左到右的顺序。
这时又有疑惑了,抢占优先级和响应优先级是什么呢?
🦔抢占优先级和响应优先级
抢占优先级:
- 抢占优先级是指中断的打断优先级,抢占优先级高的中断可以打断正在执行的抢占优先级低的中断。
响应优先级
- 响应优先级是指中断的响应顺序,响应优先级只有在抢占优先级相同的情况下才有意义。当抢占优先级相同时,俩个中断同时发生,响应优先级高的中断先响应。
俩个优先级中,数字越小表示的优先级越高。
举例说明:
- 假定设置中断优先级组为2
- 然后设置
- 中断3(RTC中断)的抢占优先级为2,响应优先级为1。
- 中断6(外部中断0)的抢占优先级为3,响应优先级为0。
- 中断7(外部中断1)的抢占优先级为2,响应优先级为0。
那么的这三个中断的优先级顺序就是
- 中断7>中断3>中断6
当抢占优先级和响应优先级都相同的时候,哪个中断先发生就先执行哪个中断程序。
注意:
中断分组仅在系统的初始化完成后设置一次。如果在后面的程序中有修改分组就会混乱。
比如当使用的是2组的时候
优先级管理位如上图设置,此时的抢占优先级是2,响应优先级是2。
在使用这个分组后再将分组设置成3组的时候,此时抢占优先级是5,响应优先级是0。
如此一来,优先级的管理就混乱了。
🦔中断优先级分组函数
ST官方提供了设置分组的库函数,不用我们自己去挨个设置寄存器的值。
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
/* Check the parameters */
assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
/* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */
SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}
这是中断优先级分组的函数,他在ST官方固件库的misc.c源文件中。
通过函数的定义我们可以看到,它的实质就是在配置AIRCR寄存器。
#define NVIC_PriorityGroup_0 ((uint32_t)0x700) /*!< 0 bits for pre-emption priority 4 bits for subpriority */
#define NVIC_PriorityGroup_1 ((uint32_t)0x600) /*!< 1 bits for pre-emption priority 3 bits for subpriority */
#define NVIC_PriorityGroup_2 ((uint32_t)0x500) /*!< 2 bits for pre-emption priority 2 bits for subpriority */
#define NVIC_PriorityGroup_3 ((uint32_t)0x400) /*!< 3 bits for pre-emption priority 1 bits for subpriority */
#define NVIC_PriorityGroup_4 ((uint32_t)0x300) /*!< 4 bits for pre-emption priority 0 bits for subpriority */
以上5个宏定义就是中断优先级分组函数的入口参数,需要分成哪一组就将哪一组对应的参数传入函数中。
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
如此便将这60个外部中断分好了组。
中断优先级设置
虽然分好了组,方便管理了,但是具体是哪个中断发生,它的优先级是多少还需要进行具体的设置。
🦔中断优先级设置寄存器
typedef struct
{
__IO uint32_t ISER[8]; /*!< Offset: 0x000 Interrupt Set Enable Register */
uint32_t RESERVED0[24];
__IO uint32_t ICER[8]; /*!< Offset: 0x080 Interrupt Clear Enable Register */
uint32_t RSERVED1[24];
__IO uint32_t ISPR[8]; /*!< Offset: 0x100 Interrupt Set Pending Register */
uint32_t RESERVED2[24];
__IO uint32_t ICPR[8]; /*!< Offset: 0x180 Interrupt Clear Pending Register */
uint32_t RESERVED3[24];
__IO uint32_t IABR[8]; /*!< Offset: 0x200 Interrupt Active bit Register */
uint32_t RESERVED4[56];
__IO uint8_t IP[240]; /*!< Offset: 0x300 Interrupt Priority Register (8Bit wide) */
uint32_t RESERVED5[644];
__O uint32_t STIR; /*!< Offset: 0xE00 Software Trigger Interrupt Register */
} NVIC_Type;
在ST官方的固件库中的misc.h中定义了这样一个结构体,结构体的寄存器就是用来设置中断的优先级的。
- ISER[8]:ISER 全称是:Interrupt Set-Enable Registers,这是一个中断使能寄存器组。STM32F103 的可屏蔽中断只有 60 个,所以对我们来说,有用的就是两个(ISER[0]和 ISER[1]),总共可以表示 64 个中断。而 STM32F103 只用了其中的前 60 位。ISER[0]的 bit 0到31 对应中断0到31。ISER[1]的 bit 0到27 对应中断 32~59;这样总共 60 个中断就分别对应上了。你要使能某个中断,必须设置相应的 ISER 位为 1。
- ICER[8]:全称是:Interrupt Clear-Enable Registers,是一个中断除能寄存器组。该寄存器组与 ISER 的作用恰好相反,是用来清除某个中断的使能的。这里要专门设置一个 ICER 来清除中断位,而不是向 ISER 写 0 来清除,是因为 NVIC 的这些寄存器都是写 1 有效的,写 0 是无效的。
- ISPR[8]:全称是:Interrupt Set-Pending Registers,是一个中断挂起控制寄存器组。每个位对应的中断和 ISER 是一样的。通过置 1,可以将正在进行的中断挂起,而执行同级或更高级别的中断。写 0 是无效的。
- ICPR[8]:全称是:Interrupt Clear-Pending Registers,是一个中断解挂控制寄存器组。其作用与 ISPR 相反,对应位也和 ISER 是一样的。通过设置 1,可以将挂起的中断接挂。写 0 无效。
- IABR[8]:全称是:Interrupt Active Bit Registers,是一个中断激活标志位寄存器组。对应位所代表的中断和 ISER 一样,如果为 1,则表示该位所对应的中断正在被执行。这是一个只读寄存器,通过它可以知道当前在执行的中断是哪一个。在中断执行完了由硬件自动清零。
- IP[240]:全称是:Interrupt Priority Registers,是一个中断优先级控制的寄存器组。这个寄存器组相当重要STM32 的中断分组与这个寄存器组密切相关。STM32F103只用到了其中的前 60 个。IP[59]到IP[0]分别对应中断 59~0。而每个可屏蔽中断占用的 8bit 并没有全部使用,而是只用了高 4 位。这 4 位,又分为抢占优先级和响应优先级。抢占优先级在前,响应优先级在后。而这两个优先级各占几个位又要根据 SCB->AIRCR 中的中断分组设置来决定。
在ST官方的固件库的core_cm3.h中有几个库函数
static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn);
static __INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn);
static __INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn);
分别的作用是挂起某中断,读某中断状态,解除挂起的某中断。
🦔中断优先级初始化函数
ST官方同样提供了中断优先级的设置函数,不用我们去挨个设置寄存器。
typedef struct
{
uint8_t NVIC_IRQChannel; //设置中断通道
uint8_t NVIC_IRQChannelPreemptionPriority;//设置抢占优先级
uint8_t NVIC_IRQChannelSubPriority; //设置响应优先级
FunctionalState NVIC_IRQChannelCmd; //使能/使能
} NVIC_InitTypeDef;
在misc.h中定义了这样一个结构体,成员变量分别代表着
- 中断通道,也就是哪个类型的中断。
- 抢占优先级。
- 响应优先级。
- 中断使能。
而使用这个结构体和GPIO的使用方法类似
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;// 抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;// 子优先级位2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据上面指定的参数初始化NVIC寄存器
以上便完成了中断优先级的初始化。
总结
在使用中断的时候
系统运行后先设置中断优先级分组。
调用函数:void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);整个系统执行过程中,只设置一次中断分组。针对每个中断,设置对应的抢占优先级和响应优先级。
调用函数:void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可。
边栏推荐
- 【ChaosBlade:节点磁盘填充、杀节点上指定进程、挂起节点上指定进程】
- QT charts use (rewrite qchartview to realize some custom functions)
- systemd
- LeetCode 715. Range module
- 指针进阶,字符串函数
- OpenGL frame buffer
- 实现自定义内存分配器
- Greenplum6.x重新初始化
- Digital triangle model acwing 275 Pass a note
- With an annual salary of 50W, Alibaba P8 will come out in person to teach you how to advance from testing
猜你喜欢
指针进阶,字符串函数
Oracle makes it clear at one time that a field with multiple separators will be split into multiple rows, and then multiple rows and columns. Multiple separators will be split into multiple rows, and
数字三角形模型 AcWing 275. 传纸条
Greenplum 6.x version change record common manual
Troublesome problem of image resizing when using typora to edit markdown to upload CSDN
Greenplum6.x搭建_环境配置
Category of IP address
面试题:高速PCB一般布局、布线原则
使用Typora编辑markdown上传CSDN时图片大小调整麻烦问题
LeetCode 715. Range 模块
随机推荐
JS operation
Image segmentation in opencv
Greenplum 6.x build_ install
硬件大熊原创合集(2022/06更新)
Esp32-ulp coprocessor low power mode RTC GPIO interrupt wake up
Quick sorting (detailed illustration of single way, double way, three way)
面板显示技术:LCD与OLED
模拟卷Leetcode【普通】1609. 奇偶树
Port occupation troubleshooting
Simulation volume leetcode [general] 1609 Parity tree
cmake命令行使用
MySQL主从延迟的解决方案
年薪50w阿裏P8親自下場,教你如何從測試進階
NCS Chengdu New Electric interview Experience
Cmake command line use
Tronapi wave field interface - source code without encryption - can be opened twice - interface document attached - package based on thinkphp5 - detailed guidance of the author - July 6, 2022 - Novice
Count sort (diagram)
2022-07-06 Unity核心9——3D动画
Recommended by Alibaba P8, the test coverage tool - Jacobo is very practical
Opencv converts 16 bit image data to 8 bits and 8 to 16