第三章 EXTI介紹及應用
1. EXTI介紹
EXTI(External interrupt/event controller)—外部中斷/事件控制器,管理了控制器的 20 個中斷/事件線。每個中斷/事件線都對應有一個邊沿檢測器,可以實現輸入信號的上升沿檢測和下降沿的檢測。 EXTI 可以實現對每個中斷/事件線進行單獨配置,可以單獨配置為中斷或者事件,以及觸發事件的屬性。
EXTI 有 20 個中斷/事件線,每個 GPIO 都可以被設置為輸入線,占用 EXTI0 至 EXTI15,還有另外七根用于特定的外設事件
EXTI0 至 EXTI15 用于 GPIO,通過編程控制可以實現任意一個 GPIO 作為 EXTI 的輸入源。
2. EXTI初始化結構體介紹
標準庫函數對每個外設都建立了一個初始化結構體,比如 EXTI_InitTypeDef,結構體成員用于設置外設工作參數,并由外設初始化配置函數,比如 EXTI_Init() 調用,這些設定參數將會設置外設相應的寄存器,達到配置外設工作環境的目的。
初始化結構體和初始化庫函數配合使用是標準庫精髓所在,理解了初始化結構體每個成員意義基本上就可以對該外設運用自如了。初始化結構體定義在 stm32f10x_exti.h 文件中,初始化庫函數定義在 stm32f10x_exti.c 文件中,編程時我們可以結合這兩個文件內注釋使用。
typedef struct {uint32_t EXTI_Line; // 中斷/事件線EXTIMode_TypeDef EXTI_Mode; // EXTI 模式EXTITrigger_TypeDef EXTI_Trigger; // 觸發類型FunctionalState EXTI_LineCmd; // EXTI 使能
} EXTI_InitTypeDef;
-
EXTI_Line: EXTI 中斷/事件線選擇,可選 EXTI0 至 EXTI19
-
EXTI_Mode: EXTI 模式選擇,可選為產生中斷 (EXTI_Mode_Interrupt) 或者產生事件(EXTI_Mode_Event)。
-
EXTI_Trigger: EXTI 邊沿觸發事件,可選上升沿觸發 (EXTI_Trigger_Rising)、下降沿觸發 (EXTI_Trigger_Falling) 或者上升沿和下降沿都觸發 ( EXTI_Trigger_Rising_Falling)。
-
EXTI_LineCmd:控制是否使能 EXTI 線,可選使能 EXTI 線 (ENABLE) 或禁用 (DISABLE)。
3. EXTI應用示例
輕觸按鍵在按下時會使得引腳接通,通過電路設計可以使得按下時產生電平變化
3.1 KEY和EXTI相關參數宏定義
#ifndef __KEY_H__
#define __KEY_H__#include "stm32f10x.h"/* KEY GPIO */
#define KEY1_GPIO_CLK RCC_APB2Periph_GPIOA // KEY1 PA0
#define KEY1_GPIO_Port GPIOA
#define KEY1_GPIO_Pin GPIO_Pin_0
#define KEY2_GPIO_CLK RCC_APB2Periph_GPIOC // KEY2 PC13
#define KEY2_GPIO_Port GPIOC
#define KEY2_GPIO_Pin GPIO_Pin_13/* KEY EXTI */
#define KEY1_EXTI_CLK (RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO)
#define KEY1_EXTI_Port GPIO_PortSourceGPIOA // 外部中斷端口
#define KEY1_EXTI_Pin GPIO_PinSource0 // 外部中斷引腳
#define KEY1_EXTI_Line EXTI_Line0 // 外部中斷線
#define KEY1_EXTI_IRQ EXTI0_IRQn // 外部中斷中斷號
#define KEY1_IRQHandler EXTI0_IRQHandler // 外部中斷服務函數#define KEY2_EXTI_CLK (RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO)
#define KEY2_EXTI_Port GPIO_PortSourceGPIOC
#define KEY2_EXTI_Pin GPIO_PinSource13
#define KEY2_EXTI_Line EXTI_Line13
#define KEY2_EXTI_IRQ EXTI15_10_IRQn
#define KEY2_IRQHandler EXTI15_10_IRQHandler#define KEY_OFF 0
#define KEY_ON 1void NVIC_Configuration(void);
void KEY_EXTI_Init(void);#endif /* __KEY_H__ */
3.2 NVIC配置
void NVIC_Configuration(void)
{NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); // 配置中斷優先級組NVIC_InitStructure.NVIC_IRQChannel = KEY1_EXTI_IRQ; // 配置中斷源NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 配置中斷優先級NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 配置中斷子優先級NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中斷NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = KEY2_EXTI_IRQ;NVIC_Init(&NVIC_InitStructure);
}
3.3 KEY GPIO配置及EXTI
void KEY_EXTI_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;EXTI_InitTypeDef EXTI_InitStructure;RCC_APB2PeriphClockCmd(KEY1_EXTI_CLK|KEY2_EXTI_CLK, ENABLE);NVIC_Configuration();/* GPIO 配置 */GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_Pin;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_Pin;GPIO_Init(KEY2_GPIO_Port, &GPIO_InitStructure);/* EXTI 配置 */GPIO_EXTILineConfig(KEY1_EXTI_Port, KEY1_EXTI_Pin); // 配置中斷引腳EXTI_InitStructure.EXTI_Line = KEY1_EXTI_Line; // 配置中斷線EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // 配置中斷模式EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; // 上升沿觸發EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 使能中斷線EXTI_Init(&EXTI_InitStructure);GPIO_EXTILineConfig(KEY2_EXTI_Port, KEY2_EXTI_Pin);EXTI_InitStructure.EXTI_Line = KEY2_EXTI_Line;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿觸發EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);
}
3.4 中斷服務函數
void KEY1_IRQHandler(void)
{if(EXTI_GetITStatus(KEY1_EXTI_Line) != RESET){LED_TOGGLE(RED_LED_Pin);EXTI_ClearITPendingBit(KEY1_EXTI_Line); // 清中斷標志位}
}void KEY2_IRQHandler(void)
{if(EXTI_GetITStatus(KEY2_EXTI_Line) != RESET){LED_TOGGLE(BLUE_LED_Pin);EXTI_ClearITPendingBit(KEY2_EXTI_Line); // 清中斷標志位}
}
3.5 主函數測試
#include "stm32f10x.h"
#include "led.h"
#include "key.h"int main()
{BSP_LED_Init();KEY_EXTI_Init();while(1);
}
4. EXTI常見函數
4.1 基本配置步驟
- 使能時鐘
// 使能AFIO時鐘(EXTI配置需要)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
- 配置GPIO為輸入模式
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; // 以PA0為例
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉輸入模式
GPIO_Init(GPIOA, &GPIO_InitStruct);
- 映射GPIO到EXTI線
// 將PA0映射到EXTI0線
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
- 配置EXTI線
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line = EXTI_Line0; // 選擇EXTI0線
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; // 中斷模式
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; // 上升沿觸發
EXTI_InitStruct.EXTI_LineCmd = ENABLE; // 使能該線
EXTI_Init(&EXTI_InitStruct);
- 配置NVIC(嵌套向量中斷控制器)
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; // EXTI0中斷通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x0F; // 搶占優先級
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x0F; // 子優先級
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 使能通道
NVIC_Init(&NVIC_InitStruct);
4.2 關鍵EXTI操作函數
- 初始化與配置
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
- 參數結構體
typedef struct {uint32_t EXTI_Line; // 選擇EXTI線 (EXTI_Line0~EXTI_Line15)EXTIMode_TypeDef EXTI_Mode; // 模式: EXTI_Mode_Interrupt 或 EXTI_Mode_EventEXTITrigger_TypeDef EXTI_Trigger; // 觸發: EXTI_Trigger_Rising/Falling/BothFunctionalState EXTI_LineCmd; // 使能狀態: ENABLE/DISABLE
} EXTI_InitTypeDef;
- GPIO引腳映射到EXTI線
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
- 中斷狀態管理
// 檢查中斷標志:
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
// 清除中斷掛起位
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
- 軟件觸發中斷
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);
4.3 中斷服務函數
- 單個引腳中斷(EXTI0~EXTI14)
// PA0~PA4等引腳的中斷服務函數
void EXTI0_IRQHandler(void) {if (EXTI_GetITStatus(EXTI_Line0) != RESET) {// 處理中斷EXTI_ClearITPendingBit(EXTI_Line0); // 清除標志位}
}
- 多引腳共用中斷
// EXTI5~9共用中斷服務函數
void EXTI9_5_IRQHandler(void) {if (EXTI_GetITStatus(EXTI_Line5) != RESET) {// 處理EXTI5中斷EXTI_ClearITPendingBit(EXTI_Line5);}if (EXTI_GetITStatus(EXTI_Line6) != RESET) {// 處理EXTI6中斷EXTI_ClearITPendingBit(EXTI_Line6);}// ... 其他線同理
}// EXTI10~15共用中斷服務函數
void EXTI15_10_IRQHandler(void) {// 處理方式同上
}
文中工程下載:https://github.com/hazy1k/STM32F1-Quick-Start-Guide-STD/tree/master/2.code