EXTI原理講解--配置詳解


原文鏈接:https://blog.csdn.net/zxh1592000/article/details/80280715
原文鏈接:https://www.cnblogs.com/firege/p/9287065.html
一、 EXTI 簡介

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

二、 EXTI 功能框圖

EXTI 的功能框圖包含了 EXTI 最核心內容,掌握了功能框圖,對 EXTI 就有一個整體的把握,在編程時思路就非常清晰。EXTI功能框圖見圖。
在圖可以看到很多在信號線上打一個斜杠並標注“20”字樣,這個表示在控制器內部類似的信號線路有 20 個,這與 EXTI 總共有 20 個中斷/事件線是吻合的。所以我們只要明白其中一個的原理,那其他 19 個線路原理也就知道了。

EXTI 可分為兩大部分功能,一個是產生中斷,另一個是產生事件,這兩個功能從硬件上就有所不同。

image
首先我們來看圖中紅色虛線指示的電路流程。它是一個產生中斷的線路,最終信號流入到 NVIC 控制器內。
(1)編號 1 是輸入線,輸入線一般是存在電平變化的信號,EXTI 控制器有 19 個中斷/事件輸入線,這些輸入線可以通過寄存器設置為任意一個 GPIO,也可以是一些外設的事件,這部分內容我們將在后面專門講解。

(2)編號 2 是一個邊沿檢測電路,它會根據"上升沿觸發選擇寄存(EXTI_RTSR)"和"下降沿觸發選擇寄存器(EXTI_FTSR)"對應位的設置來控制信號觸發。邊沿檢測電路以"編號1輸入線"作為信號輸入端,如果檢測到"有邊沿跳變"就輸出有效信號 1 給編號 3 電路,否則輸出無效信號0。而 "上升沿觸發選擇寄存(EXTI_RTSR)"和"下降沿觸發選擇寄存器(EXTI_FTSR)" 兩個寄存器可以控制需要檢測哪些類型的電平跳變過程,可以是只有上升沿觸發、只有下降沿觸發或者上升沿和下降沿都觸發。

(3)編號 3 電路實際就是一個或門電路,它一個輸入來自編號 2 電路,另外一個輸入來自軟件中斷事件寄存器(EXTI_SWIER)。EXTI_SWIER允許我們通過程序控制就可以啟動中斷/事件線,這在某些地方非常有用。我們知道或門的作用就是有 1 就為 1,所以這兩個輸入隨便一個有有效信號 1就可以輸出 1 給編號 4和編號 6電路。

注:軟件中斷事件寄存器(EXTI_SWIER),當該位為’0’時,寫’1’將設置掛起寄存器(EXTI_PR)中相應的掛起位。如果在中斷屏蔽寄存器(EXTI_IMR)和事件屏蔽寄存器(EXTI_EMR)中允許產生該中斷,則此時將產生一個中斷。

(4)編號 4 電路是一個與門電路,它一個輸入是編號 3 電路,另外一個輸入來自中斷屏蔽寄存器(EXTI_IMR)。
與門電路要求輸入都為 1 才輸出 1,導致的結果是如果 EXTI_IMR 設置為 0 時,那不管編號 3 電路的輸出信號是 1 還是 0,最終編號 4 電路輸出的信號都為 0;
如果EXTI_IMR設置為1時,最終編號4電路輸出的信號才由編號3電路的輸出信號決定,這樣我們可以簡單的控制 中斷屏蔽寄存器(EXTI_IMR) 來實現是否產生中斷的目的。編號 4 電路輸出的信號會被保存到掛起寄存器(EXTI_PR)內,如果確定編號 4 電路輸出為 1 就會把 EXTI_PR 對應位置 1。

(5)編號 5 是將 EXTI_PR 寄存器內容輸出到 NVIC 內,從而實現系統中斷事件控制。

暫時那個事件中斷不care了。
其實我覺得這張圖更好
image

三、 中斷/事件線
EXTI有 20個中斷/事件線,每個 GPIO都可以被設置為輸入線,占用 EXTI0至 EXTI15,還有另外七根用於特定的外設事件。
4根特定外設中斷/事件線由外設觸發,具體用法參考《STM32F10X-中文參考手冊》中對外設的具體說明。

image
EXTI0至 EXTI15用於 GPIO,通過編程控制可以實現任意一個 GPIO作為 EXTI的輸入源。
由表可知,EXTI0 可以通過 AFIO 的外部中斷配置寄存器 1(AFIO_EXTICR1)的EXTI0[3:0]位選擇配置為 PA0、PB0、PC0、PD0、PE0、PF0、PG0、PH0 或者 PI0,其他 EXTI線(EXTI中斷/事件線)使用配置都是類似的。

image

