首页 > 代码库 > 多功能检测按键-3 单按 长按 多个按键 响应方式

多功能检测按键-3 单按 长按 多个按键 响应方式

/***************************************
// 函数功能:按键扫描
//这是我第三次对按键扫描的优化,为什么我要这么做呢,很简单,
//我只想将简单的事情不断完善好
//第一次发表:http://blog.csdn.net/chuangwu2009/article/details/9466715
//第一次发表:http://blog.csdn.net/chuangwu2009/article/details/18032195					
*****************************************/

/* 按键响应方式我个人总结了下,一共有11种(包括无按键)
按键响应方式:1:单按键按下响应 2:单按键按下释放响应 3:多按键按下响应

其中按下相应有:1.1:按下马上响应
				1.2:长按后马上响应
				1.3:长按后一直响应(如:长按累加更改时间设置)

释放响应有:      2.1:短按释放响应
				2.2长按释放响应

多按键按下响应有: 1.1 1.2 1.3 2.1 2.2四种组合按键响应方式				 
*/
#define  SETB0   (unsigned char)0x01
#define  SETB1   (unsigned char)0x02
#define  SETB2   (unsigned char)0x04
#define  SETB3   (unsigned char)0x05
#define  SETB4   (unsigned char)0x10
#define  SETB5   (unsigned char)0x20
#define  SETB6   (unsigned char)0x40
#define  SETB7   (unsigned char)0x80



typedef union uFLG1{
	uint8 Flg ;
    struct FLAG1{
        uint8	Flg1   : 1;
        uint8	Flg2   : 1;
        uint8	Flg3   : 1;
        uint8	Flg4   : 1;
        uint8	Flg5   : 1;
        uint8	Flg6   : 1;
        uint8	Flg7   : 1;
        uint8	Flg8   : 1;
    }tFlg1;	
}uFlg1;


uFlg1  F_KEY={0};
//位定义
#define		f_onekey			F_KEY.tFlg1.Flg1//有单按键按下标志
#define		F_longonekey	F_KEY.tFlg1.Flg2//长按标志
#define		f_mulkey			F_KEY.tFlg1.Flg3//多按键标志
#define		F_longmulkey 	F_KEY.tFlg1.Flg4//有多按键按下标志
#define 	F_first    		F_KEY.tFlg1.Flg5//上电识别是否上电按下 开机初始化时 执行 F_first = 1;


//按键响应模式
#define  NONE_KEY			  (unsigned char)0//无效按键值-无按键

#define  ONE_DOWN 			(unsigned char)1
//单个按键按下响应--(短按)按下马上响应
#define	 ONE_LONG_DOWN  (unsigned char)2
//单个按键长按下响应--长按时间到后的(马上)响应
#define  MUL_DOWN			  (unsigned char)3
//多个按键按下响应
#define  MUL_LONG_DOWN  (unsigned char)4
//多个按键长按下响应
#define  ONE_UP    			(unsigned char)5
//单个按键释放响应
#define  MUL_UP    			(unsigned char)6
//多个按键释放响应
#define  ONE_LONG_UP		(unsigned char)7
//单个按键长按后释放响应
#define  MUL_LONG_UP		(unsigned char)8
//多个按键长按后释放响应
#define  ONE_AL_DOWN		(unsigned char)9
//单按键长按之后的响应-长按后一直响应(如:长按累加更改时间设置)
#define  MUL_AL_DOWN		(unsigned char)10
//多按键长按之后的响应

#define  LongAndShortUpIsSame		//长按和短按释放按键功能一样
//定义此宏意思是 在短按按键释放后 或者长按按键后
// 功能执行是一样的 即执行ONE_UP或者MUL_UP的动作

static	 uint8	key_value1=0;//单前按键值
//按键值寄存器-当前按下的值-按下马上响应一次动作

