14.1、中断优先级分组
14.2、NVIC中断优先级设置
14.3、NVIC总结
参考资料:《STM32F1开发指南--库函数版》4.5小节
STM32 有 84 个中断,包括 16 个内核中断和 68 个可屏蔽中断,具有 16 级可编程的中断优先级。而我们常用的就是这 68 个可屏蔽中断,但是 STM32 的 68 个可屏蔽中断,在 STM32F103 系列上面,又只有 60 个(在 107 系列才有 68 个)。因为我们开发板选择的芯片是 STM32F103 系列的所以我们就只针对 STM32F103 系列这 60 个可屏蔽中断进行介绍。
14.1、中断优先级分组
(1)中断管理方法:首先,在STM32系统初始化的时候对中断进行分组,从组0~组4,分组的依据是由寄存器SCB->AIRCR确定的,换句话说,是在寄存器SCB->AIRCR中完成分组配置的。同时,对每一个中断设置一个抢占优先级和响应优先级。
PS:抢占优先级和响应优先级的设置依据是:每一个中断的ip寄存器都有4位,不同的分组配置不同的4位,具体可看下表:(同组的中断,响应优先级和抢占优先级配置是相同的)
前文所说的16级可编程中断意思就是,每个中断的ip寄存器共有四位可以配置,那么2^4=16,因此说共有16级可编程中断。同时,分组的作用也很明确了,就是确定中断的抢占优先级和响应优先级的配置情况。
(2)抢占优先级和响应优先级的区别
1、两个中断,高抢占优先级有打断低抢占优先级的权力;
2、两个中断,抢占优先级相同时,高响应优先级不能打断低响应优先级;
3、两个中断,抢占优先级相同 ,并且两个中断同时发生,那么高响应优先级会先执行;
4、两个中断,抢占优先级和响应优先级相同,则哪个中断先发生就先执行哪个中断。
PS:怎么判断抢占优先级的高低?
假设,将两个中断设置为分组2,那么这两个中断就都有两位抢占优先级和两位响应优先级,抢占优先级可以设置为0~3,且,数字越低代表抢占优先级越高。(0>1>2>3)
举例说明:
设置中断优先级分组为2,设置中断3的抢占优先级为2,响应优先级为1;中断6的抢占优先级为3,响应优先级为0;中断7的抢占优先级为2,响应优先级为0。
那么上述三个中断的优先顺序为中断7>中断3>中断6
PS:在代码执行的过程中,只设置一次中断优先级分组,比如分组2,设置好分组后一般不会再改变,随意改变会导致中断管理混乱。
14.2、NVIC中断优先级设置
(1)中断优先级分组函数
在设置完系统分组后,怎么设置单个中断的抢占优先级和响应优先级?
(2)对单个中断的抢占优先级和响应优先级的设置是通过配置寄存器的方式来实现
中断设置相关寄存器有如下:
(3)相关程序
NVIC的相关函数定义:
//中断优先级的分组函数
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}
//分组的有效性如下
#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 */
观察其有效性,可以发现分组函数将中断分为0~4组,这与之前的表格对应。
同时,之前所说的关于对单个中断抢占优先级和响应优先级设置的寄存器被以结构体的方式定义在内核头文件中:
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;
14.3、NVIC 总结
首先,通过分组函数确定中断的分组,一旦确定分组,就可以知道中断的抢占优先级和响应优先级,接着可以调用NVIC_Init()来设置每一个中断的抢占优先级和响应优先级的位,上述两步结束之后,系统就可以确定每一个中断的执行顺序,或者两个中断间的打断关系。