1.NVIC初始化流程
<1>配置中断优先级分组
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
<2>建立NVIC初始化结构体
NVIC_InitTypeDef NVIC_InitStructure;
<3>配置NVIC结构体并初始化
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
2.NVIC初始化结构体
typedef struct
{
uint8_t NVIC_IRQChannel; /*指定要启用或禁用的IRQ通道 */
uint8_t NVIC_IRQChannelPreemptionPriority; /*指定IRQ通道的抢占优先级*/
uint8_t NVIC_IRQChannelSubPriority; /*指定IRQ通道的子先级*/
FunctionalState NVIC_IRQChannelCmd; /*指定是否在使能*/
} NVIC_InitTypeDef;
/*优先级组的宏定义*/
#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 */
3.NVIC初始化例程
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
注释
<1> 一般来说,NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)函数只能被调用一次,多次重复调用该函数设置不同的优先级分组的结果是未定义的,谁也不知道会发生什么。
<2> NVIC不会单独使用,总是和中断联系在一起,包括但不限于外部中断,定时器中断,串口通信中断······也就是说使用任何形式的中断都要预先配置好NVIC,确定他的优先级分组,抢占优先级和子优先级,然后使能中断,最后在初始化NVIC。
<3> 当优先级分组和配置的抢占优先级与子优先级不符和时,会发生什么尚不清楚,但是一定要注意这个问题。
4.NVIC常用函数
/*设置优先级分组*/
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
/*初始化NVIC结构体*/
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
/*设置系统进入低功耗的模式*/
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);
/*设置SysTick的时钟源*/
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
5.NVIC优先级的补充说明
NVIC的全称是Nested vectoredinterrupt controller,即嵌套向量中断控制器。
对于M3和M4内核的MCU,每个中断的优先级都是用寄存器中的8位来设置的。8位的话就可以设置2^8 =256级中断,实际中用不了这么多,所以芯片厂商根据自己生产的芯片做出了调整。比如ST的STM32F1xx和F4xx只使用了这个8位中的高四位[7:4],低四位取零,这样2^4=16,只能表示16级中断嵌套。
注:
<1>抢占优先级的级别高于响应优先级,数值越小所代表的优先级越大。
<2>具体优先级的确定和嵌套规则:
- 1 只能高抢先优先级的中断可以打断低抢占优先级的中断服务,构成中断嵌套。
- 2 当2个(N个)相同抢占优先级的中断出现,他们之间不能构成中断嵌套,但STM32首先响应子优先级高的中断。
- 3 当2个(N个)个抢占优先级和子优先级相同的中断出现,STM32首先响应中断同道所对应的中断向量地址低的中断,就是谁先发生谁先被执行。
<3>通俗的来说
具有高抢占式优先级的中断可以在具有低抢占式优先级的中断服务程序执行过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以抢占低抢占式优先级的中断的执行。在抢占式优先级相同的情况下,有几个子优先级不同的中断同时到来,那么高子优先级的中断优先被响应。在抢占式优先级相同的情况下,如果有低子优先级中断正在执行,高子优先级的中断要等待已被响应的低子优先级中断执行结束后才能得到响应,即子优先级不支持中断嵌套。Reset、NMI、HardFault 优先级为负数,高于普通中断优先级,且优先级不可配置。
系统中断(比如:PendSV,SVC,SysTick)不一定比外部中断(比如SPI,USART)要高。