1. 程式人生 > >STM32學習---中斷EXTI(按鍵中斷)

STM32學習---中斷EXTI(按鍵中斷)

//中斷實驗--利用按鍵進行的中斷;
//首先分析STM32的中斷機制:
/*
    因為STM32的中斷如此之多:
    需要一個東西來控制,此時,就運用:NVIC(中斷控制器)來操作,不可遮蔽中斷(NMI)和外部中斷都由它處理。
    但是SYSTICK不是由NVIC來控制的。
*/
/*
庫函式中NVIC 的結構體成員:
NVIC_InitTypeDef型別的結構體。這個結構體有4個成員:
NVIC_IRQChannel ---------- 需要配置的中斷向量
NVIC_IRQChannelCmd ------- 使能或關閉相應中斷向量的中斷響應
NVIC_IRQChannelPreemptionPriority ------- 配置相應中斷向量搶佔優先順序
NVIC_IRQChannelSubPriority -------- 配置相應中斷向量的響應優先順序;

使用:
首先使用NVIC_IRQChannel引數來選擇將要配置的中斷向量,
用NVIC_IRQChannelCmd引數來進行使能(ENABLE)和關閉(DISABLE)該中斷;
NVIC_IRQChannelPreemptionPriority 成員中配置向量的搶佔的優先順序,
在NVIC_IRQChannelSubPriority 需要配置中斷向量的響應優先順序。
而在STM32中,最重要是配置其優先順序。但是這兩種優先順序有什麼區別和聯絡呢?

搶佔優先順序和響應優先順序:
STM32的中斷具有兩個屬性,一個為搶佔屬性,另一個為響應屬性,其屬性的編號越高表明其優先順序越高。

搶佔,是指打斷其他中斷屬性,即因為具有這個屬性會出現巢狀中斷(在執行中斷服務函式A的過程中被中斷B打斷,執行完中斷服務函式B再繼續服務函式B再繼續
執行中斷服務函式A),搶佔屬性由NVIC_IRQChannelPreemptionPriority的引數配置。

而相應屬性則應用在搶佔屬性相同的情況下,當兩個中斷向量的搶佔優先順序相同時,如果兩個中斷同時到達,則先處理響應優先順序高的中斷,
相應屬性由NVIC_IRQCh|annelSubPriority的引數配置。

例如:
中斷向量        搶佔優先順序       響應優先順序
A                  0                 0
B                  1                 0
C                  1                 1
此時,若核心正在執行C的中斷服務函式,則它能被搶佔優先順序更高的中斷A打斷,由於B和C的搶佔優先順序相同,所以C不能被B打斷。
但如果B和C中斷是同時到達的,核心就會首先響應優先順序更高的B中斷。


NVIC的優先順序組:
在配置優先順序的時候,還要注意一個很重要的問題,即中斷種類的數量。NVIC值可以配置16種中斷向量的優先順序,也就是說,搶佔優先順序和響應優先順序的數量
由一個4位的數字來決定,把這個4位數字分配成搶佔優先順序部分和響應優先順序部分。
有5組分配方式:
第0組:所有4位用來配置響應優先順序。即16種中斷向量具有不相同的響應優先順序。
第1組:最高1位用來配置搶佔優先順序,低3位用來配置響應優先順序。表示2(1次)=2中級別的搶佔優先順序(0級,1級),有2(3次)=8種響應優先順序,即在16種
中斷向量之中,有8種中斷,其搶佔優先順序都為0級,而它們的響應優先順序分別為0~7,其餘8種中斷向量的搶佔優先順序則都為1級,響應優先順序分別為0~7.
第2組:2位用來配置搶佔優先順序,2位用來配置響應優先順序。即2(2次)=4種搶佔優先順序,2(2次)=4種響應優先順序。
第3組:高3位用來配置搶佔優先順序,最低1位用來配置響應優先順序。即有8種搶佔優先順序,2種響應優先順序。
第4組:所有4位用來配置搶佔優先順序,即NVIC配置的想2(4次方)=16種中斷向量都是隻有搶佔優先順序沒,有響應屬性。
*/
/*
EXTI外部中斷:
STM32微控制器的所有I/O埠都可以配置為EXTI中斷模式,用來捕捉外部訊號,可以配置為下降沿中斷、上升沿中斷和上升下降沿中斷這三種模式。
STM32的所有GPIO都引入到EXTI外部中斷線上,使得所有的GPIO都能作為外部中斷的輸入源。
觀察參考手冊原理圖可知,PA0~PG0連線到EXTI0,PA1~PG1連線到EXTI1,以此類推,PA15~PG15連線到EXTI15。

注意:PAx~PGx埠的中斷事件都連線到了EXTIx,即同一時刻EXTIx只能響應一個埠的事件觸發,不能夠同一時間響應所有GPIO埠事件,但可以分時複用。
它可以配置為上升沿觸發、下降沿觸發和雙邊沿觸發。
EXTI最普通的應用就是接上一個按鍵,設定為下降沿觸發,用中斷來檢測按鍵。
*/
//根據我自己實驗板的原理圖有下列程式碼:
//我的是PC5連線按鍵,所以選其作為中斷線路:

