STM32 EXTI(外部中斷)


一、EXTI 簡介

EXTI(External interrupt/event controller)—外部中斷/事件控制器,管理了控制器的 20個中斷/事件線。每個中斷/事件線都對應有一個邊沿檢測器,可以實現輸入信號的上升沿檢測和下降沿的檢測。EXTI 可以實現對每個中斷/事件線進行單獨配置,可以單獨配置為中斷或者事件,以及觸發事件的屬性。

二、EXTI框圖


在圖中可以看到很多在信號線上打一個斜杠並標注“20”字樣,這表示在控制器內部的信號線有 20 路,我們只要明白其中一路的原理即可。

  • 輸入線:EXTI 控制器有 20 個中斷/事件輸入線,這些輸入線可以通過寄存器設置為任意一個 GPIO,也可以是一些外設的事件,輸入線一般是存在電平變化的信號。
  • 邊沿檢測電路:它會根據上升沿觸發選擇寄存(EXTI_RTSR)和下降沿觸發選擇寄存器(EXTI_FTSR)對應位的設置來控制信號觸發。邊沿檢測電路以輸入線作為信號輸入端,如果檢測到有邊沿跳變就輸出有效信號 1 ,否則輸出無效信號0。而 EXTI_RTSR 和 EXTI_FTSR 兩個寄存器可以控制器需要檢測哪些類型的電平跳變過程,可以是只有上升沿觸發、只有下降沿觸發或者上升沿和下降沿都觸發。
  • NVIC中斷控制器:NVIC中斷控制器接收到EXTI_PR 寄存器發送的內容,實現中斷的發生。
  • 脈沖發生器:脈沖發生器發送信號后會產生事件線路,脈沖信號可以給其他外設電路使用,比如定時器 TIM、模擬數字轉換器 ADC等等,這樣的脈沖信號一般用來觸發 TIM 或者 ADC開始轉換。

現在可以知道EXTI 可分為兩大部分功能,一個是產生中斷,另一個是產生事件。產生中斷線路目的是把輸入信號輸入到 NVIC,進一步會運行中斷服務函數,實現功能,這樣是軟件級的。而產生事件線路目的就是傳輸一個脈沖信號給其他外設使用,並且是電路級別的信號傳輸,屬於硬件級的。

三、中斷/事件線

EXTI有 20個中斷/事件線,每個 GPIO都可以被設置為輸入線,每個輸入線的來源如圖所示:

從圖中可以看出STM32的外部中斷只有16個,又是怎么使每個GPIO都可以實現中斷了,通過編程控制可以實現任意一個 GPIO作為 EXTI的輸入源。

從上圖可知EXTI0 可以通過 AFIO 的外部中斷配置寄存器 1(AFIO_EXTICR1)的EXTI0[3:0]位選擇配置為 PA0、PB0、PC0、PD0、PE0、PF0、PG0,其他 EXTI線(EXTI中斷/事件線)使用配置都是類似的。

四、EXTI 寄存器

  1. 中斷屏蔽寄存器(EXTI_IMR)

  2. 事件屏蔽寄存器(EXTI_EMR)

  3. 上升沿觸發選擇寄存器(EXTI_RTSR)

    注意: 外部喚醒線是邊沿觸發的,這些線上不能出現毛刺信號。在寫EXTI_RTSR寄存器時,在外部中斷線上的上升沿信號不能被識別,掛起位也不會被置位。在同一中斷線上,可以同時設置上升沿和下降沿觸發。即任一邊沿都可觸發中斷

  4. 下降沿觸發選擇寄存器(EXTI_FTSR)

    注意: 外部喚醒線是邊沿觸發的,這些線上不能出現毛刺信號。在寫EXTI_FTSR寄存器時,在外部中斷線上的下降沿信號不能被識別,掛起位不會被置位。在同一中斷線上,可以同時設置上升沿和下降沿觸發。即任一邊沿都可觸發中斷。

  5. 軟件中斷事件寄存器(EXTI_SWIER)

  6. 掛起寄存器(EXTI_PR)

  7. 外部中斷/事件寄存器映像

五、EXTI 程序分析

  1. EXTI 初始化程序的結構體
typedef struct
{
    uint32_t EXTI_Line;    // 中斷/事件線               
    EXTIMode_TypeDef EXTI_Mode;    // EXTI 模式       
    EXTITrigger_TypeDef EXTI_Trigger;   // 觸發類型
    FunctionalState EXTI_LineCmd;    // EXTI 使能
}EXTI_InitTypeDef;

  1. 初始化GPIO
