单片机按键“消抖”的思考

初学单片机时,讲到了一个按键“消抖”概念,视屏教程中只是说到要确定按键是不是真正按下,所以需要加一个延时来判断。

附上延时消抖程序代码:
代码1

void keypros()
{
	if(k1==0)		  //检测按键K1是否按下
	{	
		delay(1000);   //消除抖动 一般大约10ms
		if(k1==0)	 //再次判断按键是否按下
		{
			                          //此处添加相应操作
		}
		while(!k1);	 //检测按键是否松开
	}		
}

前不久,又了解到另外两个按键消抖的代码

状态机消抖:
代码2

#define key_input P3
#define key_state_0  0  //判断是否按下
#define key_state_1  1 //判断是否为抖动
#define key_state_2  2 //判断是否弹起

unsigned char t0count;
char key_value; 
  
char read_key(void) 
{ 
 static char key_state = 0; 
 char key_press, key_return = 0; 
 key_press = key_input&key_mask; 
 switch (key_state) 
{ 	
   case key_state_0:     
   if (key_press!=key_mask) key_state = key_state_1; 
   break; 
	 
   case key_state_1:    
   if (key_press!=key_input&key_mask) 
   { 
  	 if(key_press==0x0e) key_return = 1;  //S7
		 if(key_press==0x0d) key_return = 2;  //S6
		 if(key_press==0x0b) key_return = 3;  //S5
		 if(key_press==0x07) key_return = 4;  //S4
  	 key_state = key_state_2;  
   } 
   else 
   	 key_state = key_state_0;  
   break;  
   case key_state_2: 
   if (key_press==0x0f) key_state = key_state_0; 
   break; 
} 
return key_return; 
} 

void tm0_isr() interrupt 1
{
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	t0count++;
	if(t0count>=2)
	{
		t0count=0;
		key_value=read_key();
	}
}
...
if(key_value==...)
{
   //对于操作
}

三行代码消抖:
代码2

#define KEYPORT P3

typedef unsigned char u8;

u8 Trg;
u8 Cont;
u8 t0count;

void Read_key()
{
	u8 readdata=KEYPORT^0xff;                   //核心代码1
	Trg=readdata&(readdata^Cont);              //核心代码2
	Cont=readdata;                             //核心代码3
}

void tm0_isr() interrupt 1
{
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	t0count++;
	if(t0count>=10)
	{
		t0count=0;
		Read_key();
	}
}
...
if(Trg==...)    //短按
{
      //对应操作
}

if(Cont==..)   //长按
{
      //对应操作
}

三种方法为什么都可以“消抖”?
这一问题引起了我的思考。

于是我查询了什么是按键抖动:按键抖动通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动。

如下图:
在这里插入图片描述
由於单片机的运行速度非常快,按下一次按键,可能在A点检测到一次低电平,在B点检测到一次高电平,在C点又检测到一次低电平。同时抖动是随机,不可测的。那么按下一次按键,抖动可能对会让单片机误以为按下多次按键。

延时消抖

最简单的消抖原理,就是当检测到按键状态变化后,先等待一个 10ms 左右的延时时间,让抖动消失后再进行一次按键状态检测,如果与刚才检测到的状态相同,就可以确认按键已经稳定的动作了。

状态机消抖

与延时消抖大同小异,间隔10ms检测一次按键电位变化,状态0时检测到有按键电位变化就进入状态1,状态1再来确认是否还有变化,有则是按下按键。但是由于是利用了定时器,所以在间隔等待10ms时单片机仍可以进行其他进程。

三行代码消抖

真的佩服。
说起来与状态机消抖原理差不多也是利用定时器间隔10ms检测一次按键。但是构思非常巧妙。
当没有按键按下时,Trg与Cont均为0x00。
当单片机执行到此程序且按键按下时(假设P3^0按下),Trg与Cont均为0x01。
当单片机再次执行到此程序且按键按下时(假设P3^0按下),Trg为0x00,Cont为0x01。
而当按键释放,再次检测时,Trg与Cont又均为0x00。(恢复到没有按键按下状态)

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