经典按键算法使用心得

目的:记录自己学习过程

大神按键处理程序:原著
https://blog.csdn.net/qq_26697807/article/details/78196263
另一位大神详细对上面的博文发表的个人看法,并加入防抖
https://blog.csdn.net/tianxuechao/article/details/51675033

程序

1、未加防抖

unsigned char Trg;
unsigned char Cont;

void KeyRead( void )
{
    unsigned char ReadData = PINB^0xff;   // 1
    Trg = ReadData & (ReadData ^ Cont);   //按键按下,trg置一只保持一次
    Cont = ReadData;                      // Cont代表的是长按键,如果按着不放,那么Cont的值就为 1;
}

#define KEY_MODE 0x01    // 模式按键
#define KEY_PLUS 0x02     // 加
void KeyProc(void)
{
       if (Trg & KEY_MODE) // 如果按下的是KEY_MODE,而且你常按这按键也没有用,
    {                    //它是不会执行第二次的哦 , 必须先松开再按下
         Mode++;         // 模式寄存器加1,当然,这里只是演示,你可以执行你想
                         // 执行的任何代码
    }
    if (Cont & KEY_PLUS) // 如果“加”按键被按着不放
    {
         cnt_plus++;       // 计时
         if (cnt_plus > 100) // 20ms*100 = 2S 如果时间到
         {
              Func();      // 你需要的执行的程序
         }          
    }
}

2、加入防抖

//按键变量
unsigned char	KeyPressDown=0x00;
unsigned char	KeyRelease=0x00;
unsigned char	LastKey=0x00;
 
//按键扫描,定时10ms执行一次
void KeyScan(void)
{  	
 	static unsigned char LastReadKey=0x00; 	//记录上次KeyScan()读取的IO口键值
	unsigned char CurrReadKey;  //记录本次KeyScan()读取的IO口键值
	unsigned char CurrKey;    	//记录本次经过消抖处理后的有效按键值	
 
	P1|=KEYMASK;  //将按键对应的IO设置为输入状态
	CurrReadKey=(~P1)&KEYMASK; //取反
	
	//消抖原理很简单:
	//如果上次LastReadKey和当前CurReadKey读取的键值都为1,那么当前有效键值CurrKey一定为1
	//如果上次和当前读取的键值不一样的话,则与上次有效键值LastKey保持一致。
	//通过这种方式来进行消抖,抖动时间必须小于keyscan()定时扫描周期,否则会出现错误。
	CurrKey=(CurrReadKey&LastReadKey)|LastKey&(CurrReadKey^LastReadKey);
	//记录按键按下及释放
	KeyPressDown=(~LastKey)&CurrKey;
	KeyRelease=LastKey&(~CurrKey);
 
	LastReadKey=CurrReadKey;
	LastKey=CurrKey;
}

我是新手,看了半天才领会算法防抖的奇妙
我对程序加注释

void KEY_Check(void)
{
    static unsigned int LastReadKey=0x00; 	//记录上次KeyScan()读取的IO口键值
	unsigned int CurrReadKey;               //记录本次KeyScan()读取的IO口键值
	unsigned int CurrKey;    	            //记录本次经过消抖处理后的有效按键值	

	/********************KEY1_IN引脚运行代码示例*******************************
	           CurrReadKey   CurrKey   KeyTrg    KeyRel    LastKey   LastReadKey
	  初始值:    0x0000       0x0000    0x0000    0x0000    0x0000      0x0000
	按下消抖:    0x0001       0x0000    0x0000    0x0000    0x0000      0x0001   
	确认按下:    0x0001       0x0001    0x0001    0x0000    0x0001      0x0001
	长按按键:    0x0001       0x0001    0x0000    0x0000    0x0001      0x0001
	释放消抖:    0x0000       0x0001    0x0000    0x0000    0x0001      0x0000
	确认释放:    0x0000       0x0000    0x0000    0x0001    0x0000      0x0000
	***************************************************************************/
	CurrReadKey = (~KEY_Signal.iBuf)^0xFFFF;            //读当前IO口键值
	
	CurrKey=(CurrReadKey&LastReadKey)|(LastKey&(CurrReadKey^LastReadKey));    //消抖算法,当前读取键值与上次读取键值相同才说明无已消抖
	
    KeyTrg = CurrKey & (CurrKey ^ LastKey);           //按键按下,KeyTrg置一只保持一次
    KeyRel = LastKey & (LastKey ^ CurrKey);           //按键释放,KeyRel置一只保持一次
    LastKey = CurrKey;                                // LastKey代表的是长按键,如果按着不放,那么LastKey值的对应位为 1
    
    LastReadKey=CurrReadKey;                          //存储当前读取的IO口键值
}
void IO_Read(void)
{  
    KEY_Signal.onebits.bKEY1 = KEY1_IN;
    KEY_Signal.onebits.bKEY2 = KEY2_IN;
    KEY_Signal.onebits.bKEY3 = KEY3_IN;
    KEY_Signal.onebits.bKEY4 = KEY4_IN;
    KEY_Signal.onebits.bKEY5 = KEY5_IN;
    KEY_Signal.onebits.bKEY6 = KEY6_IN;
    KEY_Signal.onebits.bKEY7 = KEY7_IN;

    KEY_Signal.onebits.bKnob1 = Knob_IN1;
    KEY_Signal.onebits.bKnob2 = Knob_IN2;
    KEY_Signal.onebits.bKnob4 = Knob_IN4;
    KEY_Signal.onebits.bKnob3 = Knob_IN3;
    KEY_Signal.onebits.bKnob5 = Knob_IN5;
    KEY_Signal.onebits.bKnob6 = Knob_IN6;
}
typedef union
{
    unsigned int iBuf;
    struct
    {
        unsigned bKEY1 :1;
        unsigned bKEY2 :1;
        unsigned bKEY3 :1;
        unsigned bKEY4 :1;
        unsigned bKEY5 :1;
        unsigned bKEY6 :1;
        unsigned bKEY7 :1;
        unsigned       :1;
        
        unsigned bKnob1 :1;
        unsigned bKnob2 :1;
        unsigned bKnob3 :1;
        unsigned bKnob4 :1;
        unsigned bKnob5 :1;
        unsigned bKnob6 :1;
        unsigned :1; 
        unsigned :1;
    }onebits;
}KEY_TYPE;
           CurrReadKey   CurrKey   KeyTrg    KeyRel    LastKey   LastReadKey
  初始值:    0x0000       0x0000    0x0000    0x0000    0x0000      0x0000
按下消抖:    0x0001       0x0000    0x0000    0x0000    0x0000      0x0001   
确认按下:    0x0001       0x0001    0x0001    0x0000    0x0001      0x0001
长按按键:    0x0001       0x0001    0x0000    0x0000    0x0001      0x0001
释放消抖:    0x0000       0x0001    0x0000    0x0000    0x0001      0x0000
确认释放:    0x0000       0x0000    0x0000    0x0001    0x0000      0x0000

这样看是不是更能理解了?我只要判断LastKey、KeyRel、KeyTrg的值就能判断按键所处的状态,而且通过创建一个共同体就能不受限制的使用任何一个引脚,只要 #define KEY1_IN _RA8,宏定义一下。这里只需要注意共同体的值就可以了。

你可能感兴趣的:(按键处理)