static	uint8	key_value2=0;
//按键值寄存器-前一次的值
//--长按响应一次动作或者按键短按释放响应一次动作
static	uint8	key_value3=0;
//按键值寄存器长按的值---长按后一直响应

static	uint8 mode_key=0;//按键响应模式


void Key_scan(void)	 // 
{


  static	uint8	key_delay=0;//按键去抖动寄存器
  static	uint8	key_value0=0;//前一次按键值寄存器

  static	uint8	key1_mult=0;//多按键寄存器2
  
  static	uint8	key_longtime=0;//长按时间累积寄存器1
  static	uint8	key_longtime1=0;//长按时间累积寄存器2
  
  uint8	key_mult=0;//多按键寄存器1

  
  if(!P_K0)//	
  {
		key_value1|=SETB0;
		key_mult++;
  } 
  
  if(!P_K1)//
  {
		key_value1|=SETB1;	
		key_mult++;
  }
  /*
  if(!P_K2)//
  {
		key_value1|=SETB2;	
		key_mult++;
  } 
  if(!P_K3)//
  {
		key_value1|=SETB3;	
		key_mult++;
  } 
  if(!P_K4)//
  {
		key_value1|=SETB4;	
		key_mult++;
  } 
  */
  
  
  if(key_value1 == key_value0)//如不响等,保存当前按键值,清抖动寄存器,以此次识别
  {
    if(key_delay > 10)//抖动处理
    {
      if(key_value1 > 0)//无按键按下确认,等于0时表示无按键
      {
        if(1 == key_mult)
        {//单按键按下处理程序
            if(!f_onekey)
            { //单按键短按按下处理程序
                    f_onekey=1;
                    key1_mult=0;
                    mode_key=ONE_DOWN;
            }
            else
            {//单按键长按
							if(!F_longonekey)
							{//还没达到长按时间
								if(++key_longtime>=100)//
								{
									 key_longtime=0;
									 if(++key_longtime1>=15)
									 {//长按时间到
													 key_longtime1=0;	
													 mode_key=ONE_LONG_DOWN;
													 F_longonekey=1;
													//长按按键处理程序
									 }
								}
								else								
								{//还没达到长按时间
									mode_key=NONE_KEY;
								}
							}
							else
							{//单按键长按之后的响应
								
								mode_key = ONE_AL_DOWN;

							}
            }
        }
        else
        {	   //多按键按下处理程序
          key1_mult=1;
          if(!f_mulkey)
          {//多按键短按下相应
							f_mulkey=1;	
							f_onekey=1;	
		//	f_onekey=1;	防止多个按键释放时候,不同时释放,响应单个按键功能
							mode_key=MUL_DOWN;
          }
          else
          {//多按键长按
						if(!F_longmulkey)
						{
							if(++key_longtime>=100)//2毫秒1次  100*2*15=3秒
							{
								 key_longtime=0;
								 if(++key_longtime1>=15)
								 {
									 key_longtime1=0;//3秒时间到	
									 
									 F_longmulkey=1;
									//多按键长按按键处理程序
									 mode_key=MUL_LONG_DOWN;
									}
																							
							 }
							 else
							{
											mode_key=NONE_KEY;
							}
						}
						else
						{
										//多按键长按之后的响应
										mode_key = MUL_AL_DOWN;
						}
				  }	
			  }   
       }
        else//按键释放或者无按键
       {
              
        f_mulkey=0;
        F_first=0;

        key_longtime=0;
        key_longtime1=0;
        if(F_longonekey)
        {//长按单按键释放
            F_longonekey=0;
            #ifdef (LongAndShortUpIsSame)
						 mode_key=ONE_UP;
						#else
						 mode_key=ONE_LONG_UP;
						#endif
           
                
        }
        else if(F_longmulkey)
        {//长按多按键释放
            F_longmulkey=0;	
    
						#ifdef (LongAndShortUpIsSame)
						 mode_key=MUL_UP;
						#else
						 mode_key=MUL_LONG_UP;
						#endif
				
        }
        else if(f_onekey)
        {//短按按键释放
                        
            if(0==key1_mult)
            {
                mode_key=ONE_UP;
            }
            else
            {
                mode_key=MUL_UP;	
            }
        }
        else
        {
             mode_key=NONE_KEY;
        }
        f_onekey=0;  
       }
    }
    else  
    {//滤波处理
            key_delay++;
    }
  }
  else
  {
          key_value0=key_value1;
          key_delay=0;
  }
		
}