四、 EXTI 初始化結構體詳解
標准庫函數對每個外設都建立了一個初始化結構體,比如 EXTI_InitTypeDef,結構體成員用於設置外設工作參數,並由外設初始化配置函數,比如 EXTI_Init()調用,這些設定參數將會設置外設相應的寄存器,達到配置外設工作環境的目的。
初始化結構體和初始化庫函數配合使用是標准庫精髓所在,理解了初始化結構體每個成員意義基本上就可以對該外設運用自如了。初始化結構體定義在 stm32f10x_exti.h 文件中,初始化庫函數定義在 stm32f10x_exti.c 文件中,編程時我們可以結合這兩個文件內注釋使用。

EXTI 初始化結構體
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,可參考表 18-1 選擇。
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)。

五、 外部中斷控制實驗
中斷在嵌入式應用中占有非常重要的地位,幾乎每個控制器都有中斷功能。中斷對保證緊急事件得到第一時間處理是非常重要的。
我們設計使用外接的按鍵來作為觸發源,使得控制器產生中斷,並在中斷服務函數中實現控制 RGB 彩燈的任務。
我們創建了兩個文件:bsp_exti.c 和 bsp_exti.h 文件用來存放 EXTI驅動程序及相關宏定義,中斷服務函數放在 stm32f10x_it.h 文件中。
image
編程要點
初始化用來產生中斷的 GPIO;
初始化 EXTI;
配置 NVIC;
編寫中斷服務函數;
軟件分析
按鍵和 EXTI 宏定義

(1)
/使用宏定義方法指定與硬件電路設計相關配置,這對於程序移植或升級非常有用的。
在上面的宏定義中,我們除了開 GPIO的端口時鍾外,我們還打開了 AFIO 的時鍾,這是因為等下配置 EXTI信號源的時候需要用到 AFIO的外部中斷控制寄存器 AFIO_EXTICRx,具體見《STM32F10X-中文參考手冊》AFIO 寄存器描述。
/

//引腳定義

#define KEY1_INT_GPIO_PORT 				GPIOA
#define KEY1_INT_GPIO_CLK 				(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO)
#define KEY1_INT_GPIO_PIN 				GPIO_Pin_0
#define KEY1_INT_EXTI_PORTSOURCE 		GPIO_PortSourceGPIOA
#define KEY1_INT_EXTI_PINSOURCE 		GPIO_PinSource0
#define KEY1_INT_EXTI_LINE 				EXTI_Line0
#define KEY1_INT_EXTI_IRQ 				EXTI0_IRQn

 #define KEY1_IRQHandler 				EXTI0_IRQHandler


 #define KEY2_INT_GPIO_PORT 			GPIOC
 #define KEY2_INT_GPIO_CLK 				(RCC_APB2Periph_GPIOC\
 |RCC_APB2Periph_AFIO)
 #define KEY2_INT_GPIO_PIN 				GPIO_Pin_13
 #define KEY2_INT_EXTI_PORTSOURCE 		GPIO_PortSourceGPIOC
 #define KEY2_INT_EXTI_PINSOURCE 		GPIO_PinSource13
 #define KEY2_INT_EXTI_LINE 			EXTI_Line13
 #define KEY2_INT_EXTI_IRQ 				EXTI15_10_IRQn

(2)
/這里我們配置兩個的中斷軟件優先級一樣,如果出現了兩個按鍵同時按下的情況,那怎么辦,到底該執行哪一個中斷?當兩個中斷的軟件優先級一樣的時候,中斷來臨時,具體先執行哪個中斷服務函數由硬件的中斷編號決定,編號越小,優先級越高。有關外設的硬件編號可查詢《STM32F10X-中文參考手冊》的中斷和事件章節中的向量表,表中的位置編號即是每個外設的硬件中斷優先級。當然,我們也可以把搶占優先級設置成一樣,子優先級設置成不一樣,這樣就可以區別兩個按鍵同時按下的情況,而不用硬件去對比硬件編號。/

//嵌套向量中斷控制器 NVIC 配置
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;

	/* 配置 NVIC 為優先級組 1 */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

	/* 配置中斷源:按鍵 1 */
	NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;
	/* 配置搶占優先級:1 */
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	/* 配置子優先級:1 */
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	/* 使能中斷通道 */
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	/* 配置中斷源:按鍵 2,其他使用上面相關配置 */
	NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;
	NVIC_Init(&NVIC_InitStructure);
}

(3)

/*首先,使用 GPIO_InitTypeDef和 EXTI_InitTypeDef結構體定義兩個用於 GPIO和 EXTI初始化配置的變量,關於這兩個結構體前面都已經做了詳細的講解。

使用 GPIO之前必須開啟 GPIO端口的時鍾;用到 EXTI必須開啟 AFIO 時鍾。

調用 NVIC_Configuration函數完成對按鍵 1、按鍵 2 優先級配置並使能中斷通道。

作為中斷/事件輸入線時需把 GPIO 配置為輸入模式,具體為浮空輸入,由外部電路完全決定引腳的狀態。

GPIO_EXTILineConfig 函數用來指定中斷/事件線的輸入源,它實際是設定外部中斷配置寄存器的 AFIO_EXTICRx 值,該函數接收兩個參數,第一個參數指定 GPIO 端口源,第二個參數為選擇對應 GPIO 引腳源編號。

我們的目的是產生中斷,執行中斷服務函數,EXTI 選擇中斷模式,按鍵 1 使用上升沿觸發方式,並使能 EXTI線。

按鍵 2 基本上采用與按鍵 1 相關參數配置,只是改為下降沿觸發方式。
兩個按鍵的電路是一樣的,可代碼中我們設置按鍵 1 是上升沿中斷,按鍵 2 是下降沿中斷,有人就會問這是不是設置錯了?實際上可以這么理解,按鍵 1 檢測的是按鍵按下的狀態,按鍵 2檢測的是按鍵彈開的狀態,那這樣就解釋的通了。*/

