STM32外部中斷的原理與應用分析
1、搶占優先級和響應優先級
在了解中斷之前,先了解一下它們之間的優先級別。STM32的中斷源具有兩種優先級:一種為搶占優先級;另一種為響應優先級(亞優先級),其屬性編號越小,表明它的優先級別越高。搶占是指打斷其他中斷的屬性,即低搶占優先級的中斷A可以被高搶占優先級的中斷B打斷,執行完中斷服務函數B後,再返回繼續執行中斷服務函數A,由此會出現中斷嵌套。響應屬性則應用在搶占屬性相同的情況下,即當兩個中斷源的搶占優先級相同時,分以下幾種情況處理:
(1)如果兩個中斷同時到達,則中斷控制器會先處理響應優先級高的中斷。
(2)當一個中斷到來後,如果正在處理另一個中斷,則這個後到的中斷就要等到前一個中斷處理完之後才能被處理(高響應優先級的中斷不可以打斷低響應優先級的中斷)。
(3)如果它們的搶占式優先級和響應優先級都相等,則根據它們在中斷表中的排位順序決定先處理哪一個。
舉個例子,現在有3個中斷向量,如下圖,若內核正在執行C的中斷服務函數,則它能被搶占優先級更高的中斷A打斷,由於B和C的搶占優先級相同,所以C不能被B打斷。但如果B和C中斷是同時到達的,內核就會首先執行響應優先級別更高的B中斷。如果B和C中有一個先到,不管誰的響應優先級高,都不能打斷,只能等待。
2、NVIC的優先級組
STM32使用了4個中斷優先級的寄存器位,只可以配置16種優先級,即搶占優先級和響應優先級的數量由一個4位的數字來決定,把這個4位數字的位數分配成搶占優先級部分和響應優先級部分。有以下5種分配方式:
第0種:所有4位用於指定響應優先級,即NVIC配置的2的4次方共16種中斷向量都是只有響應屬性,沒有搶占屬性。
第1種:最高1位用來配置搶占優先級,低3位用來配置響應優先級,表示有2種級別的搶占優先級(0級,1級),有2的3次方共8種響應優先級,即在16種中斷向量之中,有8種中斷的搶占優先級都為0級,而它們的響應優先級分別為0~ 7,其余8種中斷的搶占優先級則都為1級,響應優先級別分別為0~7。
第2種:2位用來配置搶占優先級,2位用來配置響應優先,即2的2次方共4種搶占優先級,2的2次方共4種響應優先級。
第3種:高3位用來配置搶占優先級,最低1位用來配置響應優先級,即有8種搶占優先級,2種響應優先級。
第4種:所有4位用來指定搶占優先級,即16種中斷具有不相同的搶占優先級。
可以通過調用STM32固件庫中的函數NVIC_PriorityGroupConfig()選擇使用哪種優先級分組,這個函數有5個參數:
#define NVIC_PriorityGroup_0 ((uint32_t)0x700) //選擇第0種 #define NVIC_PriorityGroup_1 ((uint32_t)0x600) //選擇第1種 #define NVIC_PriorityGroup_2 ((uint32_t)0x500) //選擇第2種#define NVIC_PriorityGroup_3 ((uint32_t)0x400) //選擇第3種 #define NVIC_PriorityGroup_4 ((uint32_t)0x300) //選擇第4種
這裡我說一下為什麼要設置分組和優先級?首先中斷需要有優先級,事件有重要和次要之分,當CPU接到更重要的中斷請求時,應當先去處理重要的事情。設計優先級分組是一個更靈活的選擇,STM32使用了4個中斷優先級的寄存器位,這就意味著可以設置16種優先級,比如說我做的項目會突發很多種情況,這時就可以設置為第3種,有8種搶占(先後)級別,2種響應級別;如果中斷的情況不多,可以設置為第2種,那就會有4種搶占(先後)和4種響應,這樣的設計就可以靈活對付很多複雜的情況。注意:
一般情況下,系統代碼執行過程中,只設置一次中斷優先級分組,比如分組3,設置好分組之後一般不會再改變分組。隨意改變分組會導致中斷管理混亂,程序出現意想不到的執行結果。
3、中斷線的概念
STM32的每個IO都可以作為外部中斷輸入。
STM32的中斷控制器支持19個外部中斷/事件請求:
線0~15:對應外部IO口的輸入中斷。
線16:連接到PVD輸出。
線17:連接到RTC鬧鐘事件。
線18:連接到USB喚醒事件。
每個外部中斷線可以獨立的配置觸發方式(上升沿,下降沿或者雙邊沿觸發),觸發/屏蔽,專用的狀態位。STM32供IO使用的中斷線只有16個,但是STM32F10x系列的IO口多達上百個,那麼中斷線怎麼跟io口對應呢?其實啊,一組IO口對應一根中斷線,每個IO口都可以使用這跟中斷線,但是在同一時刻,只能響應一個埠的事件觸發,不能同時響應所有GPIO埠的事件,也就是分時復用。
4、中斷服務函數
STM32分配了16根中斷線,但是中斷服務函數隻分配了7個,毋庸置疑,肯定有幾個也是要大家共享的了。
·中斷線0 ~ 4各對應一個中斷函數(下圖少了一個外部中斷0)
·中斷線5 ~ 9共用中斷函數EXTI9_5_IRQHandler
·中斷線10 ~ 15共用中斷函數EXTI15_10_IRQHandler
中斷效勞函數列表:
EXTI0_IRQHandler EXTI1_IRQHandlerEXTI2_IRQHandler EXTI3_IRQHandler EXTI4_IRQHandler EXTI9_5_IRQHandler EXTI15_10_IRQHandler
在編寫中斷效勞函數的時候會經常使用到兩個函數實現下面的功能:
(1)判斷某個中斷線上的中斷是否發生(標誌位是否置位),一般使用在中斷效勞函數的開頭,判斷中斷是否發生:
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
(2)革除某個中斷線上的中斷標誌位,這個函數一般應用在中斷效勞函數完畢之前,革除中斷標誌位:
void EXTI_ClearITPendingBit(uint32_t EXTI_Line)
中斷效勞函數的格式能夠說是一個套路的,常用的中斷效勞函數格式為:
void EXTI9_5_IRQHandler(void){
if(EXTI_GetITStatus(EXTI_Line8)!=RESET)//判斷線8上的中斷是否發生
{
?中斷邏輯
EXTI_ClearITPendingBit(EXTI_Line8);//革除LINE上的中斷標誌位
}
}
另外,固件庫還提供了兩個函數用來判斷外部中斷狀態和革除外部狀態標誌位,即EXTI_GetFlagStatus()和EXTI_ClearFlag(),其作用和前面兩個函數的作用類似,只是在EXTI_GetITStatus()中會先判斷這種中斷是否使能,使能了才去判斷中斷標誌位,而EXTI_GetFlagStatus()直接用來判斷狀態標誌位。
5、外部中斷的一般配置步驟:
初始化IO口為輸寫。
GPIO_Init();
開啟IO口復用時鐘。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
【文章福利】:小編整理了一些個人覺得比較好的學習書籍、視頻資料共享在群文件裡面,有需要的可以自行添加哦!~點擊綠色通訊軟體搜索airuimcu加入。
設置IO口與中斷線的映射關係。
void GPIO_EXTILineConfig();例如:GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
初始化線上中斷,設置觸發條件等。
EXTI_Init();例如: EXTI_InitStructure.EXTI_Line=EXTI_Line2;//指定中斷線EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //模式:事件或者中斷EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//觸發方式:下降沿EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能 EXTI_Init(&EXTI_InitStructure);
配置中斷分組(NVIC),並使能中斷。
NVIC_Init();例如: NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中斷NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//搶占優先級為1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//子優先級位2NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能NVIC_Init(&NVIC_InitStructure); //根據上面指定的參數初始化NVIC寄存器
編寫中斷服務函數。
EXTIx_IRQHandler();
清除中斷標誌位
EXTI_ClearITPendingBit();