STM32的中斷系統
STM32的中斷系統
STM32具有十分強大的中斷系統,將中斷分為了兩個類型:內核異常和外部中斷。並將所有中斷通過一個表編排起來,下面是stm32中斷向量表的部分內容:
上圖-3到6這個區域被標黑了,這個區域就是內核異常。內核異常不能夠被打斷,不能被設置優先級(也就是說優先級是淩駕於外部中斷之上的)。常見的內核異常有以下幾種:復位(reset),不可屏蔽中斷(NMI),硬錯誤(Hardfault),其他的也可以在表上找到。
從第7個開始,後面所有的中斷都是外部中斷。外部中斷是我們必須學習掌握的知識,包含線中斷,定時器中斷,IIC,SPI等所有的外設中斷,可配置優先級。外部中斷的優先級分為兩種:搶占優先級和響應優先級。
什麽是搶占優先級?
搶占優先級比較霸道,一言不和就插隊。搶占優先級高的,能夠打斷優先級低的任務,等優先級較高的任務執行完畢後,再回來繼續執行之前的任務。所以當存在多個搶占優先級不同的任務時,很有可能會產生任務的嵌套。
什麽是響應優先級?
響應優先級則稍微謙遜些,比較有禮貌。響應優先級又被稱為次優先級,若兩個任務的搶占式優先級一樣,那麽響應優先級較高的任務則先執行,且在執行的同時不能被下一個響應優先級更高的任務打斷,所以我說它比較有有禮貌。。
中斷控制器(NVIC)
因為stm32的中斷系統比較復雜,所以在內核中有一個專門管理中斷的控制器:NVIC.
NVIC負責除了SYSTICK之外的所有中斷的控制,十分重要!
在標準庫中,提供了一套通過NVIC來控制中斷的API,我們首先來看NVIC_Init()函數,這套函數首先要定義並填充一個結構體:NVIC_InitTypeDef 該結構體的定義如下:
NVIC_IRQChannel 需要配置的中斷向量
NVIC_IRQChannelCmd 使能或者關閉相應中斷向量的中斷響應
NVIC_IRQChannelPreemptionPriority 配置相應中斷向量的搶占優先級
NVIC_IRQChannelSubPriority 配置相應中斷的響應優先級
結構體的四個成員都比較好理解,這裏就不再累述了。
不過要註意一點的是,NVIC只可以配置16種中斷向量的優先級,其搶占優先級和響應優先級都用一個4位的數字來決定。在庫函數中,將其分為了5中不同的分配方式:
第0組:所有的4位都有來表示響應優先級,能夠配置16種不同的響應優先級。中斷優先級則都相同。
第1組:最高一位用來配置搶占優先級,剩余三位用來表示響應優先級。那麽就有兩種不同的搶占優先級(0和1)和8種不同的響應優先級(0~7)。
第2組:高兩位用來配置搶占優先級,低位用來配置響應優先級。那麽兩種優先級就各有4種。
第3組:高三位用來配置搶占優先級,低位用來配置響應優先級。有8種搶占優先級和2種相應優先級。
第4組:所有位都用來配置搶占優先級,即有16種搶占優先級,沒有響應屬性。
這5種不同的分配方式,根據項目的實際需求來配置。
配置的API如下:
NVIC_PriorityGroupConfig();
其中括號內可以輸入以下一個參數,代表不同的分配方式:
NVIC_PriorityGroup_0
NVIC_PriorityGroup_1
NVIC_PriorityGroup_2
NVIC_PriorityGroup_3
NVIC_PriorityGroup_4
EXTI外部中斷
STM32的所有GPIO都引入到了EXTI外部中斷線上,也就是說,所有的IO口經過配置後都能夠觸發中斷。下圖就是GPIO和EXTI的連接方式:
從上圖我們可以看出,一共有16個中斷線: EXTI0到EXTI15.
每個中斷線都對應了從PAx到PGx一共7個GPIO。也就是說,在同一時刻每個中斷線只能相應一個GPIO端口的中斷,不能夠同時相應所有端口的中斷事件,但是可以分時復用,在程序執行過程中,這個不需要我們太多的去關心。我們關心最多的是中斷觸發的方式:
在EXTI中,有三種觸發中斷的方式:上升沿觸發,下降沿觸發,雙邊沿觸發。根據不同的電路,我們選擇不同的觸發方式,以確保中斷能夠被正常觸發。
實例
為了便於理解,這裏我們將中斷配置代碼貼上來。
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 配置NVIC為優先級組1 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* 配置中斷源:按鍵1 */
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //配置為EXTI0通道
/* 配置搶占優先級 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 配置子優先級 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中斷通道 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); //將上述配置參數傳入中斷初始化函數
}
除了中斷線的配置,我們還要配置對應引腳
void EXTI_Key_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
/*開啟按鍵GPIO口的時鐘*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
/* 配置 NVIC 中斷*/
NVIC_Configuration();
/*--------------------------KEY1配置-----------------------------*/
/* 選擇按鍵用到的GPIO */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
/* 配置為浮空輸入 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);
/* 選擇EXTI的信號源 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
/* EXTI為中斷模式 */
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
/* 上升沿中斷 */
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
/* 使能中斷 */
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
至此,中斷的配置完畢。相信你已經看出來,上述代碼是將PA0配置為上升沿中斷。不過,現在只能夠說該中斷已經配置完畢,但我們還不能使用它。我們還缺少一個中斷的執行函數。
當中斷被觸發後,程序要馬上跳轉到中斷函數去執行中斷操作,這個函數在工程創建時默認時沒有的。需要你自己去添加。而且需要註意的是,中斷函數的名稱必須是由標準庫提供的,否則無法識別。
我們打開startup_stm32f10x_hd.s這個文件,在裏面能找到這麽一段代碼:
; External Interrupts
DCD WWDG_IRQHandler ; Window Watchdog
DCD PVD_IRQHandler ; PVD through EXTI Line detect
DCD TAMPER_IRQHandler ; Tamper
DCD RTC_IRQHandler ; RTC
DCD FLASH_IRQHandler ; Flash
DCD RCC_IRQHandler ; RCC
DCD EXTI0_IRQHandler ; EXTI Line 0
DCD EXTI1_IRQHandler ; EXTI Line 1
DCD EXTI2_IRQHandler ; EXTI Line 2
DCD EXTI3_IRQHandler ; EXTI Line 3
...
...
...
不難看出,EXTI0_IRQHandler 就是中斷線0的中斷函數,所以,我們把這個函數添加到工程中即可。最好添加到stm32f10x_it.c 這個文件中,方便管理。
可以在這個函數中添加你想要的功能,代碼如下:
void EXTI0_IRQHandler(void)
{
//確保是否產生了EXTI Line中斷
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
/******/
//LED閃爍相關代碼
/******/
//清除中斷標誌位
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
至此,整個中斷的流程梳理完畢,如果有什麽紕漏的話,歡迎探討!
STM32的中斷系統