STM32 外部中斷(EXTI)概述
這篇文章結合示例代碼,系統性地講述 STM32 外部中斷(EXTI)實驗的原理、以及配置流程。目的在于輔助讀者掌握STM32F1 外部中斷機制。
STM32F1xx官方資料:《STM32中文參考手冊V10》-第9章 中斷和事件
STM32的每個IO都可以作為外部中斷輸入。
STM32的中斷控制器支持19個外部中斷/事件請求:
線0~15:對應外部IO口的輸入中斷。
線16:連接到PVD輸出。
線17:連接到RTC鬧鐘事件。
線18:連接到USB喚醒事件。每個外部中斷線可以獨立的配置觸發方式(上升沿,下降沿或者雙邊沿觸發),觸發/屏蔽,專用的狀態位。從上面可以看出,STM32供IO使用的中斷線只有16個,但是STM32F10x系列的IO口多達上百個,STM32F103ZET6(112),
STM32F103RCT6(51),那么中斷線怎么跟io口對應呢?
如圖所示,
GPIOx.0映射到EXTI0
GPIOx.1映射到EXTI1
…
GPIOx.15映射到EXTI15圖20:AFIO_EXTICR 映射機制圖:
每個 EXTI 線可通過 AFIO 寄存器選擇映射到 GPIOA~GPIOG 的某一個引腳。
例如:EXTI3 可以綁定 PE3、PC3、PB3 等,只能綁定一個。
特性 | 說明 |
---|---|
可用中斷線 | EXTI0 ~ EXTI15(共16條 IO 線) + EXTI16(PVD)、EXTI17(RTC)、EXTI18(USB) |
可觸發方式 | 上升沿、下降沿、雙邊沿 |
可配置功能 | 中斷 / 事件 |
IO與EXTI映射 | 通過 AFIO_EXTICR 寄存器設置 |
中斷向量數量 | 僅有 7 個中斷服務函數(EXTI0~4,EXTI9_5,EXTI15_10) |
中斷線與中斷函數映射關系
對于每個中斷線,我們可以設置相應的觸發方式(上升沿觸發,下降沿觸發,邊沿觸發)以及使能。
那么,是不是16個中斷線就可以分配16個中斷服務函數呢?
IO口外部中斷在中斷向量表中只分配了7個中斷向量,也就是只能使用7個中斷服務函數。
從表中可以看出,外部中斷線5~9分配一個中斷向量,共用一個服務函數,
外部中斷線10~15分配一個中斷向量,共用一個中斷服務函數。
中斷線 | 中斷服務函數 | 是否共享中斷 |
---|---|---|
EXTI0 | EXTI0_IRQHandler | 否 |
EXTI1 | EXTI1_IRQHandler | 否 |
EXTI2 | EXTI2_IRQHandler | 否 |
EXTI3 | EXTI3_IRQHandler | 否 |
EXTI4 | EXTI4_IRQHandler | 否 |
EXTI5~9 | EXTI9_5_IRQHandler | 是,需區分 |
EXTI10~15 | EXTI15_10_IRQHandler | 是,需區分 |
另外,補充一個知識點,線16、線17、線18 是 STM32 外部中斷控制器(EXTI)中,與特定內部外設連接的特殊中斷線。 它們不再對應 GPIO 引腳,而是與 STM32 內部某些模塊直接相關。
EXTI 特殊中斷線(EXTI16 ~ EXTI18)
EXTI16 — PVD(電源電壓監測器)
EXTI17 — RTC Alarm(實時時鐘鬧鐘)
EXTI18 — USB Wakeup(USB 喚醒)
中斷線編號 | 來源模塊 | 名稱/用途 | 中斷觸發條件 | 常用用途 |
---|---|---|---|---|
EXTI16 | PVD(電源監測) | 電壓檢測中斷 | 電壓低于/高于設定閾值 | 電源掉電、低電壓預警 |
EXTI17 | RTC(實時時鐘) | RTC鬧鐘中斷 | RTC 到達設定鬧鐘時間 | 定時喚醒、定時事件處理 |
EXTI18 | USB(喚醒模塊) | USB 喚醒中斷 | USB 活動信號喚醒 MCU | USB 喚醒低功耗模式 |
外部中斷庫函數設置
中斷服務函數列表:
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
EXTI9_5_IRQHandler
EXTI15_10_IRQHandler
EXTI_Init函數
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
typedef struct
{uint32_t EXTI_Line; //指定要配置的中斷線 EXTIMode_TypeDef EXTI_Mode; //模式:事件 OR中斷EXTITrigger_TypeDef EXTI_Trigger;//觸發方式:上升沿/下降沿/雙沿觸發FunctionalState EXTI_LineCmd; //使能 OR失能
}EXTI_InitTypeDef;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);
EXTI 外部中斷配置步驟(官方流程)
外部中斷的一般配置步驟:
① 初始化IO口為輸入。
GPIO_Init();
② 開啟IO口復用時鐘。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
③ 設置IO口與中斷線的映射關系。
void GPIO_EXTILineConfig();
④ 初始化線上中斷,設置觸發條件等。
EXTI_Init();
⑤ 配置中斷分組(NVIC),并使能中斷。
NVIC_Init();
⑥ 編寫中斷服務函數。
EXTIx_IRQHandler();
⑦ 清除中斷標志位
EXTI_ClearITPendingBit();
EXTI線通過 AFIO_EXTICR1~4 映射 GPIO 引腳
EXTI0
可映射PA0 ~ PG0
EXTI15
可映射PA15 ~ PG15
中斷向量表圖說明:僅為 EXTI0~4、EXTI9_5、EXTI15_10 提供中斷服務函數。多線共享的服務函數需在函數內判斷是哪條線路觸發。
🌟 配置步驟詳解(以 KEY1 按鍵連接 PE3 → EXTI3 為例):
① 配置 GPIO 為輸入模式
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); // 使能GPIOE時鐘GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // PE3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉輸入
GPIO_Init(GPIOE, &GPIO_InitStructure);
② 使能 AFIO(復用功能模塊)時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
③ 配置 EXTI 線映射(將 PE3 映射到 EXTI3)
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3);
④ 配置 EXTI 中斷線
EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line3; // EXTI3
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_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 搶占優先級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 響應優先級
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能
NVIC_Init(&NVIC_InitStructure);
⑥ 編寫中斷服務函數 EXTI3_IRQHandler
void EXTI3_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line3) != RESET){// 中斷處理邏輯,比如點亮 LEDLED1_TOGGLE(); // 示例函數,用戶自定義EXTI_ClearITPendingBit(EXTI_Line3); // 清除中斷標志位}
}
按鍵的硬件連接
戰艦:
精英:
mini:
原理圖說明(KEY0 ~ KEY2 與 PA0、PE3、PE4)(對照圖解說明)
按鍵名稱 | 接口引腳 | 對應 EXTI 線 | 中斷函數 |
---|---|---|---|
KEY0 | PE4 | EXTI4 | EXTI4_IRQHandler |
KEY1 | PE3 | EXTI3 | EXTI3_IRQHandler |
KEY2 | PE2 | EXTI2 | EXTI2_IRQHandler |
WK_UP | PA0 | EXTI0 | EXTI0_IRQHandler |
多個引腳使用同一個中斷線時的處理(共享中斷)
如圖所示:
EXTI9_5_IRQHandler 處理 EXTI5EXTI9
EXTI15_10_IRQHandler 處理 EXTI10EXTI15
處理多個中斷線:
void EXTI9_5_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line7) != RESET){// 處理 EXTI7 對應按鍵EXTI_ClearITPendingBit(EXTI_Line7);}if (EXTI_GetITStatus(EXTI_Line6) != RESET){// 處理 EXTI6 對應按鍵EXTI_ClearITPendingBit(EXTI_Line6);}
}
完整按鍵中斷實驗總結
📋 總體代碼結構:
void KEY_Interrupt_Init(void)
{// 1. 初始化 GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOE, &GPIO_InitStructure);// 2. 映射 EXTI 線GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3);// 3. 配置 EXTIEXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line3;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);// 4. 配置 NVICNVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}
綜上。
步驟
1?? 配置 GPIO 為輸入模式(上拉/下拉)
2?? 使能 AFIO 時鐘
3?? 使用GPIO_EXTILineConfig()
設置 EXTI 映射
4?? 使用EXTI_Init()
配置中斷線觸發方式
5?? 使用NVIC_Init()
設置中斷優先級與使能
6?? 編寫EXTIx_IRQHandler()
并清除中斷標志位
以上,歡迎有從事同行業的電子信息工程、互聯網通信、嵌入式開發的朋友共同探討與提問,我可以提供實戰演示或模板庫。希望內容能夠對你產生幫助!