STM32之外部中斷 EXTI
STM32中斷控制線支持19個外部中斷/事件請求,每個中斷都有對應狀態位和獨立的觸發與屏蔽設置。STM32F103的19個外部中斷爲:
線0-15:對應GPIO口的輸入中斷。
線16:連接到PVD輸出(掉電檢測,掉電時可立即保存重要數據作用)。
線17:連接RTC鬧鐘事件。 線18:連接到USB喚醒事件
STM32的每個IO口都可以作爲外部中斷源的輸入端,而IO口使用的中斷線只有16根,且引腳GPIOx.0~GPIOx.15(x=A~G)分別對應中斷線0-15.這樣每個中斷線對應了7個IO口。如線0對應引腳GPIOA.0/GPIOB.0/GPIOC.0/GPIOD.0/GPIOE.0/GPIOF.0/GPIOG.0,但是每個中斷線每次只能連接到1個IO口上。即同一時刻EXTIx只能響應一個端口的事件觸發,不能同時響應所有IO端口的事件,但可以分時複用。
*1、GPIO與中斷映射配置通過函數來實現
void GPIO_EXTILineConfig ( uint8_t GPIO_PortSource,uint8_t GPIO_PinSource );
例如
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE , GPIO_PinSource2);
即外部中斷線2就和GPIOE映射起來了,顯然是GPIOE.2連接EXTI2中斷線。
設置中斷觸發方式:
void EXTI_Init( EXTI_InitTypeDef * EXTI_InitStruct )
例如設置中斷線line4的中斷爲下降沿觸發
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line4;//選擇中斷線4,即EXTI4
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中斷模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿觸發
EXTI_InitStructure.EXTI_LineCmd = ENABLE;//中斷使能
EXTI_Init(&EXTI_InitStructure);
//根據EXTI_InitStruct結構體中指定的參數初始化外設 EXTI 寄存器
設置好了中斷線和GPIO的映射關係,然後又設置好了中斷的觸發模式等參數,涉及到中斷,當然不能忘了設置中斷控制體NVIC的中斷優先級。
2、設置NVIC的中斷優先級
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //使能外部中斷通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
//搶佔優先級 2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子優先級 2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中斷通道
NVIC_Init(&NVIC_InitStructure); //中斷優先級分組初始化
3、 配置完中斷優先級後,需要編寫中斷服務程序
stm32f10x_it.c文件是專門用來存放中斷服務函數的。文件中默認只有幾個關於系統異常的中斷服務函數,而且都是空函數,在需要的時候自行編寫。相信部分像我一樣的初學者會有疑問,中斷服務函數的名稱可以自己定義嗎?不行。中斷服務程序的名字必須要與啓動文件startup_stm32f10x_hd.s中的中斷向量表定義的一致。
需要注意的一點,IO口16個外部中斷只有7個函數名:
EXTI0_IRQHandler ;EXTI Line0
EXTI1_IRQHandler ;EXTI Line1
EXTI2_IRQHandler ;EXTI Line2
EXTI3_IRQHandler ;EXTI Line3
EXTI4_IRQHandler ;EXTI Line4
EXTI9_5_IRQHandler ;EXTI Line9..5
EXTI15_10_IRQHandler;EXTI Line15..10
中斷線在5後就不能單獨命名,如果寫成EXTI5_IRQHandler…編譯器是不會報錯的,不過中斷服務程序不能正常工作。
編寫中斷服務函數經常需要使用兩個函數:
ITStatus EXTI_GetITStatus(uint32_t EXTI_line);
//放在中斷服務程序開頭,檢測中斷標誌位
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
//放在函數的結尾
第一個是判斷某個中斷線上的中斷是否發生(即標誌位是否置位)
第二個是清除中斷線上的標誌位(即清除標誌位)
常用的外部中斷服務程序格式
格式一:
void EXTI4_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line4) != RESET)//判斷是否置位
Dosomething();//執行中斷事件
EXTI_ClearITpendingBit(EXTI_Line4);//清除Line4標誌位
}
格式二:
void EXTI_IRQHandler(void)
{
if(EXTI_GetFlagStatus(EXTI_Line4) != RESET)
Dosomething();
EXTI_ClearFlag(EXTI_Line4);
}
EXTI_GetITStatus() 會先判斷中斷該中斷是否使能,使能了的話在判斷該標誌位是否置位;而EXTI_GetFlagStatus()會直接判斷中斷標誌位是否置位(所以顯得馬虎一點)。一般情況下首選EXTI_GetITStatus().
關於外部中斷EXTI大概就這些了,其他的還要靠自己去動手操作才能掌握更多。
-- From #IRONMAN#
-- 4/24/2017