天天看點

STM32_按鍵中斷

***************************************************************************************************************************************

開發闆   :奮鬥STM32

CPU        :STM32F103

開發環境:keil uVsion4

****************************************************************************************************************************************

前言:本文主要是通過按鍵中斷,實作當按下按鍵時,LED燈滅,釋放按鍵時,LED燈亮。(不過我設定LED的起始狀态為亮,也就是上電就點亮了LED燈。)

    我的開發闆按鍵,LED所對應的GPIO管腳原理圖如下:

STM32_按鍵中斷

我寫的按鍵中斷程式實作的功能是:按下按鍵K2,LED3由亮變滅,釋放按鍵LED3又變亮。(按鍵K2對應PC2管腳,LED3對應PD3管腳)。

測試代碼:

#include "misc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_rcc.h"

#define LED_ON 	GPIO_SetBits(GPIOD, GPIO_Pin_3);

//unsigned char flag=0;
//unsigned char num=0;
void LED_Config(void);
void EXTI_PC2_Config(void);
void RCC_Config(void);
//void KEY_Dither(void);
//void delay_nms(u16 time);
int main(void)
{ 
	
//	unsigned char a = 0;
	RCC_Config();
	LED_Config();
	EXTI_PC2_Config();
	LED_ON;
	
	
	while(1)
	{
		//KEY_Dither();
		//if(num==1&&a==0){GPIO_ResetBits(GPIOD,GPIO_Pin_6);a=1;}
		//else if(num==1&&a==1){GPIO_SetBits(GPIOD,GPIO_Pin_6);a=0;}
  }
}
/*void KEY_Dither(void)
{
	num=0;
	if(flag==1)
		{   
			  delay_nms(12000);
		   if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_6)==0)
			 {
				 delay_nms(12000);
			   if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_6)==0)
				 {
					 while(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_6)==0)
						 num=1;
					   goto n_exit;
			   }
		    }
				else ;
           n_exit:;
           flag=0;
			}
}			 


void delay_nms(u16 time)
{    
   u16 i=0;  
   while(time--)
   {
      i=12000;  //自己定義
      while(i--) ;    
   }
}
*/
void RCC_Config(void)  
{    
	   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 
	   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOD,ENABLE); 
     SystemInit();  
	 
}  

void LED_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	/*led config*/	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOD, &GPIO_InitStructure);

}
void EXTI_PC2_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	
  /*config for NVIC*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);	

	NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	/* key for exti */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource2);
	
  /*EXIT line(PC2) mode config */
	
	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);	

}
void EXTI2_IRQHandler(void)  
{  
    if (EXTI_GetITStatus(EXTI_Line2) != RESET)  
    {  
       // flag= 1;//按鍵按下标志 
			    /*LED取反*/
         GPIO_WriteBit(GPIOD, GPIO_Pin_3,  
                (BitAction)((1-GPIO_ReadOutputDataBit(GPIOD, GPIO_Pin_3)))); 			
  
        EXTI_ClearITPendingBit(EXTI_Line2);  
    }  
}  
           

************************************************************************************************************************************

說明:我寫的這個程式隻是實作了按鍵按下燈由亮變滅的簡單功能,但是測試發現,這個按鍵抖動太嚴重,輕輕的觸摸按鍵,燈會閃閃的亮,有時

候碰一下按鍵,還沒有按下按鍵時,LED燈就熄滅了。是以用delay_nms()延時函數進行去抖,代碼中注釋掉的代碼是為了按鍵去抖,不過這個去抖效果不是很好,還是會有抖動現象,但相比之前會好一點!不過官方提供了一個延時函數,可以調用官方寫好的延時函數,一般10ms的時間可以去抖。

************************************************************************************************************************************************

寫這個程式主要是完成相應的配置工作,步驟如下:

(1)初始化系統時鐘和

初始化外部時鐘(時鐘配置)

void RCC_Config(void)  
{    
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);  
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOD,ENABLE); 
      SystemInit(); //系統時鐘初始化 	 
}  
           

*****************************************************************************************************************************************************************************

說明:我們可以不用加SystemInit();不加這個函數也沒影響,因為startup_stm32f10x_hd.s這個檔案已經幫我們做了這些事情。

*****************************************************************************************************************************************************************************

(3)配置LED

void LED_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	/*led config*/	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽輸出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOD, &GPIO_InitStructure);

}
           

(4)配置中斷優先級

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);	

	NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
           

*********************************************************************************************************************************************************************************

說明:這個中斷優先級的設定可以随便設定,原因是我建立的工程中隻用到了按鍵中斷,沒有其他中斷,當然如果有多個中斷,就得按照中斷向量表

以及中斷優先級設定規則來設,具體規則可以參考網上的資料,有很多,可以看看,這裡我就不說明了。這裡我設定的是第一組中斷,搶占優先級是

0,響應優先級也是0。

************************************************************************************************************************************************************************************

(5)配置外部中斷線

/*EXIT line(PC2) mode config */
	
	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);	
           

*************************************************************************************************************************************************************************************

說明:這個中斷模式有兩種,一是Event,二是Interrupt,因為這裡是中斷,是以我們設為

Interrupt

,因為是按鍵Key2,則這裡中斷線為EXTI_Line2,如果按鍵是5-9則這裡就要統一寫成EXTI9_5_IRQn。

**************************************************************************************************************************************************************************************

(6)中斷處理函數

void EXTI2_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line2) != RESET) //判斷按鍵是否按下
	{
		/*LED反轉*/
GPIO_WriteBit(GPIOD, GPIO_Pin_6,  
                (BitAction)((1-GPIO_ReadOutputDataBit(GPIOD, GPIO_Pin_6))));  
		EXTI_ClearITPendingBit(EXTI_Line2); //清除中斷标志位
	}
} 
           

****************************************************************************************************************************************************************************************

說明:這裡的中斷處理函數我們通常最好是放在 stm32f10x_it.c這個檔案,這是官方提供的一個用來放所有外部中斷處理函數的檔案,當主程式在執行程式時,如果發生中斷,cpu會立即跳到這裡來執行中斷處理函數,這裡因為隻有按鍵中斷,還展現不出這樣做的好處,如果是一個大工程,用到多個中斷時,把中斷函數統一放在這個檔案中的話,可以大大優化代碼。

***************************************************************************************************************************************************************************************