單片機學習筆記————51單片機實現獨立按鍵的雙擊按鍵觸發

一、使用proteus繪製簡單的電路圖,用於後續仿真

二、編寫程序

/********************************************************************************************************************
----	@Project:	Independent-KEY
----	@File:	main.c
----	@Edit:	ZHQ
----	@Version:	V1.0
----	@CreationTime:	20200506
----	@ModifiedTime:	20200506
----	@Description:	有兩個獨立按鍵,每雙擊一個獨立按鍵,蜂鳴器發出“滴”的一聲後就停。
----	單片機:AT89C52
********************************************************************************************************************/
#include "reg52.h"
/*——————宏定義——————*/
#define FOSC 11059200L
#define T1MS (65536-FOSC/12/1000)   /*1ms timer calculation method in 12Tmode*/

#define const_voice_short  80   /*蜂鳴器短叫的持續時間*/

#define const_key_time1   60  /*按鍵去抖動延時的時間*/
#define const_key_time2   60  /*按鍵去抖動延時的時間*/

#define const_interval_time1   600  /*連續兩次按鍵之間的有效時間差*/
#define const_interval_time2   600  /*連續兩次按鍵之間的有效時間差*/

/*——————變量函數定義及聲明——————*/
/*定義按鍵S1*/
sbit Key_S1 = P0^0;
/*定義按鍵S2*/
sbit Key_S2 = P0^1;
/*定義蜂鳴器*/
sbit BUZZER = P2^7;

unsigned char ucKeySec = 0;   /*被觸發的按鍵編號*/

unsigned int  uiKeyTimeCnt1 = 0; /*按鍵去抖動延時計數器*/
unsigned char ucKeyLock1 = 0; /*按鍵觸發後自鎖的變量標誌*/
unsigned char ucKeyTouchCnt1 = 0; /*按鍵按下的次數記錄*/
unsigned int  uiKeyIntervalCnt1 = 0; /*按鍵間隔的時間計數器*/

unsigned int  uiKeyTimeCnt2 = 0; /*按鍵去抖動延時計數器*/
unsigned char ucKeyLock2 = 0; /*按鍵觸發後自鎖的變量標誌*/
unsigned char ucKeyTouchCnt2 = 0; /*按鍵按下的次數記錄*/
unsigned int  uiKeyIntervalCnt2 = 0; /*按鍵間隔的時間計數器*/

unsigned int  uiVoiceCnt = 0;  /*蜂鳴器鳴叫的持續時間計數器*/


/**
* @brief  定時器0初始化函數
* @param  無
* @retval 初始化T0
**/
void Init_T0(void)
{
	TMOD = 0x01;                    /*set timer0 as mode1 (16-bit)*/
	TL0 = T1MS;                     /*initial timer0 low byte*/
	TH0 = T1MS >> 8;                /*initial timer0 high byte*/
}
/**
* @brief  外圍初始化函數
* @param  無
* @retval 初始化外圍
**/
void Init_Peripheral(void)
{
	ET0 = 1;/*允許定時中斷*/
	TR0 = 1;/*啓動定時中斷*/
	EA = 1;/*開總中斷*/

}

