前言
这一篇博客主要讲解NVCI中断优先级分组,优先级设置。因为还没有我还没学到做中断实验,所以有些地方我自己理解得也不是很透彻,这是看了原子哥的视频用自己的话来梳理一下思路。
基础知识
STM32 有 84 个中断,包括 16 个内核中断和 68 个可屏蔽中断,具有 16 级可编程的中断优先级。
而我们常用的就是这 68 个可屏蔽中断, 但是 STM32 的 68 个可屏蔽中断,在 STM32F103 系列上面,又只有 60 个(在 107 系列才有 68 个)。因为我们开发板选择的芯片是 STM32F103 系列的所以我们就只针对 STM32F103 系列这 60 个可屏蔽中断进行介绍。
具体就是IP[0]-IP[59],每一个中断具体作用可以查看《STM32中文参考手册》9.1.2,下面放一下部分参考手册中的截图。
NVIC中断优先级分组
STM32 将中断分为 5 个组,组 0-4该分组的设置是由 SCB->AIRCR 寄存器的 bit10-8 来定义的。具体的分配关系如表所示。
配置了AIRCR的10-8位之后,就对4-7位进行了一个分组,假设分组为1,则第7位是抢占优先级,6-4位是响应优先级(即1位抢占优先级,3位响应优先级),同理可以看出抢占优先级可以设置位0或1,响应优先级可以设置位0-7(000-111)。
抢占和响应优先级的理解
这里先贴一张原子哥的图。用通俗的话来讲,我们把响应和抢占当作抢答一样,现在有A B C三个人进行抢答。
如果A B C,A的抢占优先级高,那我们就将A设为评委,现在B先抢到了回答,正在进行回答。但是A是评委(高抢占优先级),他可以随时中止B的回答,然后进行自己的回答。
如果A B C,A的抢占优先级高(评委),但B的响应优先级比C高,我们就假设B离控制中心更近,如果B,C同时进行抢答操作的话,B的信号会先达到控制中心,然后就判定B开始回答问题。但是如果C先抢答到,B无法跟A一样可以中断C的回答,因为B并非评委,B,C地位一样。
如果三个人都没有抢占优先级,也没有响应优先级,就跟抢答一样,谁先抢到谁发言。
值得注意的是抢占优先级和响应优先级一样,越低位优先级越高,比如0比1的抢占优先级高,响应优先级同理。
原子哥的这个例子说明性也很强,可以参考一下
NVCI 相关函数
首先是中断优先级分组函数,这个函数的作用是对中断的优先级进行分组,这个函数在系统中只能被调用一次,一旦分组确定就最好不要更改,否则可能会出现意想不到的错误。
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
这个函数的实现方式可以找到,跟上文一样然是配置AIRCR寄存器
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}
函数的入口参数也可以查看
#define IS_NVIC_PRIORITY_GROUP(GROUP)
(((GROUP) == NVIC_PriorityGroup_0) || //分组0
((GROUP) == NVIC_PriorityGroup_1) || \
((GROUP) == NVIC_PriorityGroup_2) || \
((GROUP) == NVIC_PriorityGroup_3) || \ //分组3
((GROUP) == NVIC_PriorityGroup_4))
如果我们要分组位2响应2抢占
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
分组好了之后,要设置单个中断的抢占优先级和响应优先级
在寄存器里面我们要配置IP[0]-IP[59] (60个中断),每个IP寄存器的高四位来设置抢占和响应优先级,低四位没有用到。(根据前面的表格就是4-7位)
这里就要用上NVIC_Init() 函数,用法和GPIO_Init()相同。
先看一下这个函数的结构体成员变量
typedef struct
{
uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled.
This parameter can be a value of @ref IRQn_Type
(For the complete STM32 Devices IRQ Channels list, please
refer to stm32f10x.h file) */
uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel
specified in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref NVIC_Priority_Table */
uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified
in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref NVIC_Priority_Table */
FunctionalState NVIC_IRQChannelCmd; /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
will be enabled or disabled.
This parameter can be set either to ENABLE or DISABLE */
} NVIC_InitTypeDef;
- NVIC_IRQChannel:定义初始化的是哪个中断,这个我们可以在 stm32f10x.h 中找到每个中断对应的名字。例如USART1_IRQn。
- NVIC_IRQChannelPreemptionPriority:定义这个中断的抢占优先级别。
- NVIC_IRQChannelSubPriority:定义这个中断的子优先级别。
- NVIC_IRQChannelCmd:该中断是否使能。
比如我们要使能串口 1 的中断,同时设置抢占优先级为 1,子优先级位 2,初始化的方法是(跟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 寄存器
参考资料
《STM32F1开发指南-库函数版本》 4.5小节
《STM32中文参考手册》第九章