当前位置:文档之家› 中断管理函数

中断管理函数

中断管理函数CM3内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。

但STM32并没有使用CM3内核的全部东西,而是只用了它的一部分。

STM32有76个中断,包括16个内核中断和60个可屏蔽中断,具有16级可编程的中断优先级。

而我们常用的就是这60个可屏蔽中断,所以我们就只针对这60个可屏蔽中断进行介绍。

在MDK内,与NVIC相关的寄存器,MDK为其定义了如下的结构体:typedef struct{vu32 ISER[2];u32 RESERVED0[30];vu32 ICER[2];u32 RSERVED1[30];vu32 ISPR[2];u32 RESERVED2[30];vu32 ICPR[2];u32 RESERVED3[30];vu32 IABR[2];u32 RESERVED4[62];vu32 IPR[15];} NVIC_TypeDef;STM32的中断在这些寄存器的控制下有序的执行的。

了解这些中断寄存器,你才能方便的使用STM32的中断。

下面重点介绍这几个寄存器:ISER[2]:ISER全称是:Interrupt Set-Enable Registers,这是一个中断使能寄存器组。

上面说了STM32的可屏蔽中断只有60个,这里用了2个32位的寄存器,总共可以表示64个中断。

而STM32只用了其中的前60位。

ISER[0]的bit0~bit31分别对应中断0~31。

ISER[1]的bit0~27对应中断32~59;这样总共60个中断就分别对应上了。

你要使能某个中断,必须设置相应的ISER位为1,使该中断被使能(这里仅仅是使能,还要配合中断分组、屏蔽、IO口映射等设置才算是一个完整的中断设置)。

具体每一位对应哪个中断,请参考stm32f10x_nvic..h里面的第36行处。

ICER[2]:全称是:Interrupt Clear-Enable Registers,是一个中断除能寄存器组。

该寄存器组与ISER的作用恰好相反,是用来清除某个中断的使能的。

其对应位的功能,也和ICER一样。

这里要专门设置一个ICER来清除中断位,而不是向ISER写0来清除,是因为NVIC的这些寄存器都是写1有效的,写0是无效的。

具体为什么这么设计,请看《CM3权威指南》第125页,NVIC概览一章。

ISPR[2]:全称是:Interrupt Set-Pending Registers,是一个中断挂起控制寄存器组。

每个位对应的中断和ISER是一样的。

通过置1,可以将正在进行的中断挂起,而执行同级或更高级别的中断。

写0是无效的。

ICPR[2]:全称是:Interrupt Clear-Pending Registers,是一个中断解挂控制寄存器组。

其作用与ISPR相反,对应位也和ISER是一样的。

通过设置1,可以将挂起的中断接挂。

写0无效。

IABR[2]:全称是:Active Bit Registers,是一个中断激活标志位寄存器组。

对应位所代表的中断和ISER一样,如果为1,则表示该位所对应的中断正在被执行。

这是一个只读寄存器,通过它可以知道当前在执行的中断是哪一个。

在中断执行完了由硬件自动清零。

IPR[15]:全称是:Interrupt Priority Registers,是一个中断优先级控制的寄存器组。

这个寄存器组相当重要!STM32的中断分组与这个寄存器组密切相关。

IPR寄存器组由15个32bit的寄存器组成,每个可屏蔽中断占用8bit,这样总共可以表示15*4=60个可屏蔽中断。

刚好和STM32的可屏蔽中断数相等。

IPR[0]的[31~24],[23~16],[15~8],[7~0]分别对应中中断3~0,依次类推,总共对应60个外部中断。

而每个可屏蔽中断占用的8bit并没有全部使用,而是只用了高4位。

这4位,又分为抢占优先级和子优先级。

抢占优先级在前,子优先级在后。

而这两个优先级各占几个位又要根据SCB->AIRCR中中断分组的设置来决定。

这里简单介绍一下STM32的中断分组:STM32将中断分为5个组,组0~4。

该分组的设置是由SCB->AIRCR寄存器的bit10~8来定义的。

