一、前言
STM32F103ZET6具备强大的中断控制能力,其嵌套向量中断控制器(NVIC)和处理器核的接口紧密相连,可以实现低延迟的中断处理和高效地处理晚到的中断。NVIC主要具备以下特性:
- 68个可屏蔽中断通道(不包含16个Cortex™-M3的中断线);
- 16个可编程的优先等级(使用了4位中断优先级);
- 低延迟的异常和中断处理;
- 电源管理控制;
- 系统控制寄存器的实现;
二、NVIC相关寄存器介绍
NVIC主要包含以下寄存器组:
寄存器 | 功能 |
---|---|
ISER | 中断使能寄存器组 |
ICER | 中断除能寄存器组 |
ISPR | 中断挂起控制寄存器组 |
ICPR | 中断解挂控制寄存器组 |
IABR | 中断激活标志位寄存器组 |
IPR | 中断优先级控制寄存器组 |
STIR | 软件触发中断寄存器组 |
SCB_AIRCR | 应用中断和复位控制寄存器 |
STM32的NVIC控制器寄存器组看起来比较独特,普通的寄存器可以通过写0和写1实现使能和除能、挂起和解挂,但是NVIC的这些寄存器都是写1有效,写0无效的。因此才会出现“中断使能寄存器”与“中断除能寄存器”、“中断挂起控制寄存器”和“中断解挂控制寄存器”这样的独特寄存器对。 下面将对这些寄存器进行一一解析。
2.1 ISER中断使能寄存器组
《STM32F10xxx Cortex-M3编程手册》对ISER寄存器的描述如下:
Cortex-M3内核支持 256 个中断,这里用 8 个 32 位寄存器(即8个ISER)来控制,每个位控制一个中断。但是STM32 的可屏蔽中断最多只有 68 个(互联型),所以就是三个(ISER[0~2]]),总共可以表示 96 个中断。而 STM32 只用了其中的前 68 位。ISER[0]的 bit0~31 分别对应中断0~31;ISER[1]的 bit0~32 对应中断 32~63;ISER[2]的 bit0~3 对应中断 64~67;这样总共 68 个中断就分别对应上了。 若使能某个中断,必须设置相应的 ISER 位为 1 。具体某一位代表哪个中断,可以参考stm32f10x.h的172-477行。
2.2 ICER中断除能寄存器组
《STM32F10xxx Cortex-M3编程手册》对ICER寄存器的描述如下:
该寄存器组与 ISER 的作用恰好相反,是用来清除某个中断的使能的。若除能某个中断,必须设置相应的ICER位为1。
2.3 ISPR中断挂起控制寄存器组
《STM32F10xxx Cortex-M3编程手册》对ISPR寄存器的描述如下:
通过置 1,可以将正在进行的中断挂起,而执行同级或更高级别的中断。
2.4 ICPR中断解挂控制寄存器组
《STM32F10xxx Cortex-M3编程手册》对ICPR寄存器的描述如下:
通过置 1,可以将挂起的中断解挂。
2.5 IABR中断激活标志位寄存器组
《STM32F10xxx Cortex-M3编程手册》对IABR寄存器的描述如下:
如果为 1,则表示该位所对应的中断正在被执行。这是一个只读寄存器,通过它可以知道当前在执行的中断是哪一个。在中断执行完了由硬件自动清零。
2.6 IPR中断优先级控制寄存器组
《STM32F10xxx Cortex-M3编程手册》对IP寄存器的描述如下:
IPR是控制中断优先级的一个非常重要的寄存器,STM32 的中断分组与这个寄存器组密切相关。IP 寄存器组由 240 个 8bit 的寄存器组成,每个可屏蔽中断占用 8bit,这样总共可以表示 240 个可屏蔽中断。而 STM32 只用到了其中的 68 个。IP[67]~IP[0]分别对应中断 67~0。而每个可屏蔽中断占用的 8bit 并没有全部使用,而是 只用了高 4 位。这 4 位,又分为抢占优先级和子优先级。抢占优先级在前,子优先级在后。而这两个优先级各占几个位又要根据 SCB->AIRCR 中的中断分组设置来决定。
2.7 STIR软件触发中断寄存器组
《STM32F10xxx Cortex-M3编程手册》对STIR寄存器的描述如下:
写入 STIR 以生成软件生成中断 (SGI)。需要写入的值是所需 SGI 的中断 ID,范围为 0-239。例如,值 0b00000011 指定中断 IRQ3。
2.8 SCB_AIRCR应用中断和复位控制寄存器
《STM32F10xxx Cortex-M3编程手册》对SCB_AIRCR寄存器的描述如下:
STM32将中断分为5个组,组0-4,该分组由AIRCR的[10:8]决定,最终影响到IPR的[7:4]位分配情况。如下所示:
组 AIRCR[10:8] IPR[7:4] 分配结果 0 111 0:4 0位抢占优先级,4位响应优先级 1 110 1:3 1位抢占优先级,3位响应优先级 2 101 2:2 2位抢占优先级,2位响应优先级 3 100 3:1 3位抢占优先级,1位响应优先级 4 011 4:0 4位抢占优先级,0位响应优先级 例:组设置为 2,那么此时所有的 68 个中断,每个中断的中断优先寄存器的高四位中的最高 2位是抢占优先级,低 2位是响应优先级。每个中断,你可以设置抢占优先级为 0~3,响应优先级为0-3。抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。
三、中断打断方式
STM32的中断按照如下约定进行相互打断:
- 如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;
- 高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。
四、 程序实现
4.1 NVIC分组函数
NVIC分组函数位于SYSTEM/sys.c/MY_NVIC_PriorityGroupConfig()。值得注意的是,在对SCB_AIRCR寄存器写入之前,需要在高16位灌入密钥0X05FA,在改变其中10:8位时,不能更改其他位的数值。具体程序如下所示:
//设置NVIC分组
//NVIC_Group:NVIC分组 0~4 总共5组
void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)
{ u32 temp,temp1; temp1=(~NVIC_Group)&0x07;//取后三位temp1<<=8;temp=SCB->AIRCR; //读取先前的设置temp&=0X0000F8FF; //清空先前分组temp|=0X05FA0000; //写入钥匙temp|=temp1; SCB->AIRCR=temp; //设置分组
}
4.2 NVIC初始化设置函数
NVIC初始化设置函数位于SYSTEM/sys.c/MY_NVIC_Init()。该函数主要通过ISER寄存器使能相应中断位,通过IPR寄存器设置响应优先级和抢断优先级。具体程序如下所示:
//设置NVIC
//NVIC_PreemptionPriority:抢占优先级
//NVIC_SubPriority :响应优先级
//NVIC_Channel :中断编号
//NVIC_Group :中断分组 0~4
//注意优先级不能超过设定的组的范围!否则会有意想不到的错误
//组划分:
//组0:0位抢占优先级,4位响应优先级
//组1:1位抢占优先级,3位响应优先级
//组2:2位抢占优先级,2位响应优先级
//组3:3位抢占优先级,1位响应优先级
//组4:4位抢占优先级,0位响应优先级
//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); temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);temp&=0xf; //取低四位 NVIC->ISER[NVIC_Channel/32]|=(1<<NVIC_Channel%32);//使能中断位(要清除的话,相反操作就OK) NVIC->IP[NVIC_Channel]|=temp<<4; //设置响应优先级和抢断优先级
}
有以下两点务必注意:
- 注意优先级不能超过设定的组的范围,否则会有意想不到的错误!
- 一个系统代码里面,所有的中断分组都要统一!
五、STM32F103ZET6中断向量表
来源:《STM32中文参考手册_V10》表55