抢占优先级和响应优先级
值越小优先级越高,抢占优先级高就可以的打断抢占优先级低的;但同一个抢占优先级,高响应优先级并不能打断低响应优先级;当然中断同时发生的响应优先级高的先执行。简单理解为:抢占优先级能控制中断的绝对打断,同级抢断优先级没有打断的功能
分组配置是在寄存器SCB->AIRCR中配置:
SCB: System Control Block; AIRCR : Application Interrupt / Reset Control Register
常用寄存器解释
typedef struct
{
__IOM uint32_t ISER[8U];
uint32_t RESERVED0[24U];
__IOM uint32_t ICER[8U];
uint32_t RSERVED1[24U];
__IOM uint32_t ISPR[8U];
uint32_t RESERVED2[24U];
__IOM uint32_t ICPR[8U];
uint32_t RESERVED3[24U];
__IOM uint32_t IABR[8U];
uint32_t RESERVED4[56U];
__IOM uint8_t IP[240U];
uint32_t RESERVED5[644U];
__OM uint32_t STIR;
} NVIC_Type;
ISER[8]
ISER 全称是:Interrupt Set-Enable Registers,这是一个中断使能寄存器组。CM3 内核支持 256 个中断,这里用 8 个 32 位寄存器来控制(328=256),但103系列的芯片只有60个所以只需要两个32位中断(232=64),也就是ISER[0]和ISER[1]
ICER
ICER[8]:全称是:Interrupt Clear-Enable Registers,是一个中断除能寄存器组。该寄存器组与 ISER 的作用恰好相反,是用来清除某个中断的使能的。
ISPR
ISPR[8]:全称是:Interrupt Set-Pending Registers,是一个中断挂起控制寄存器组。每个位对应的中断和 ISER 是一样的。
ICPR
ICPR[8]:全称是:Interrupt Clear-Pending Registers,是一个中断解挂控制寄存器组。其作用与 ISPR 相反,对应位也和 ISER 是一样的。
IABR
全称是:Interrupt Active Bit Registers,是一个中断激活标志位寄存器组。对应位所代表的中断和 ISER 一样,如果为 1,则表示该位所对应的中断正在被执行。这是一个只读寄存器,通过它可以知道当前在执行的中断是哪一个。
IP
IP[240]:全称是:Interrupt Priority Registers,是一个中断优先级控制的寄存器组。这个寄存器组相当重要!STM32 的中断分组与这个寄存器组密切相关。IP 寄存器组由 240 个 8bit 的寄存器组成,每个可屏蔽中断占用 8bit。想要设置某个序号的中断,最终是通过修改IP中某个序号8位的值。例如IP[37]=
程序设置中断过程
typedef struct
{
uint8_t NVIC_IRQChannel; //设置中断通道
uint8_t NVIC_IRQChannelPreemptionPriority;//设置响应优先级
uint8_t NVIC_IRQChannelSubPriority; //设置抢占优先级
FunctionalState NVIC_IRQChannelCmd; //使能/使能
} NVIC_InitTypeDef;
系统运行后先设置中断优先级分组。调用函数:
1.void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
整个系统执行过程中,只设置一次中断分组。
针对每个中断,设置对应的抢占优先级和响应优先级:
2.void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断,这里就是37
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_Init(NVIC_InitTypeDef* NVIC_InitStruct)
{
uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;
/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));
assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));
assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));
if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)
{
/* Compute the Corresponding IRQ Priority --------------------------------*/
tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08; //抢占优先级需要定义的位数
tmppre = (0x4 - tmppriority); //定义响应优先级位数
tmpsub = tmpsub >> tmppriority; //定义的响应优先级位全是1
tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre; //设置的抢占优先级数值左移响应优先级的定义位数
tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub; //只保留响应优先级定义位和抢占优先级位的值,其他位清零
tmppriority = tmppriority << 0x04; //左移四位,因为只是用[7:4]位做为中断抢占和响应优先级的值
NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority; //NVIC的IP对应的值可以根据数据手册查看,也可参考程序库中的名称和对应的地址,例如USART1就是37
/* Enable the Selected IRQ Channels --------------------------------------*///这里才是把设置的值作用到寄存器
NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] = //ISER中每一bit位管理一个中断使能,而每一个ISER是以32位bit为数组中的一个元素,所以中断序号除以32得到该序号对应的ISER的数组序号
(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F); //取得不被32整除的部分做为中断序号在对应ISER组中的bit位的值
}
else
{
/* Disable the Selected IRQ Channels -------------------------------------*/
NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F); //如果设置为DISABLE,那么设置另一个寄存器和上面寄存器的方法一样
}
}