单片机按键去抖动的方法

描述

在使用按键时,我们想按一次按键,但在实际中却经常发现我们要的”一次“,实际上去并不是”一次“而可能是多次。为什么呢?这是因为,我们使用的机械按键,在我们按下时,并非只是接触一次,因为存在机械抖动,导致接触多次。因此,按键检测去抖动就很有必要了。下面,我就向大家介绍按键去抖动的方法。

一、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();

        }

}
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分