//EXTI 中斷配置
void EXTI_Key_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;

	/*開啟按鍵 GPIO 口的時鍾*/
	RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK,ENABLE);

	/* 配置 NVIC 中斷*/
	NVIC_Configuration();

	/*--------------------------KEY1 配置---------------------*/
	/* 選擇按鍵用到的 GPIO_init */
	GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;
	/* 配置為浮空輸入 */
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);

	/* 選擇 EXTI 的信號源 */
	GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, KEY1_INT_EXTI_PINSOURCE);
	EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;

	/* EXTI 為中斷模式 */
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	/* 上升沿中斷 */
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
	/* 使能中斷 */
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);

	/*--------------------------KEY2 配置------------------*/
	/* 選擇按鍵用到的 GPIO */
	GPIO_InitStructure.GPIO_Pin = KEY2_INT_GPIO_PIN;
	/* 配置為浮空輸入 */
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);

	/* 選擇 EXTI 的信號源 */
	GPIO_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE, KEY2_INT_EXTI_PINSOURCE);
	EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE;

	/* EXTI 為中斷模式 */
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	/* 下降沿中斷 */
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	/* 使能中斷 */
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
}

(4)
/*當中斷發生時,對應的中斷服務函數就會被執行,我們可以在中斷服務函數實現一些控制。
一般為確保中斷確實發生,我們會在中斷服務函數中調用中斷標志位狀態讀取函數讀取外設中斷標志位並判斷標志位狀態。
EXTI_GetITStatus 函數用來獲取 EXTI 的中斷標志位狀態,如果 EXTI 線有中斷發生函數返回“SET”否則返回“RESET”。

實際上,EXTI_GetITStatus 函數是通過讀取EXTI_PR寄存器值來判斷 EXTI線狀態的。

按鍵 1的中斷服務函數我們讓 LED1翻轉其狀態,按鍵 2的中斷服務函數我們讓 LED2翻轉其狀態。執行任務后需要調用 EXTI_ClearITPendingBit函數清除 EXTI線的中斷標志位。
*/
//EXTI 中斷服務函數
void KEY1_IRQHandler(void)
{
//確保是否產生了 EXTI Line 中斷
if (EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET)
{
// LED1 取反
LED1_TOGGLE;
//清除中斷標志位
EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);
}
}

void KEY2_IRQHandler(void)
{
	//確保是否產生了 EXTI Line 中斷
	if (EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) 
	{
		// LED2 取反
		LED2_TOGGLE;
		//清除中斷標志位
		EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);
	}
}

(5)
/**/
//主函數
int main(void)
{
/* LED 端口初始化 */
LED_GPIO_Config();

	/* 初始化 EXTI 中斷,按下按鍵會觸發中斷,
	* 觸發中斷會進入 stm32f10x_it.c 文件中的函數
	* KEY1_IRQHandler 和 KEY2_IRQHandler,處理中斷,反轉 LED 燈。
	*/
	EXTI_Key_Config();

	/* 等待中斷,由於使用中斷方式,CPU 不用輪詢按鍵 */
	while (1) 
	{
	}
}


static void power_auto_change_init(void)

{
//自動充電檢測引腳初始化_gpio_init
//(0)配置引腳作為中斷輸入線
gpio_init(POWER_AUTO_CHARGE_DET_PORT,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,POWER_AUTO_CHARGE_DET_PIN);

/*(1)用到EXTI必須開啟 AFIO 時鍾 */
rcu_periph_clock_enable(RCU_AF);
/*(2)NVIC配置:中斷通道優先級和中斷通道使能 */
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
nvic_irq_enable(POWER_AUTO_CHARGE_DET_IRQ, 2U, 2U);

/*(3)EXTI配置:指定輸入線連接的EXTI的輸入源*/
gpio_exti_source_select(POWER_AUTO_CHARGE_DET_PORT_SRC, POWER_AUTO_CHARGE_DET_PIN_SRC);

/*(4)EXTI配置:選擇中斷模式(中斷還是事件),中斷觸發方式(上升沿還是下降沿),使能中斷*/
exti_init(POWER_AUTO_CHARGE_DET_LINE, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(POWER_AUTO_CHARGE_DET_LINE);

}


免責聲明!

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



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