STM32中斷嵌套方法
STM32中斷嵌套方法先說(shuō)明: 所有中斷要放在同一個(gè)組里, 因?yàn)橹挥薪M確定了, 4位描述占先式優(yōu)先級(jí)和副優(yōu)先級(jí)的位數(shù)才可以確定。
NVIC——Nested Vectored Interrupt Controller(嵌套中斷向量控制器)
STM32有43個(gè)channel的settable的中斷源:AIRC(Application Interrupt and Reset Register)寄存器中有用于指定優(yōu)先級(jí)的4bits。這4個(gè)bits用于分配pre-emption優(yōu)先級(jí)和sub優(yōu)先級(jí),在STM32的固件庫(kù)中定義如下:
NVIC_PriorityGroup_0 ((u32)0x700) //0 bits for pre-emption priority 4 bits for subpriority#define
NVIC_PriorityGroup_1 ((u32)0x600) //1 bits for pre-emption priority 3 bits for subpriority#define
NVIC_PriorityGroup_2 ((u32)0x500) //2 bits for pre-emption priority 2 bits for subpriority#define
NVIC_PriorityGroup_3 ((u32)0x400) // 3 bits for pre-emption priority 1 bits for subpriority#define
NVIC_PriorityGroup_4 ((u32)0x300) //4 bits for pre-emption priority 0 bits for subpriority
形象化的理解是:你是上帝,造了43個(gè)人,這么多人要分社會(huì)階級(jí)和社會(huì)階層了;因?yàn)椤半A級(jí)”的詞性比較重;“階層”比較中性,所以pre-emption優(yōu)先級(jí)-》階級(jí);每個(gè)階級(jí)內(nèi)部,有一些階層,sub優(yōu)先級(jí)-》階層;
如果按照NVIC_PriorityGroup_4這么分,就分為了16個(gè)階級(jí)每個(gè)階級(jí)有0個(gè)階層;階級(jí)高的人,可以打斷階級(jí)低的正在做事的人(嵌套),最多可以完成1個(gè)中斷和15級(jí)嵌套。每個(gè)階級(jí)你來(lái)指定這43人中,誰(shuí)進(jìn)入該階級(jí);
一個(gè)人叫EXTI0_IRQChannel,你指定他進(jìn)入“階級(jí)8”,則
NVIC_InitStructure.NVIC_IRQChannel= EXTI0_IRQChannel;NVIC_InitStructure.
NVIC_IRQChannelPreemptionPriority= 8;//指定搶占式優(yōu)先級(jí)別1,可取0-15
在同一階級(jí)內(nèi)部,一個(gè)人在做事的時(shí)候,另外一個(gè)人不能打斷他;(pre-emption優(yōu)先級(jí)別相同的中斷源之間沒(méi)有嵌套關(guān)系)。
還有,如果他們兩個(gè)同時(shí)想做事,因?yàn)闆](méi)有階層,那么就根據(jù)Vector table中的物理排序,讓排名靠前的人去做。
又有1個(gè)人SPI1_IRQChannel,設(shè)定如下
NVIC_InitStructure.NVIC_IRQChannel=SPI1_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0//指定搶占式優(yōu)先級(jí)別1,可取0-15
SPI1_IRQChannel的階級(jí)高,EXTI0_IRQChannel做事的時(shí)候可以打斷(嵌套)。
如果按照NVIC_PriorityGroup_3這么分,就分為了8個(gè)階級(jí)(1個(gè)階級(jí)是1個(gè)preemption優(yōu)先級(jí)),每個(gè)階級(jí)內(nèi)有2個(gè)階層(sub優(yōu)先級(jí));高階級(jí)的人,可以打斷低階級(jí)的正在做事的人(嵌套),最多可以完成1個(gè)中斷和7級(jí)嵌套。每個(gè)階級(jí)(每個(gè)preemption優(yōu)先級(jí)),你來(lái)指定這43人中,誰(shuí)進(jìn)入該階級(jí);
一個(gè)人叫EXTI0_IRQChannel,你指定他進(jìn)入“階級(jí)3”,則:
NVIC_InitStructure.NVIC_IRQChannel= EXTI0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 3; //指定搶占式優(yōu)先級(jí)別1,可取0-7
還需要指定他的階層:
NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0; //指定響應(yīng)優(yōu)先級(jí)別0,可取0-1
另有1個(gè)人叫EXTI9_5_IRQChannel,他的階級(jí)和階層設(shè)定如下
NVIC_InitStructure.NVIC_IRQChannel= EXTI9_5_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 3; //指定搶占式優(yōu)先級(jí)別0,可取0-7
NVIC_InitStructure.NVIC_IRQChannelSubPriority= 1; //指定響應(yīng)優(yōu)先級(jí)別1
那么這兩個(gè)人是同一階級(jí)的兄弟,一個(gè)人在做事的時(shí)候,另外一個(gè)人不能打斷他(preemption優(yōu)先級(jí)別相同的中斷源之間沒(méi)有嵌套關(guān)系)。如果他們兩個(gè)同時(shí)想做事,因?yàn)榍罢叩碾A層高,所以前者優(yōu)先。
還有一個(gè)人叫USART1_IRQChannel,他的階級(jí)和階層設(shè)定如下
NVIC_InitStructure.NVIC_IRQChannel= USART1_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 2; //指定搶占式優(yōu)先級(jí)別0,可取0-7
NVIC_InitStructure.NVIC_IRQChannelSubPriority= 1; //指定響應(yīng)優(yōu)先級(jí)別1
USART1_IRQChannel的優(yōu)先級(jí)最高,當(dāng)前面兩個(gè)人做事的時(shí)候,他都可以打斷(嵌套)。
依次類(lèi)推:如果按照NVIC_PriorityGroup_0這么分,那么沒(méi)有階級(jí),只有16個(gè)階層了。需要給各個(gè)人指定階層編號(hào)。sub優(yōu)先級(jí)的范圍0-15當(dāng)一個(gè)人做事的時(shí)候,另外的人不能打斷他(就沒(méi)有嵌套了);當(dāng)多人同時(shí)想做事的時(shí)候,按照階層編號(hào)的排序,排名靠前的先做事。階層編號(hào)一樣的人同時(shí)想做事,那么按照Vector Table硬件排序,排名靠前的先做。
stm32中斷嵌套實(shí)例
ARM公司的Cortex-m3 內(nèi)核,支持256個(gè)中斷,其中包含16個(gè)內(nèi)核中斷和240個(gè)外部中斷,并且具有256級(jí)的可編程中斷設(shè)置。在ST公司的STM32單片機(jī)中最多有84個(gè)中斷,包括16個(gè)內(nèi)核中斷(這16個(gè)內(nèi)部中斷是任何半導(dǎo)體商也改不了的),和68個(gè)可屏蔽中斷,具有16級(jí)可編程的中斷優(yōu)先級(jí)。但是在STM32F103系列中只有60個(gè)可屏蔽中斷,(107系列有68個(gè))。
針對(duì)這60個(gè)可屏蔽中斷,重點(diǎn)掌握它的一個(gè)中斷優(yōu)先級(jí)寄存器組IPR,全稱(chēng)Interrupt Priority Registers。這個(gè)寄存器組包含15個(gè)32位的寄存器,一個(gè)可屏蔽中斷占用8bit,那么一個(gè)寄存器可以控制4個(gè)可屏蔽中斷,一共15*4=60。然而在這占用的8bit中又只使用了高4bit,這高4bit的分配才是STM32F103系列單片機(jī)中斷嵌套的設(shè)置所在。STM32F103系列的中斷嵌套分為5個(gè)組,分別是0、1、2、3、4 這5個(gè)組,下面是5個(gè)組與中斷嵌套的對(duì)應(yīng)關(guān)系。
對(duì)于搶占優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí),只需記住兩點(diǎn),第一、搶占任何優(yōu)先級(jí)比都比所有響應(yīng)優(yōu)先級(jí)優(yōu)先級(jí)高。只有搶占優(yōu)先級(jí)更高的具有中斷嵌套功能。(即打斷其他正在執(zhí)行的中斷)。第二、數(shù)字越小優(yōu)先級(jí)越高 ,搶占優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí)都一樣時(shí),首先響應(yīng)中斷通道對(duì)應(yīng)中斷向量地址低的那個(gè)中斷。
下面對(duì)0組和1組的情況做一個(gè)分析。
0組對(duì)應(yīng)是0位搶占優(yōu)先級(jí),4位響應(yīng)優(yōu)先級(jí),那么無(wú)搶占優(yōu)先級(jí),響應(yīng)優(yōu)先級(jí)可設(shè)置為0到15級(jí)(2的4次方種)中的任意一種。
1組對(duì)應(yīng)是1位搶占優(yōu)先級(jí),3位響應(yīng)優(yōu)先級(jí),那么搶占優(yōu)先級(jí)只可設(shè)置為0級(jí)或者1級(jí)中的任意一種(2的1次方種),響應(yīng)優(yōu)先級(jí)可設(shè)置為0到7級(jí)(2的3次方種)中的任意一種。
上電復(fù)位時(shí),中斷配置為4組,并且60個(gè)外部中斷都是搶占優(yōu)先級(jí)為0級(jí),無(wú)響應(yīng)優(yōu)先級(jí)。
總結(jié)一下:
1、高優(yōu)先級(jí)的搶占優(yōu)先級(jí)是可以打斷正在進(jìn)行的低搶占優(yōu)先級(jí)中斷的。
2、搶占優(yōu)先級(jí)相同的中斷,高響應(yīng)優(yōu)先級(jí)不可以打斷低響應(yīng)優(yōu)先級(jí)的中斷。
3、搶占優(yōu)先級(jí)相同的中斷,當(dāng)兩個(gè)中斷同時(shí)發(fā)生的情況下,哪個(gè)響應(yīng)優(yōu)先級(jí)高,哪個(gè)先執(zhí)行。
4、如果兩個(gè)中斷的搶占優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí)都是一樣的話,則看哪個(gè)中斷先發(fā)生就先執(zhí)行。
所以可以看出判斷兩個(gè)中斷的優(yōu)先級(jí)時(shí)先看搶占優(yōu)先級(jí)的高低,如果相同再看響應(yīng)優(yōu)先級(jí)的高低。如果全都相同最后看中斷通道向量地址。
一般來(lái)說(shuō)在使用過(guò)程中,一個(gè)系統(tǒng)使用一個(gè)組別就完全可以滿足需要。所以在使用一個(gè)組別后一般不要在系統(tǒng)中再改動(dòng)組別,骨灰級(jí)玩家可以去試試(小心芯片燒了)。
外部中斷:
STM32F103的外部中斷EXTI支持19個(gè)外部中斷/事件請(qǐng)求。每個(gè)中斷/事件都有獨(dú)立的觸發(fā)和屏蔽設(shè)置。
0到15線:對(duì)應(yīng)外部I/O口輸入中斷
線16:接到PVD輸出
線17:接到RCT鬧鐘事件
線18:接到USB喚醒事件
線16到線18我自己都沒(méi)用過(guò),主要對(duì)線0到15的I/O輸入中斷做一個(gè)總結(jié),有個(gè)注意的地方是這0到15線的外部中斷,其中0到4線,這5個(gè)外部中斷都有自己?jiǎn)为?dú)的中斷響應(yīng)函數(shù)。5到9線公用一個(gè)中斷服務(wù)函數(shù),10到15線公用一個(gè)中斷服務(wù)函數(shù)。
外部中斷配置寄存器組EXTICR包含4個(gè)32位的寄存器,分別是EXTICR0、EXTICR1、EXTICR2、EXTICR3、但每一個(gè)寄存器只用了低16位,每4位控制一個(gè)I/O口,一個(gè)寄存器控制4個(gè)I/O口,EXTICR寄存器組控制16個(gè)I/O口,剛好一個(gè)GPIO的I/O口數(shù)。下面以 EXTICR0為例,用一個(gè)表格表示:
比如配置GPIOA.0就是將EXTICR0的低4位配置成0000,若配置GPIOB.1就是配置EXTICR0的4到7位,為0001。
這里有一個(gè)問(wèn)題,如果要配置GPIOA.0和GPIOB.0,會(huì)引起沖突,不知道是不是分時(shí)配置解決的。我用的固體庫(kù)的方式,不需要考慮這些,呵呵。注意使用固件庫(kù)時(shí)中斷復(fù)位函數(shù)是寫(xiě)在stm32f10x_it.c這個(gè)文件里的。
下面結(jié)合外部中斷附上固件庫(kù)版本的程序:
主函數(shù)里:
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitSructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設(shè)置為優(yōu)先級(jí)組2
NVIC_InitSructure.NVIC_IRQChannel = EXTI15_10_IRQn; //定義外部中斷線13中斷通道
NVIC_InitSructure.NVIC_IRQChannelPreemptionPriority = 0; //搶占優(yōu)先級(jí)0
NVIC_InitSructure.NVIC_IRQChannelSubPriority = 0; //響應(yīng)優(yōu)先級(jí)0
NVIC_InitSructure.NVIC_IRQChannelCmd = ENABLE; //使能指定通道
NVIC_Init(&NVIC_InitSructure);
NVIC_InitSructure.NVIC_IRQChannel = EXTI15_10_IRQn; //定義外部中斷線15中斷通道
NVIC_InitSructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitSructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitSructure.NVIC_IRQChannelCmd = ENABLE; //使能指定通道
NVIC_Init(&NVIC_InitSructure);
NVIC_InitSructure.NVIC_IRQChannel = EXTI0_IRQn; //定義外部中斷線0中斷通道
NVIC_InitSructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitSructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitSructure.NVIC_IRQChannelCmd = ENABLE; //使能指定通道
NVIC_Init(&NVIC_InitSructure);
}
void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure; //初始化結(jié)構(gòu)
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource13); //指明當(dāng)前哪個(gè)引腳為外部中斷觸發(fā)引腳
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15);
EXTI_ClearITPendingBit(EXTI_Line13); //清除中斷標(biāo)志位 EXTI_Line13對(duì)應(yīng)相應(yīng)的中斷線13
EXTI_ClearITPendingBit(EXTI_Line15);
EXTI_InitStructure.EXTI_Mode =EXTI_Mode_Interrupt; //選擇中斷模式請(qǐng)求
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿觸發(fā)
EXTI_InitStructure.EXTI_Line = EXTI_Line13|EXTI_Line15; // 選擇待使能的外部中斷線
EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 定義選中線的新?tīng)顟B(tài) 使能
EXTI_Init(&EXTI_InitStructure); //把EXIT_InitStructure中的每一個(gè)參數(shù)按缺省值填入
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); //指明當(dāng)前哪個(gè)引腳為外部中斷觸發(fā)引腳
EXTI_ClearITPendingBit(EXTI_Line0);
EXTI_InitStructure.EXTI_Mode =EXTI_Mode_Interrupt; //選擇中斷模式請(qǐng)求
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿觸發(fā)
EXTI_InitStructure.EXTI_Line = EXTI_Line0; // 選擇待使能的外部中斷線
EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 定義選中線的新?tīng)顟B(tài) 使能
EXTI_Init(&EXTI_InitStructure); //把EXIT_InitStructure中的每一個(gè)參數(shù)按缺省值填入
}
stm32f10x_it.c這個(gè)文件里
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line13)!=RESET)
{ GPIO_WriteBit( GPIOA,GPIO_Pin_8,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_8))); //LED0翻轉(zhuǎn)
EXTI_ClearITPendingBit(EXTI_Line13);
}
if(EXTI_GetITStatus(EXTI_Line15)!=RESET)
{ GPIO_WriteBit( GPIOD,GPIO_Pin_2,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOD,GPIO_Pin_2))); //LED0翻轉(zhuǎn)
EXTI_ClearITPendingBit(EXTI_Line15);
}
}
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0)!=RESET)
{ GPIO_WriteBit( GPIOA,GPIO_Pin_8,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_8))); //LED0翻轉(zhuǎn)
GPIO_WriteBit( GPIOD,GPIO_Pin_2,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOD,GPIO_Pin_2))); //LED0翻轉(zhuǎn)
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
評(píng)論