//將GPIOA_0設置為下拉輸入
void KEY_Init(void) //IO初始化
{ 
    GPIO_InitTypeDef GPIO_InitStructure;
 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);    //使能PORTB,PORTE時鍾
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//使能AFIO復用功能時鍾

    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;    // 0 pin
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;     // 設置成下拉輸入
    GPIO_Init(GPIOA, &GPIO_InitStructure);    // 初始化GPIOA_0

}

  1. 初始化EXTI
    //GPIOA_0 中斷線以及中斷初始化配置   下降沿觸發
void EXTIX_Init(void)
{
    EXTI_InitTypeDef EXTI_InitStructure;
		
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); 	// 選擇GPIOA_0作為中斷EXTI0的線路

    EXTI_InitStructure.EXTI_Line=EXTI_Line0;	//中斷/事件線
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;		// 中斷觸發
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;		// 下降沿觸發
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);	 	//根據EXTI_InitStruct中指定的參數初始化外設EXTI寄存器
}

  1. 配置 GPIO 中斷
    //初始化中斷
void NVICX_Init(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			//使能按鍵WK_UP所在的外部中斷通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//搶占優先級2, 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;			//子優先級2
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//使能外部中斷通道
  	NVIC_Init(&NVIC_InitStructure); 
}

  1. 中斷程序
    這里的功能是當按鍵觸發后切換led的狀態
//外部中斷2服務程序 
void EXTI0_IRQHandler(void)
{
	Delay(100);//消抖
	if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)	 	 //檢測按鍵
	{	
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)==1)    //檢測led燈的狀態,進行切換
		{
			GPIO_ResetBits(GPIOB,GPIO_Pin_12);
		}else{
			GPIO_SetBits(GPIOB,GPIO_Pin_12);
		}
		
	}

	EXTI_ClearITPendingBit(EXTI_Line0);   //清除LINE0上的中斷標志位  
	
}

注意:配置中斷函數時,先確保提供的頭文件中有相應的中斷函數,否則會報錯

六、程序源碼

main.c 文件

#include "stm32f10x.h"
#include "stm32f10x_exti.h"
#include "misc.h"

 /***************  配置LED用到的I/O口 *******************/
void LED_GPIO_Config(void)	
{
  GPIO_InitTypeDef GPIO_InitStructure;
	
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); // 使能PC端口時鍾  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;	//選擇對應的引腳
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;       
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);  //初始化PC端口
  GPIO_SetBits(GPIOB, GPIO_Pin_12 );	 // 關閉LED
}

void Delay(__IO u32 nCount)
{
  for(; nCount != 0; nCount--);
} 

//將GPIOA_0設置為下拉輸入
void KEY_Init(void) //IO初始化
{ 
 	GPIO_InitTypeDef GPIO_InitStructure;
 
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);    //使能PORTB,PORTE時鍾
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//使能AFIO復用功能時鍾

	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;    // 0 pin
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;     // 設置成下拉輸入
 	GPIO_Init(GPIOA, &GPIO_InitStructure);    // 初始化GPIOA_0

}

/* 配置PA0為外部中斷 */
void EXTIX_Init(void)
{
	EXTI_InitTypeDef EXTI_InitStructure;
	
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); 	// 選擇GPIOA_0作為中斷EXTI0的線路

  	EXTI_InitStructure.EXTI_Line=EXTI_Line0;	//中斷/事件線
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;		// 中斷觸發
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;		// 下降沿觸發
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);	 	//根據EXTI_InitStruct中指定的參數初始化外設EXTI寄存器
}

//初始化中斷
void NVICX_Init(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			//使能按鍵WK_UP所在的外部中斷通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//搶占優先級2, 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;			//子優先級2
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//使能外部中斷通道
  	NVIC_Init(&NVIC_InitStructure); 
}

//外部中斷2服務程序 
void EXTI0_IRQHandler(void)
{
	Delay(100);//消抖
	if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)	 	 //WK_UP按鍵
	{	
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)==1)
		{
			GPIO_ResetBits(GPIOB,GPIO_Pin_12);
		}else{
			GPIO_SetBits(GPIOB,GPIO_Pin_12);
		}
		
	}

	EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中斷標志位  
	
}



int main(void)
{
	SystemInit();
	LED_GPIO_Config(); //LED 端口初始化 
	KEY_Init();
	EXTIX_Init();
	NVICX_Init();
	while (1)
	{
		
	}
		
}



七、編譯運行


編譯完成后下載程序並觀察運行現象,當GPIOA_0引腳接地一次,LED燈的狀態便切換一次

參考文獻

STM32系統學習——EXTI(外部中斷):https://blog.csdn.net/zxh1592000/article/details/80280715
STM32之EXTI——外部中斷:https://www.cnblogs.com/alvis-jing/p/3678285.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM