文章目錄
- 0.中斷關系映射
- 1.使能 IO 口時鐘,初始化 IO 口為輸入
- 2.設置 IO 口模式,觸發條件,開啟 SYSCFG 時鐘,設置 IO 口與中斷線的映射關系。
- 3.配置NVIC優先級管理,并使能中斷
- 4.編寫中斷服務函數。
- 5.編寫中斷處理回調函數 HAL_GPIO_EXTI_Callback
0.中斷關系映射
STM32F103 的中斷控制器支持 19
個外部中斷/事件請求。每個中斷設有狀態位,每個中斷/事件都有獨立的觸發和屏蔽設置。
STM32F103 的 19 個外部中斷為:
EXTI 線 0~15:對應外部 IO 口的輸入中斷。
EXTI 線 16:連接到 PVD 輸出。
EXTI 線 17:連接到 RTC 鬧鐘事件。
EXTI 線 18:連接到 USB 喚醒事件。
EXTI 線 19:連接到以太網喚醒事件。
從上面可以看出,STM32F1 供 IO 口使用的中斷線只有 16 個,但是 STM32F1 的 IO 口卻 遠遠不止 16 個,那么 STM32F1 是怎么把 16 個中斷線和 IO 口一一對應起來的呢?于是 STM32 就這樣設計,GPIO 的管教 GPIOx.0-GPIOx.15(x=A,B,C,D,E,F,G,H,I)分別對應中斷線 0~15。這 樣每個中斷線對應了最多 9 個 IO 口,以線 0 為例:它對應了 GPIOA.0、GPIOB.0、GPIOC.0、 GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0。而中斷線每次只能連接到 1 個 IO 口上,這樣就需要 通過配置來決定對應的中斷線配置到哪個 GPIO 上了。下面我們看看 GPIO 跟中斷線的映射關系圖:
1.使能 IO 口時鐘,初始化 IO 口為輸入
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
2.設置 IO 口模式,觸發條件,開啟 SYSCFG 時鐘,設置 IO 口與中斷線的映射關系。
GPIO_InitTypeDef GPIO_Initure;
GPIO_Initure.Pin=GPIO_PIN_0; //PA0
GPIO_Initure.Mode=GPIO_MODE_IT_RISING; //外部中斷,上升沿觸發
GPIO_Initure.Pull=GPIO_PULLDOWN; //默認下拉
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
當我們調用 HAL_GPIO_Init 設置 IO 的 Mode 值為 GPIO_MODE_IT_RISING(外部中斷上 升 沿 觸 發 ), GPIO_MODE_IT_FALLING ( 外 部 中 斷 下 降 沿 觸 發 ) 或 者 GPIO_MODE_IT_RISING_FALLING(外部中斷雙邊沿觸發)的時候,該函數內部會通過判斷 Mode 的值來開啟 SYSCFG 時鐘,并且設置 IO 口和中斷線的映射關系。
此時如果有新的IO口在同一條中斷線上映射,后面的會覆蓋前面的,比如,此時PA0已經初始化了上升沿觸發的中斷線0,如果再配置PB0,就會清除PA0的中斷配置,改為PB0,
3.配置NVIC優先級管理,并使能中斷
HAL_NVIC_SetPriority(EXTI0_IRQn,2,0); //搶占優先級為 2,子優先級為 0
HAL_NVIC_EnableIRQ(EXTI0_IRQn); //使能中斷線 2
4.編寫中斷服務函數。
我們配置完中斷優先級之后,接著要做的就是編寫中斷服務函數。中斷服務函數的名字是
在 HAL 庫中事先有定義的。這里需要說明一下,STM32F1 的 IO 口外部中斷函數只有 7 個,分
別為:
void EXTI0_IRQHandler();
void EXTI1_IRQHandler();
void EXTI2_IRQHandler();
void EXTI3_IRQHandler();
void EXTI4_IRQHandler();
void EXTI9_5_IRQHandler();
void EXTI15_10_IRQHandler();
中斷線 0-4 每個中斷線對應一個中斷函數,中斷線 5-9 共用中斷函數 EXTI9_5_IRQHandler,中
斷線 10-15 共用中斷函數 EXTI15_10_IRQHandler
5.編寫中斷處理回調函數 HAL_GPIO_EXTI_Callback
我之前使用標準庫開發的時候,對中斷服務函數中直接編寫邏輯,清除中斷標志位,然后寫中斷對應的引腳功能。但是HAL庫對后面所說的“中斷對應引腳功能代碼編寫”又進行了庫函數的封裝,即HAL_GPIO_EXIT_Callback()回調函數。
那么在HAL庫中的中斷服務函數是:
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{ if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u) { __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); HAL_GPIO_EXTI_Callback(GPIO_Pin); }
}
然后我們把中斷功能的編寫寫在Callback回調函數中。
這個中斷標志位是在中斷觸發的時候,硬件中斷控制器就會設置中斷標志位,我們進入中斷服務函數先將中斷標志位清除,表示正在處理這個中斷,防止重復觸發同一個中斷,保證這個中斷每次響應后只處理一次。