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