在使用按键时,我们想按一次按键,但在实际中却经常发现我们要的”一次“,实际上去并不是”一次“而可能是多次。为什么呢?这是因为,我们使用的机械按键,在我们按下时,并非只是接触一次,因为存在机械抖动,导致接触多次。因此,按键检测去抖动就很有必要了。下面,我就向大家介绍按键去抖动的方法。
一、STC15W408AS按键威廉希尔官方网站
二、按键按下和松开时的波形
下面的图形中显示的是按键按下和松开时的理想状态和实际状态。
三、按键去抖动方法
理想波形:没有按下为高电平,按下之后为低电平,松开之后又为高电平。
实际波形:按下之后,存在机械抖动,需要过一段时间才会稳定成低电平,然后,松开时又会产生机械抖动。机械式按键在按下或者释放时,由于机械弹性的影响,通常会伴随有一定的时间触电机械抖动,然后其触电才稳定下来。在触点抖动期间检测按键的通与断,可能会导致错误,也就是有可能被认为进行了多次操作,这种情况是不允许出现的。
因此,在单片机检测键盘是否按下都要加上去抖动操作,按键少时,可采用硬件消抖,按键较多时,采用软件消抖。
我们在编写单片机的按键检测程序时,一般在检测按下时加入去抖动延时(10~20ms即可),也就是当检测到按键输入口是低电平时,延时20MS再检测一次按键的状态是不是还是低电平。如果还是低电平,则认为按键被真正按下一次。
四、按键检测去抖动关键代码
if(!GetKey_High()) //如果检测到按键低电平
{
Delay20ms(); //延时20MS
if(!GetKey_High()) //如果还是检测到按键低电平
{
bKeyDown=TRUE; //确认按键已按下
mNum++; //按键次数加1
}
while(!GetKey_High()); //等待按键松开
}
* //1MS定时中断函数Timer0_ISR()
void Timer0_ISR (void) interrupt 1
{
if(mDelay >0)//如果mDelay >0
{
mDelay--; //则中断到来时,mDelay减1
}
}
* //20MS延时函数Delay20ms()
void Delay20ms(void)
{
mDelay=20; //设置mDelay的值为20
while(mDelay >0); //等待mDelay在中断中减到0
}
* //500MS延时函数Delay500ms()
void Delay500ms(void)
{
mDelay=500;
while(mDelay >0);
}
五、本例完整源程序
#define FOSC 11059200L
#define T1MS (65536-FOSC/1000) // 1 T模式
#define BIT0 0x01
#define BIT1 0x02
#define BIT2 0x04
#define BIT3 0x08
#define BIT4 0x10
#define BIT5 0x20
#define BIT6 0x40
#define BIT7 0x80
#define TRUE 1
#define FALSE 0
#define Pin_LED P32
#define Pin_LED_M1 P3M1
#define Pin_LED_M0 P3M0
#define Pin_LED_BIT BIT2
#define PinLed_High() Pin_LED=1
#define PinLed_Low() Pin_LED=0
#define Pin_KEY P12
#define Pin_KEY_M1 P1M1
#define Pin_KEY_M0 P1M0
#define Pin_KEY_BIT BIT2
#define GetKey_High() Pin_KEY==1
#define BOOL unsigned char
#define UINT unsigned int
void PinLED_DirOut(void);
void PinKEY_DirIn(void);
void Timer0_Init(void);
void Delay20ms(void);
void Delay500ms(void);
void LedFlash(UINT num);
BOOL bKeyDown=FALSE;
UINT mDelay=0;
UINT mNum=0;
void main(void)
{
PinKEY_DirIn();
PinLED_DirOut();
PinLed_High();
Timer0_Init();
while(TRUE)
{
if(!GetKey_High())
{
Delay20ms();
if(!GetKey_High())
{
mNum++;
bKeyDown=TRUE;
}
while(!GetKey_High());
}
if(bKeyDown)
{
bKeyDown=FALSE;
LedFlash(mNum);
}
}
}
void PinKEY_DirIn(void)
{
Pin_KEY_M1 &=~Pin_KEY_BIT;
Pin_KEY_M0 &=~Pin_KEY_BIT;
}
void PinLED_DirOut(void)
{
Pin_LED_M1 &=~Pin_LED_BIT;
Pin_LED_M0 |=Pin_LED_BIT;
}
void Timer0_Init(void)
{
AUXR |= 0x80; //定时器0为1T模式
TMOD = 0x00; //设置定时器为模式0(16位自动重装载)
TL0 = T1MS; //初始化计时值
TH0 = T1MS > > 8;
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
EA = 1;
}
// 1ms
void Timer0_ISR (void) interrupt 1
{
if(mDelay >0)
{
mDelay--;
}
}
void Delay20ms(void)
{
mDelay=20;
while(mDelay >0);
}
void Delay500ms(void)
{
mDelay=500;
while(mDelay >0);
}
//为了方便检验效果,我写了下面这个LED闪动函数,第1次按下,LED闪动1次,第2次按下,LED闪动2次,依次类推。
void LedFlash(UINT num)
{
UINT i;
for(i=0;i< num;i++)
{
PinLed_Low();
Delay500ms();
PinLed_High();
Delay500ms();
}
}
全部0条评论
快来发表一下你的评论吧 !