//*************************************
// 函数名称:key_deal
// 函数功能:按键响应后的处理
// 入口参数:无
// 出口参数:无
//***************************************/


void key_deal(void)
{
  static uint8	key_longtime=0;//长按时间累积寄存器1


  switch(mode_key)
  {
    case ONE_DOWN://单个按键按下响应
    {
			switch(key_value1)
			{
			 case SETB1://P_K1短按下响应
			 {		
						key_value2 =	key_value1;		
						
						if(F_first)
						{//按住按键上电响应-要执行的动作-常用于自检
							
							
							break;
						}
							break;
				}
				 case SETB0:///P_K0短按下响应
				 {		
							key_value2 =	key_value1;	
							if(F_first)
							{
									
									break;
							}
							
							break;
				 }
				default:  
				break;
			}
			
    key_value1 = 0;	
    
    break;
    }
    case ONE_LONG_DOWN://单个按键长按下响应--相应一次
    {
				key_value3=key_value2;
				
				  switch(key_value2)
					{
									 
						case SETB1:
					 {		
										
									break;
					 }
					 case SETB0:
					 {		
							
									break;
					 }
									
									default:  
									break;
					}
					
					key_value2=0;
                    
    break;
    }
    case MUL_DOWN://多个按键按下响应
    {
					switch(key_value1)
					{		 
							case (SETB1|SETB0):
						 {		
														key_value2 = key_value1;
										break;
						 }	
						default:  
						break;
					}     
          key_value1=0;
      
    break;
    }
    case MUL_LONG_DOWN://多个按键长按下响应
    {
    
				if(key_value2==(SETB0|SETB1))
				{
					key_value3=key_value2;
				}
				
				key_value2=0;
    break;
    }
    case ONE_UP://单个按键释放响应
    {
				switch(key_value2)
				{
								 case SETB0:
								 {//TURBO释放
												
												break;
								 }
								 case SETB1:
								 {							 	
												
												
												break;
								 }
								default:  
								break;
				}
					key_value2=0;//按键释放后清零
    break;
    }
    case MUL_UP://多个按键释放响应
    {        
					key_value2=0;//按键释放后清零
					key_value3=0;

    break;
    }		
    case ONE_LONG_UP://单个按键长按后释放响应
    {	
                    
				switch(key_value3)
				{
						 case SETB0:
						 {//TURBO释放
										
														
										break;
						 }
						 case SETB1:
						 {							 	
										
										
										break;
						 }
						default:  
						break;
				}
				key_value2=0;//
				key_value3=0;
            
    break;
    }
    case MUL_LONG_UP://多个按键长按后释放响应
    {
                            
                     
				key_value2=0;//按键释放后清零
				key_value3=0;
    break;
    }
    case ONE_AL_DOWN://单按键长按之后的响应
    {
                            
			if(++key_longtime>=100)//2毫秒1次  40*15*5=3秒
			{
				key_longtime=0;
							
				 switch(key_value3)
				{
					 case SETB0:
					 {							 	
									
									break;
					 }
					 case SETB1:
					 {							 	
									
									
									break;
					 }
					default:  
					break;
				}	
			}	
    break;
    }
    case MUL_AL_DOWN://多按键长按之后的响应
    {	
          if(++key_longtime>=100)//2毫秒1次  40*15*5=3秒
				{
								 key_longtime=0;
				}	
    break;
    }
    default:
    break;
  }
}