具体的分配关系如下表所示:表2.7.2.1 AIRCR中断分组设置表通过这个表,我们就可以清楚的看到组0~4对应的配置关系,例如组设置为3,那么此时所有的60个中断,每个中断的中断优先寄存器的高四位中的最高3位是抢占优先级,低1位是响应优先级。

每个中断,你可以设置抢占优先级为0~7,响应优先级为1或0。

抢占优先级的级别高于响应优先级。

而数值越小所代表的优先级就越高。

结合实例说明一下:假定设置中断优先级组为2,然后设置中断3(RTC中断)的抢占优先级为3,响应优先级为1。

中断6(外部中断0)的抢占优先级为4,响应优先级为0。

中断7(外部中断1)的抢占优先级为3,响应优先级为0。

那么这3个中断的优先级顺序为:中断7>3>中断6。

这里需要注意2点:如果两个中断的响应优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行。

高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。

而抢占优先级相同的中断,上面例子中的中断3和中断7都可以打断中断6的中断。

而中断7和中断3却不可以相互打断!通过以上介绍,我们熟悉了STM32中断设置的大致过程。

接下来我们介绍如何使用函数实现以上中断设置,使得我们以后的中断设置简单化。

第一个介绍的是NVIC的分组函数MY_NVIC_PriorityGroupConfig,该函数的参数NVIC_Group0~4,总共5组。

如果参数非法,将可能导致不可预料的结果。

MY_NVIC_PriorityGroupConfig函数代码如下://设置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; //设置分组}通过前面的介绍,我们知道STM32的5个分组是通过设置SCB->AIRCR的BIT[10:8]来实现的,而通过7.2.3的介绍我们知道SCB->AIRCR的修改需要通过在高16位写入0X05FA这个密钥才能修改的,故在设置AIRCR之前,应该把密钥加入到要写入的内容的高16位,以保证能正常的写入AIRCR。

在修改AIRCR的时候,我们一般采用读->改->写的步骤,来实现不改变AIRCR原来的其他设置。

以上就是MY_NVIC_PriorityGroupConfig函数设置中断优先级分组的思路。

第二个函数是NVIC设置函数MY_NVIC_Init,该函数有4个参数,分别为:NVIC_PreemptionPriority、NVIC_SubPriority、NVIC_Channel、NVIC_Group。

第一个参数NVIC_PreemptionPriority为中断抢占优先级数值,第二个参数NVIC_SubPriority为中断子优先级数值,前两个参数的值必须在规定范围内,否则也可能产生意想不到的错误。

第三个参数NVIC_Channel为中断的编号(范围为0~59),最后一个参数NVIC_Group为中断分组设置(范围为0~4)。

该函数代码如下://设置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;u8 IPRADDR=NVIC_Channel/4; //每组只能存4个,得到组地址u8 IPROFFSET=NVIC_Channel%4;//在组内的偏移IPROFFSET=IPROFFSET*8+4; //得到偏移的确切位置MY_NVIC_PriorityGroupConfig(NVIC_Group);//设置分组temp=NVIC_PreemptionPriority<<(4-NVIC_Group);temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);temp&=0xf;//取低四位if(NVIC_Channel<32)NVIC->ISER[0]|=1<<NVIC_Channel;//使能中断位(要清除的话,相反操作就OK)else NVIC->ISER[1]|=1<<(NVIC_Channel-32);NVIC->IPR[IPRADDR]|=temp<<IPROFFSET;//设置响应优先级和抢断优先级}通过前面的介绍,我们知道每个可屏蔽中断的优先级的设置是在IPR寄存器组里面的,每个中断占8位,但只用了其中的4个位,以上代码就是根据中断分组情况,来设置每个中断对应的高4位的数值的。

当然在该函数里面还引用了MY_NVIC_PriorityGroupConfig这个函数来设置分组。

其实这个分组函数在每个系统里面只要设置一次就够了,设置多次,则是以最后的那一次为准。

但是只要多次设置的组号都是一样,就没事。

否则前面设置的中断会因为后面组的变化优先级会发生改变,这点在使用的时候要特别注意!一个系统代码里面,所有的中断分组都要统一!!,以上代码对要配置的中断号默认是开启中断的。

也就是ISER中的值设置为1了。

通过以上两个函数就实现了对NVIC的管理和配置。

相关主题