/**
* @brief  初始化函數
* @param  無
* @retval 初始化單片機
**/
void	Init(void)
{
	Init_T0();
	BUZZER = 1;
}
/**
* @brief  掃描按鍵函數
* @param  無
* @retval 獨立雙擊按鍵掃描的詳細過程:
* 第一步:平時沒有按鍵被觸發時,按鍵的自鎖標誌,去抖動延時計數器一直被清零。
*         如果之前已經有按鍵觸發過一次,那麼啓動時間間隔計數器uiKeyIntervalCnt1,
*         在這個允許的時間差範圍內,如果一直沒有第二次按鍵觸發,則把累加按鍵觸發的
*         次數ucKeyTouchCnt1也清零。
* 第二步:一旦有按鍵被按下,去抖動延時計數器開始在定時中斷函數裏累加,在還沒累加到
*         閥值const_key_time1時,如果在這期間由於受外界干擾或者按鍵抖動,而使
*         IO口突然瞬間觸發成高電平,這個時候馬上把延時計數器uiKeyTimeCnt1
*         清零了,這個過程非常巧妙,非常有效地去除瞬間的雜波干擾。
*         以後凡是用到開關感應器的時候,都可以用類似這樣的方法去幹擾。
* 第三步:如果按鍵按下的時間超過了閥值const_key_time1,馬上把自鎖標誌ucKeyLock1置位,
*         防止按住按鍵不鬆手後一直觸發。與此同時,累加一次按鍵次數,如果按鍵次數累加有兩次以上,
*         則認爲觸發雙擊按鍵,並把編號ucKeySec賦值。 
* 第四步:等按鍵鬆開後,自鎖標誌ucKeyLock1及時清零,爲下一次自鎖做準備。並且累加間隔時間,
*         防止兩次按鍵的間隔時間太長。
* 第五步:以上整個過程,就是識別按鍵IO口下降沿觸發的過程。
**/
void Key_Scan(void)
{
	/*掃描S1*/
	if(Key_S1 == 1)	/*如果沒有鍵按下(高電平),將一些標誌位及時清零*/
	{
		ucKeyLock1 = 0;/*自鎖標誌位清0*/
		uiKeyTimeCnt1 = 0;/*按鍵去抖動延時計數器清零*/
		if(ucKeyTouchCnt1 > 0)/*如果之前觸發過一次,再來一次就構成雙擊了*/
		{
			uiKeyIntervalCnt1 ++;/*按鍵間隔的時間計數器累加*/
			if(uiKeyIntervalCnt1 > const_interval_time1)/*超過最大允許間隔*/
			{
				uiKeyIntervalCnt1 = 0;
				ucKeyTouchCnt1 = 0; /*清零按鍵的按下的次數*/
			}
		}
		
	}
	else if(ucKeyLock1 == 0)	/*如果有按鍵按下,且是第一次按下*/
	{
		uiKeyTimeCnt1 ++;
		if(uiKeyTimeCnt1 > const_key_time1)
		{
			uiKeyTimeCnt1 = 0;
			ucKeyLock1 = 1;/*自鎖標誌位置位,避免一直觸發*/
			uiKeyIntervalCnt1 = 0;/*按鍵有效間隔的時間計數器清零,鬆開後計數*/
			ucKeyTouchCnt1 ++; /*按鍵觸發一次*/
			if(ucKeyTouchCnt1 > 1)/*連續被按了兩次以上*/
			{
				ucKeyTouchCnt1 = 0;
				ucKeySec = 1; /*觸發S1*/				
			}
		}
	}
	/*掃描S2*/
	if(Key_S2 == 1)	/*如果沒有鍵按下(高電平),將一些標誌位及時清零*/
	{
		ucKeyLock2 = 0;/*自鎖標誌位清0*/
		uiKeyTimeCnt2 = 0;/*按鍵去抖動延時計數器清零*/
		if(ucKeyTouchCnt2 > 0)/*如果之前觸發過一次,再來一次就構成雙擊了*/
		{
			uiKeyIntervalCnt2 ++;/*按鍵間隔的時間計數器累加*/
			if(uiKeyIntervalCnt2 > const_interval_time2)/*超過最大允許間隔*/
			{
				uiKeyIntervalCnt2 = 0;
				ucKeyTouchCnt2 = 0; /*清零按鍵的按下的次數*/
			}
		}
		
	}
	else if(ucKeyLock2 == 0)	/*如果有按鍵按下,且是第一次按下*/
	{
		uiKeyTimeCnt2 ++;
		if(uiKeyTimeCnt2 > const_key_time2)
		{
			uiKeyTimeCnt2 = 0;
			ucKeyLock2 = 1;/*自鎖標誌位置位,避免一直觸發*/
			uiKeyIntervalCnt2 = 0;/*按鍵有效間隔的時間計數器清零,鬆開後計數*/
			ucKeyTouchCnt2 ++; /*按鍵觸發一次*/
			if(ucKeyTouchCnt2 > 1)/*連續被按了兩次以上*/
			{
				ucKeyTouchCnt2 = 0;
				ucKeySec = 2; /*觸發S2*/				
			}
		}
	}
}
/**
* @brief  按鍵服務函數
* @param  無
* @retval 根據掃描得到的值,進行數據處理
**/
void key_Service(void)
{
	switch(ucKeySec)
	{
		case 1: /*S1雙擊*/
				uiVoiceCnt = const_voice_short;  /*蜂鳴器短叫*/			
				ucKeySec = 0; /*響應按鍵服務處理程序後,按鍵編號清零,避免一致觸發*/
		break;
		case 2:/*S2雙擊*/
				uiVoiceCnt = const_voice_short;  /*蜂鳴器短叫*/		
				ucKeySec = 0; 
		break;			
	}
}
/**
* @brief  定時器0中斷函數
* @param  無
* @retval 無
**/
void ISR_T0(void)	interrupt 1
{
	TF0 = 0;  /*清除中斷標誌*/
  TR0 = 0; /*關中斷*/
	/*掃描按鍵*/
	Key_Scan();
	if(0 != uiVoiceCnt)
	{
		uiVoiceCnt --;
		BUZZER = 0;
	}
	else
	{
		BUZZER = 1;
	}
	
	TL0 = T1MS;                     /*initial timer0 low byte*/
	TH0 = T1MS >> 8;                /*initial timer0 high byte*/
  TR0 = 1; /*開中斷*/	
}
/**
* @brief  延時函數
* @param  無
* @retval 無
**/
void Delay_Long(unsigned int uiDelayLong)
{
   unsigned int i;
   unsigned int j;
   for(i=0;i<uiDelayLong;i++)
   {
      for(j=0;j<500;j++)  /*內嵌循環的空指令數量*/
          {
             ; /*一個分號相當於執行一條空語句*/
          }
   }
}
/*——————主函數——————*/
/**
* @brief  主函數
* @param  無
* @retval 實現LED燈閃爍
**/
void main()
{
	/*單片機初始化*/
	Init();
	/*延時,延時時間一般是0.3秒到2秒之間,等待外圍芯片和模塊上電穩定*/
	Delay_Long(100);
	/*單片機外圍初始化*/	
	Init_Peripheral();
	while(1)
	{

		/*按鍵服務函數*/
		key_Service();
	}
}

三、仿真實現

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章