【STM32学习笔记】NVIC中断优先级管理的详细解析
一.描述
什么是中断,我们可以理解为你正在打游戏,这个时候有人在敲门,你放下游戏去开门,开完门后你接着打游戏。那么开门这个事件就代表中断,接着打游戏就代表你完成中断事件接着运行主函数。
1.中断的类型
CM3内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。
STM32F10系列并没有使用CM3内核的全部东西,而是只用了它的一部分。
STM32F10系列有84个中断,包括16个内核中断和68个可屏蔽中断,具有16级可编程的中断优先级。
STM32F103系列上面,又只有60个可屏蔽中断(在107系列才有68个)。
这就是那60个外部中断的一部分,详细可以查看stm32中文参考手册9.1.2
2.中断优先级分组
该分组的设置是由 SCB->AIRCR 寄存器的 bit10~8 来定义的。
组 |
AIRCR[10:8] |
IP bit[7:4]分配情况 |
分配结果 |
0 |
111 |
0:4 |
0位抢占优先级,4位响应优先级 |
1 |
110 |
1:3 |
1位抢占优先级,3位响应优先级 |
2 |
101 |
2:2 |
2位抢占优先级,2位响应优先级 |
3 |
100 |
3:1 |
3位抢占优先级,1位响应优先级 |
4 |
011 |
4:0 |
4位抢占优先级,0位响应优先级 |
通过赋予SCB->AIRCR寄存器中第8位到第10位的值将这些中断类型分为5个组。
不同的分组中,AIRCR寄存器中的第4位到第8位管理优先级的情况不同。
比如常用的第2组,这4位中两位是管理抢占优先级的,两位是管理响应优先级的。按照从左到右的顺序。
3.抢占优先级和响应优先级是什么
抢占优先级:抢占优先级是指中断的打断优先级,抢占优先级高的中断可以打断正在执行的抢占优先级低的中断。
响应优先级:响应优先级是指中断的响应顺序,响应优先级只有在抢占优先级相同的情况下才有意义。当抢占优先级相同时,俩个中断同时发生,响应优先级高的中断先响应。
打个比方抢占优先级高的就可以直接把正在买饭的人丢到后面去,而响应优先级高的能插队到正在买饭人的后面,等他买完饭就可以执行。
高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。
抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。
抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。 如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;
注意:俩个优先级中,数字越小表示的优先级越高。
4.中断优先级分组函数
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;
}
这是那5个组的宏定义
#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 */
配置的时候可以选择其中一个
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);
在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);
分别的作用是挂起某中断,读某中断状态,解除挂起的某中断。
5.中断优先级初始化函数
这是需要设置的成员变量
ypedef struct
{
uint8_t NVIC_IRQChannel; //设置中断通道
uint8_t NVIC_IRQChannelPreemptionPriority;//设置抢占优先级
uint8_t NVIC_IRQChannelSubPriority; //设置响应优先级
FunctionalState NVIC_IRQChannelCmd; //使能/使能
} NVIC_InitTypeDef;
这样就完成了初始化的配置
总结
在使用中断的时候
系统运行后先设置中断优先级分组。
调用函数:void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);整个系统执行过程中,只设置一次中断分组。
针对每个中断,设置对应的抢占优先级和响应优先级。
调用函数:void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可。
作者:小小嵌入式