stm32中斷嵌套實例
ARM公司的Cortex-m3 內核,支持256個中斷,其中包含16個內核中斷和240個外部中斷,并且具有256級的可編程中斷設置。在ST公司的STM32單片機中最多有84個中斷,包括16個內核中斷(這16個內部中斷是任何半導體商也改不了的),和68個可屏蔽中斷,具有16級可編程的中斷優(yōu)先級。但是在STM32F103系列中只有60個可屏蔽中斷,(107系列有68個)。
針對這60個可屏蔽中斷,重點掌握它的一個中斷優(yōu)先級寄存器組IPR,全稱Interrupt Priority Registers。這個寄存器組包含15個32位的寄存器,一個可屏蔽中斷占用8bit,那么一個寄存器可以控制4個可屏蔽中斷,一共15*4=60。然而在這占用的8bit中又只使用了高4bit,這高4bit的分配才是STM32F103系列單片機中斷嵌套的設置所在。STM32F103系列的中斷嵌套分為5個組,分別是0、1、2、3、4 這5個組,下面是5個組與中斷嵌套的對應關系。
對于搶占優(yōu)先級和響應優(yōu)先級,只需記住兩點,第一、搶占任何優(yōu)先級比都比所有響應優(yōu)先級優(yōu)先級高。只有搶占優(yōu)先級更高的具有中斷嵌套功能。(即打斷其他正在執(zhí)行的中斷)。第二、數字越小優(yōu)先級越高 ,搶占優(yōu)先級和響應優(yōu)先級都一樣時,首先響應中斷通道對應中斷向量地址低的那個中斷。
下面對0組和1組的情況做一個分析。
0組對應是0位搶占優(yōu)先級,4位響應優(yōu)先級,那么無搶占優(yōu)先級,響應優(yōu)先級可設置為0到15級(2的4次方種)中的任意一種。
1組對應是1位搶占優(yōu)先級,3位響應優(yōu)先級,那么搶占優(yōu)先級只可設置為0級或者1級中的任意一種(2的1次方種),響應優(yōu)先級可設置為0到7級(2的3次方種)中的任意一種。
上電復位時,中斷配置為4組,并且60個外部中斷都是搶占優(yōu)先級為0級,無響應優(yōu)先級。
總結一下:
1、高優(yōu)先級的搶占優(yōu)先級是可以打斷正在進行的低搶占優(yōu)先級中斷的。
2、搶占優(yōu)先級相同的中斷,高響應優(yōu)先級不可以打斷低響應優(yōu)先級的中斷。
3、搶占優(yōu)先級相同的中斷,當兩個中斷同時發(fā)生的情況下,哪個響應優(yōu)先級高,哪個先執(zhí)行。
4、如果兩個中斷的搶占優(yōu)先級和響應優(yōu)先級都是一樣的話,則看哪個中斷先發(fā)生就先執(zhí)行。
所以可以看出判斷兩個中斷的優(yōu)先級時先看搶占優(yōu)先級的高低,如果相同再看響應優(yōu)先級的高低。如果全都相同最后看中斷通道向量地址。
一般來說在使用過程中,一個系統(tǒng)使用一個組別就完全可以滿足需要。所以在使用一個組別后一般不要在系統(tǒng)中再改動組別,骨灰級玩家可以去試試(小心芯片燒了)。
外部中斷:
STM32F103的外部中斷EXTI支持19個外部中斷/事件請求。每個中斷/事件都有獨立的觸發(fā)和屏蔽設置。
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); //設置為優(yōu)先級組2
NVIC_InitSructure.NVIC_IRQChannel = EXTI15_10_IRQn; //定義外部中斷線13中斷通道
NVIC_InitSructure.NVIC_IRQChannelPreemptionPriority = 0; //搶占優(yōu)先級0
NVIC_InitSructure.NVIC_IRQChannelSubPriority = 0; //響應優(yōu)先級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); //指明當前哪個引腳為外部中斷觸發(fā)引腳
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; //下降沿觸發(fā)
EXTI_InitStructure.EXTI_Line = EXTI_Line13|EXTI_Line15; // 選擇待使能的外部中斷線
EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 定義選中線的新狀態(tài) 使能
EXTI_Init(&EXTI_InitStructure); //把EXIT_InitStructure中的每一個參數按缺省值填入
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); //指明當前哪個引腳為外部中斷觸發(fā)引腳
EXTI_ClearITPendingBit(EXTI_Line0);
EXTI_InitStructure.EXTI_Mode =EXTI_Mode_Interrupt; //選擇中斷模式請求
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿觸發(fā)
EXTI_InitStructure.EXTI_Line = EXTI_Line0; // 選擇待使能的外部中斷線
EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 定義選中線的新狀態(tài) 使能
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);
}
}
評論
查看更多