【STM32】外部中断
00. 目錄
文章目錄
- 00. 目錄
- 01. 外部中斷簡介
- 02. 外部中斷配置
- 03. 外部中斷步驟
- 04. 硬件設計
- 05. 程序示例一
- 06. 程序示例二
- 07. 附錄
- 08. 聲明
01. 外部中斷簡介
外部中斷的代碼主要分布在固件庫的 stm32f4xx_exti.h 和 stm32f4xx_exti.c 文件中。
STM32F4 的每個 IO 都可以作為外部中斷的中斷輸入口,這點也是 STM32F4 的強大之處。STM32F407 的中斷控制器支持 22
個外部中斷/事件請求。每個中斷設有狀態位,每個中斷/事件都有獨立的觸發和屏蔽設置。
STM32F407 的 22 個外部中斷為:
- EXTI 線 0~15:對應外部 IO 口的輸入中斷。
- EXTI 線 16:連接到 PVD 輸出。
- EXTI 線 17:連接到 RTC 鬧鐘事件。
- EXTI 線 18:連接到 USB OTG FS 喚醒事件。
- EXTI 線 19:連接到以太網喚醒事件。
- EXTI 線 20:連接到 USB OTG HS(在 FS 中配置)喚醒事件。
- EXTI 線 21:連接到 RTC 入侵和時間戳事件。
- EXTI 線 22:連接到 RTC 喚醒事件。
從上面可以看出,STM32F4 供 IO 口使用的中斷線只有 16 個,但是 STM32F4 的 IO 口卻遠遠不止 16 個,那么 STM32F4 是怎么把 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,GPIOH.0,GPIOI.0。而中斷線每次只能連接到 1 個 IO口上,這樣就需要通過配置來決定對應的中斷線配置到哪個 GPIO 上了。下面我們看看 GPIO跟中斷線的映射關系圖:
02. 外部中斷配置
2.1 使能 IO口時鐘,初始化 IO
我們要使用 IO 口作為中斷輸入,所以我們要使能相應的 IO 口時鐘,以及初始化相應的 IO 口為輸入模式
2.2 開啟 SYSCFG 時鐘,設置 IO 口與中斷線的映射關系
只要我們使用到外部中斷,就必須打開 SYSCFG 時鐘。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能 SYSCFG 時鐘配置 GPIO 與中斷線的映射關系。在庫函數中,配置 GPIO 與中斷線的映射關系的函數 SYSCFG_EXTILineConfig ()來實現的:
void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex);該函數將 GPIO 端口與中斷線映射起來,程序示例:
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);2.3 初始化線上中斷,設置觸發條件
中斷線上中斷的初始化是通過函數 EXTI_Init()實現的。EXTI_Init()函數的定義是:
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);程序示例
EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line= EXTI_Line4; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); //初始化外設 EXTI 寄存器2.4 配置中斷分組(NVIC ),并使能中斷
我們設置好中斷線和 GPIO 映射關系,然后又設置好了中斷的觸發模式等初始化參數。既然是外部中斷,涉及到中斷我們當然還要設置 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); //中斷優先級分組初始化2.5 編寫中斷服務函數
我們配置完中斷優先級之后,接著要做的就是編寫中斷服務函數。中斷服務函數的名字是在 MDK 中事先有定義的。這里需要說明一下,STM32F4 的 IO 口外部中斷函數只有 7 個,分別為:
DCD EXTI0_IRQHandler ; EXTI Line0 DCD EXTI1_IRQHandler ; EXTI Line1 DCD EXTI2_IRQHandler ; EXTI Line2 DCD EXTI3_IRQHandler ; EXTI Line3 DCD EXTI4_IRQHandler ; EXTI Line4 DCD EXTI9_5_IRQHandler ; External Line[9:5]s DCD EXTI15_10_IRQHandler ; External Line[15:10]s中斷線 0-4 每個中斷線對應一個中斷函數,中斷線 5-9 共用中斷函數 EXTI9_5_IRQHandler,中斷線 10-15 共用中斷函數EXTI15_10_IRQHandler。在編寫中斷服務函數的時候會經常使用到兩個函數,第一個函數是判斷某個中斷線上的中斷是否發生(標志位是否置位)
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);這個函數一般使用在中斷服務函數的開頭判斷中斷是否發生。另一個函數是清除某個中斷線上的中斷標志位:
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);這個函數一般應用在中斷服務函數結束之前,清除中斷標志位。
03. 外部中斷步驟
使用 IO 口外部中斷的一般步驟:
1)使能 IO 口時鐘,初始化 IO 口為輸入。
2)使能 SYSCFG 時鐘,設置 IO 口與中斷線的映射關系。
3)初始化線上中斷,設置觸發條件等。
4)配置中斷分組(NVIC),并使能中斷。
5)編寫中斷服務函數。
04. 硬件設計
探索者 STM32F4 開發板上載有的 4 個按鈕(KEY_UP、KEY0、KEY1 和 KEY2),來控制板上的 2 個 LED(DS0 和 DS1)和蜂鳴器,其中 KEY_UP 控制蜂鳴器,按一次叫,再按一次停;KEY0 控制 DS0,按一次亮,再按一次滅;KEY1 控制 DS1,
效果同 KEY2;KEY2 則同時控制 DS0 和 DS1,按一次,它們的狀態就翻轉一次。
05. 程序示例一
KEY0控制LED1的翻轉
exti.h文件
#ifndef __EXTI_H__ #define __EXTI_H__#include "sys.h"//中斷初始化函數void EXTIX_Init(void);#endif /*__EXTI_H__*/exti.c文件
#include "exti.h" #include "key.h" #include "led.h" #include "delay.h" #include "usart.h"//中斷初始化函數void EXTIX_Init(void){EXTI_InitTypeDef EXTI_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;//按鍵初始化KEY_Init();//初始化SYSCFG時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//KEY0 --> PE4SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4);//配置中斷EXTI_InitStruct.EXTI_Line = EXTI_Line4;EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_InitStruct.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStruct);//配置中斷分組NVIC_InitStruct.NVIC_IRQChannel = EXTI4_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);}//中斷線4處理函數 void EXTI4_IRQHandler(void) {printf("KEY0按下啦....\r\n");//消抖delay_ms(10);if (0 == KEY0){LED1 = !LED1;}//清中斷EXTI_ClearITPendingBit(EXTI_Line4); }main.c文件
#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "beep.h" #include "key.h" #include "exti.h"int main(void) { BEEP = 0;LED1 = 0;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);BEEP_Init();LED_Init();delay_init(168);uart_init(115200);//外部中斷初始化EXTIX_Init();while(1){printf("程序正在運行.....\r\n");delay_ms(1000);} }06. 程序示例二
exti.h文件
#ifndef __EXTI_H__ #define __EXTI_H__#include "sys.h"//中斷初始化函數void EXTIX_Init(void);#endif /*__EXTI_H__*/exti.c文件
#include "exti.h" #include "key.h" #include "led.h" #include "beep.h" #include "delay.h" #include "usart.h"//中斷初始化函數void EXTIX_Init(void){EXTI_InitTypeDef EXTI_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;//按鍵初始化KEY_Init();//初始化SYSCFG時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//KEY0 --> PE4SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4);//KEY1 --> PE3SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3);//KEY1 --> PE2SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2);//KEY_UP --> PA0SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);//配置中斷 KEY0 KEY1 KEY2EXTI_InitStruct.EXTI_Line = EXTI_Line4 | EXTI_Line3 | EXTI_Line2;EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_InitStruct.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStruct);//配置中斷 KEY_UPEXTI_InitStruct.EXTI_Line = EXTI_Line0;EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_InitStruct.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStruct);//配置中斷分組 KEY0NVIC_InitStruct.NVIC_IRQChannel = EXTI4_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);//配置中斷分組 KEY1NVIC_InitStruct.NVIC_IRQChannel = EXTI3_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);//配置中斷分組 KEY2NVIC_InitStruct.NVIC_IRQChannel = EXTI2_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);//配置中斷分組 WK_UPNVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);}//中斷線4處理函數 void EXTI4_IRQHandler(void) {printf("KEY0按下啦....\r\n");//消抖delay_ms(10);if (0 == KEY0){LED1 = !LED1;}//清中斷EXTI_ClearITPendingBit(EXTI_Line4); }//中斷線3處理函數 void EXTI3_IRQHandler(void) {printf("KEY1按下啦....\r\n");//消抖delay_ms(10);if (0 == KEY1){LED2 = !LED2;}//清中斷EXTI_ClearITPendingBit(EXTI_Line3); }//中斷線2處理函數 void EXTI2_IRQHandler(void) {printf("KEY2按下啦....\r\n");//消抖delay_ms(10);if (0 == KEY2){LED1 = !LED1;LED2 = !LED2;}//清中斷EXTI_ClearITPendingBit(EXTI_Line2); }//中斷線0處理函數 void EXTI0_IRQHandler(void) {printf("KEY_UP按下啦....\r\n");//消抖delay_ms(10);if (1 == WK_UP){BEEP = !BEEP;}//清中斷EXTI_ClearITPendingBit(EXTI_Line0); }main.c文件
#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "beep.h" #include "key.h" #include "exti.h"int main(void) { BEEP = 0;LED1 = 0;LED2 = 0;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);BEEP_Init();LED_Init();delay_init(168);uart_init(115200);//外部中斷初始化EXTIX_Init();while(1){printf("程序正在運行.....\r\n");delay_ms(1000);} }07. 附錄
7.1 【STM32】STM32系列教程匯總
網址:【STM32】STM32系列教程匯總
08. 聲明
該教程參考了正點原子的《STM32 F4 開發指南》
總結
以上是生活随笔為你收集整理的【STM32】外部中断的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【STM32】中断优先级管理
- 下一篇: 【STM32】独立看门狗相关函数和类型