关于中断分组和优先级设置所需要的寄存器都是内核知识部分,所以想要了解相关的知识需要查看内核手册。
首先来说说,中断分组、抢占优先级和响应优先级(子优先级)的关系;简单来说就是中断分组的配置决定着抢占优先级与响应优先级的配置,在没有配置中断分组的情况下,就配置抢占优先级和响应优先级是无意义的,其次它们三的优先级关系为:中断分组>抢占优先级>响应优先级;中断有5个分组,分别为:
组0:0位抢占优先级,4位响应优先级
组1:1位抢占优先级,3位响应优先级
组2:2位抢占优先级,2位响应优先级
组3:3位抢占优先级,1位响应优先级
组4:4位抢占优先级,0位响应优先级
而在组之间也存在优先执行规制,即组0>组1>组2>组3>组4>组5,现在结合例子组2来具体说说分组、抢占优先级和响应优先级的关系,当选择组2位中断分组后,有两位的抢占优先级和响应优先级,可以分别选择0级~3级(即00~11),其中数值越小,越优先,注意优先级不能超过设定的组的范围!否则会有意想不到的错误;
配置中断分组的寄存器为:SCB_AIRCR
位【31:16】VECTKEYSTAT[15:0]/ VECTKEY[15:0]注册钥匙 读取为 0xFA05
在写入时,将0x5FA写入VECTKEY,否则写入将被忽略。 位【15】 ENDIANESS数据字节序 读取时为 0 位【14:11】 保留,必须保持清除 位【10:8】PRIGROUP[2:0]:中断优先级分组字段 该字段决定了组优先级与次优先级的分离 位【7:3】保留,必须保持清除 位【2】 SYSRESETREQ 系统重置请求
这是为了强制除调试外的所有主要组件的大型系统重置。 这个位读起来是0。 0:无系统复位请求
1:向外部系统发出复位信号。 位【1】 VECTCLRACTIVE 保留给调试使用。这个位读起来是0。写入寄存器时,必须将0写 入该位,否则行为不可预测。 位【0】 VECTRESET 保留给调试使用。这个位读起来是0。写入寄存器时,必须将0写入 该位,否则行为不可预测。
所以在写该寄存器时,要在VECTKEY(钥匙位)写入0X5FA,在位【2:0】写入0,在PRIGROUP[2:0]位写入中断分组字段,分组字段的数值为下表:
组0~组5分别为011~111,编程时对组值取反便可以得到正确的寄存器输入值(在一些手册解说里,组0对应的PRIGROUP[2:0]为000~011,我也没试过,不知道能不能用)
具体代码如下:
//设置NVIC分组
//NVIC_Group:为NVIC分组的组值 范围:0~4 总共5组
void MY_NVIC_PriorityGroupConfig(uint8_t NVIC_Group)
{
u32 temp,temp1;
temp1=(~NVIC_Group)&0x07; //取后三位
temp1<<=8;
temp=SCB->AIRCR; //读取先前的设置
temp&=0X0000F8FF; //清空先前分组
temp|=0X05FA0000; //写入钥匙
temp|=temp1;
SCB->AIRCR=temp; //设置分组
}
配置完分组后,下一步就是配置优先级
配置优先级寄存器:NVIC_IPRx(写代码是为NVIC_IPx)(其中x的数值为中断号,可在STM32FXXX.h文件中找到)
NVIC_IPRx寄存器为每个中断提供一个4位优先级字段。这些寄存器是字节可访问的。每个寄存器保存四个优先级字段,每个优先级字段都有一个优先级值,0-255。该值越低,相应中断的优先级越大。处理器只实现每个字段的位[7:4],位[3:0]读取为零并忽略写入,其中位[7:4]中分为抢占优先级和响应优先级,抢占优先级在高位,响应优先级在低位,而抢占优先级和响应优先级具体占几位,要看分组情况,例如在组2的情况下,抢占优先级和响应优先级各占2位,其中抢占优先级为[7:6]位,响应优先级为[5:4]位,所以在编程时只需要对对应的位赋值就行。(不摆手册图了,图对于我们编程影响不大)
具体代码如下:
//设置NVIC
//NVIC_PreemptionPriority:抢占优先级
//NVIC_SubPriority :响应优先级
//NVIC_Channel :中断编号
//NVIC_Group :中断分组 0~4
//NVIC_SubPriority和NVIC_PreemptionPriority的原则是,数值越小,越优先
void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)
{
u32 temp;
MY_NVIC_PriorityGroupConfig(NVIC_Group); //设置分组,调用上面写的函数
temp=NVIC_PreemptionPriority<<(4-NVIC_Group);
//将抢占优先级预放入NVIC_IPX[]的[7:4]位中,抢占优先级放前面
temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
//将响应优先级预放入NVIC_IPX[]的[7:4]位中,响应优先级放后面
temp&=0xf; //取低四位
NVIC->ISER[NVIC_Channel/32]|=(1<<NVIC_Channel%32);//使能中断位(要清除的话,相反操作就OK)
NVIC->IP[NVIC_Channel]|=temp<<4; //设置响应优先级和抢断优先级
}