void EXTI_PC5(void)
{
	GPIO_InitTypeDef GPIO_C;
	EXTI_InitTypeDef EXTI_C;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);    //此句是當GPIO口連線到JTAG上時用。
   //GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);
	
	NVIC_CON();	//配置並初始化中斷控制器
	
	GPIO_C.GPIO_Pin = GPIO_Pin_5;
	GPIO_C.GPIO_Mode= GPIO_Mode_IPU;
	GPIO_Init(GPIOC,&GPIO_C);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);
	
	EXTI_C.EXTI_Line=EXTI_Line5;
	EXTI_C.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_C.EXTI_Trigger=EXTI_Trigger_Falling;
	
	EXTI_C.EXTI_LineCmd=ENABLE;
	EXTI_Init(&EXTI_C);
}
static void 	NVIC_CON(void)
{
	NVIC_InitTypeDef NVIC_X;	//定義一個NVIC型別的結構體變數
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);		//定義一個分組型別
	
	NVIC_X.NVIC_IRQChannel = EXTI9_5_IRQn;				//配置中斷向量;
	NVIC_X.NVIC_IRQChannelPreemptionPriority = 2;		//配置響應優先順序;
	NVIC_X.NVIC_IRQChannelSubPriority = 1;				//配置搶佔優先順序;
	NVIC_X.NVIC_IRQChannelCmd = ENABLE;					//使能配置;
	
	NVIC_Init(&NVIC_X);	//配置完成進行初始化;
}

 GPIO_EXTILineConfig這個函式的意義是:Selects the GPIO pin used as EXTI Line.(選擇一個GPIO口作為中斷線路)

/*關於STM32中斷優先順序分組的科普,初學者常見問題解答(Q&A)
http://www.openedv.com/forum.php?mod=viewthread&tid=275496&fromuid=122111
(出處: OpenEdv-開源電子網)
這裡總結了一些常見問題,非常好。
*/

//最後main
int main(void)
{
	LED_0();
	LED_1();
	EXTI_PC5();
	while(1);
}


void LED_1(void)
{
	GPIO_InitTypeDef GPIO_A;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	GPIO_A.GPIO_Pin=GPIO_Pin_8;
	
	GPIO_A.GPIO_Mode=GPIO_Mode_Out_PP;

	GPIO_A.GPIO_Speed=3;
	
	GPIO_Init(GPIOA,&GPIO_A);
}
void LED_0(void)
{
	GPIO_InitTypeDef GPIO_D;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
	
	GPIO_D.GPIO_Pin=GPIO_Pin_2;
	
	GPIO_D.GPIO_Mode=GPIO_Mode_Out_PP;

	GPIO_D.GPIO_Speed=3;
	
	GPIO_Init(GPIOD,&GPIO_D);
}

最後,在USER資料夾的:stm32f10x_it.c檔案中,還應該加上:

void EXTI9_5_IRQHandler(void)
{int i=1000;
		while(i--);
	//GPIO_SetBits(GPIOA,GPIO_Pin_8);
	if (EXTI_GetITStatus(EXTI_Line5) != RESET) {
		
GPIO_WriteBit(GPIOA, GPIO_Pin_8,  
                (BitAction)((1-GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_8))));  
		EXTI_ClearITPendingBit(EXTI_Line5); 
	}
}

這樣在按鍵是,就能實現LED燈的熄滅和點亮