找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 28496|回复: 11
打印 上一主题 下一主题
收起左侧

按键消抖方法与抖动原因分析(状态机,延时,逻辑关系消抖)单片机源程序

  [复制链接]
跳转到指定楼层
楼主
本人第一次发帖,如果有错误,欢迎大家指正!!!有关按键消抖的话题已经有很多人提出来了,在这里我把它进行一个总结。希望能帮助到大家!
1.按键抖动的原因
       按键消抖通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。形成以下的波形
   
2.按键抖动的原理
      按键抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。这是一个很重要的时间参数,在很多场合都要用到。按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。键抖动会引起一次按键被误读多次。为确保单片机对按键的一次闭合仅作一次处理,必须去除键抖动。在键闭合稳定时读取键的状态,并且必须判别到按键释放到稳定状态后再去作处理。
3.按键消抖的方法
(1)硬件的消抖
      利用电容的充放电特性来对抖动过程中产生的电压毛刺进行平滑处理,从而实现消抖。在按键的两端并联一个0.1uf的电容。如按键消抖硬件图

(2)软件的消抖
     1.延时消抖
        刚接触单片机的时候,最常用的方法,利用延时,消去抖动。代码如下:
       if(按键是否按下)
       {                        //按键按下的条件下
           Deadly_1ms(5); // 延时消去抖动
           if(按键是否按下)
          {                   //按键再次确认按下
              //执行按键功能
             while(按键是否松开);
          }
       }
   注:按键详细代码见工程文件延时消抖
    2.状态机消抖
      将按键的状态分为三种 是否按下,是否抖动,是否弹起。检测到按下时,转向判断是否抖动,并执行按键功能。等按键功能执行完了以后直接跳到按键是否弹起的状态。等弹起后,再来判断是否按下的状态。
       在按键的原理图中,将1、2相接,则构成的是4*4的矩阵键盘,并且矩阵键盘与单片机的P3口相接。
       //按键原理图见上传的图片
        
//设置按键的三种状态及按键接口
#define KEY P3
#define key_state_0  0  //判断是否按下
#define key_state_1  1 //判断是否为抖动
#define key_state_2  2 //判断是否弹起

unsigned char key_read(void)
{
  static char key_state = key_state_0;
  unsigned char key_return=0, key_press;
  unsigned char key1,key2;
        
        KEY=0xf0;   
        key1=KEY&0xf0;
        KEY=0x0f;
        key2=KEY&0x0f;
        key_press =key1|key2;  //读取矩阵按键每个按键的状态,存在key_press里
        
switch (key_state)  // 判断按键状态
{         
   case key_state_0:    //是否按下
   if (key_press!=0xff) key_state = key_state_1;  //没有按键按下时则读取出的0xff,若有不同说明有按键按下,则跳转到判断是否为抖动的状态
   break;
         
   case key_state_1:     
   if (key_press !=0xff) //再次确认是否按下,防止因单片机的速度过快,导致误判。
   {   
       switch (key_press)//根据key_press的值来执行相对应的功能
       {
           case 0xee: key_return = 19; //这里的0xee是怎么的来的,简单来推一下
           case 0xed: key_return = 18; //单片机的P3口初始化输出的是高电平,先将P3口输出0xf0,如果有按键按下,则P3口中的高四位的某一位的电平会被拉低,此时记录P3口的状态(key1)
           case 0xeb: key_return = 17; //读取了高四位的电平,之后再来读取低四位的电平(key2) ,之后 | 在一起得到key_press,得到的key_press中一定有两位是0;
           case 0xe7: key_return = 16;//举例 : 当我按下s19时,key1 = 0xe0;(即P3^4 = 0,高四位的第一位电平被拉低),key2 = 0x0e;(即P3^0 = 0,低四位的第一位电平被拉低),这样key_press = key_press =key1|key2  = 0xee;
           case 0xde: key_return = 15;//以此类推
           case 0xdd: key_return = 14;
           case 0xdb: key_return = 13;
           case 0xd7: key_return = 12;
           case 0xbe: key_return = 11;
           case 0xbd: key_return = 10;
           case 0xbb: key_return = 9;
           case 0xb7: key_return = 8;
           case 0x7e: key_return = 7;
           case 0x7d: key_return = 6;
           case 0x7b: key_return = 5;
           case 0x77: key_return = 4;
       }
                        key_state = key_state_2; //这里跳转到判断弹起的状态
   }
   else
                        key_state = key_state_0;  
   break;

   case key_state_2:
   if (key_press==0xff) key_state = key_state_0;  //等待按键完全弹起
   break;
}
return key_return;
}
注:具体用法见工程状态机消抖  

    3.逻辑关系消抖
       将按键的原理图中,将2、3相接,则构成的是独立键盘(s4,s5,s6,s7),并且独立键盘与单片机的P3口的低四位相接,另一端与gnd相接。
    利用逻辑关系 与&、或 | 、非 !、异或 ^,来消除抖动。先贴出源代码:

    unsigned char ReadData = KEYPORT^0xff;
    Trg = ReadData & (ReadData ^ Cont);      
    Cont = ReadData;

    Trg是判断那个按键按下,Cont用来判断长按、短按的;
分析:   (1)没有按键按下(初始值 Trg  =  0,Cont  = 0)
                  unsigned char ReadData = P3^0xff;  => ReadData  = 0xff ^0xff = 0x00;
                  Trg = ReadData & (ReadData ^ Cont); =>Trg  =0x00 &  (0x00 ^0x00)  = 0x00;
                  Cont = ReadData;    =>Cont  = 0x00;

                 结果 :
                         ReadData  = 0x00
                        Trg           = 0x00
                        Cont         = 0x00

            (2) s4按下
                  刚按下时
                  unsigned char ReadData = P3^0xff;  => ReadData  = 0xf7 ^0xff = 0x08;
                  Trg = ReadData & (ReadData ^ Cont); =>Trg  =0x08 &  (0x08^0x00)  = 0x08;
                  Cont = ReadData;    =>Cont  = 0x08;

               抖动时
                  unsigned char ReadData = P3^0xff;  => ReadData  = 0xff ^0xff = 0x00;
                  Trg = ReadData & (ReadData ^ Cont); =>Trg  =0x00 &  (0x00^0x08)  = 0x00;
                  Cont = ReadData;    =>Cont  = 0x00;

                 结果 :
                       刚按下时:
                        ReadData  = 0x08
                        Trg           = 0x08
                        Cont         = 0x08

                       抖动时:
                        ReadData  = 0x00
                        Trg           = 0x00
                        Cont         = 0x00


            (3) s4长按
                  unsigned char ReadData = P3^0xff;  => ReadData  = 0xf7 ^0xff = 0x08;
                  Trg = ReadData & (ReadData ^ Cont); =>Trg  =0x08 &  (0x08 ^0x00)  = 0x00;
                  Cont = ReadData;    =>Cont  = 0x08;

                 结果 :
                         ReadData  = 0x08
                        Trg           = 0x00
                        Cont         = 0x08


            (4) s4松开
                  unsigned char ReadData = P3^0xff;  => ReadData  = 0xff ^0xff = 0x00;
                  Trg = ReadData & (ReadData ^ Cont); =>Trg  =0x08 &  (0x08 ^0x00)  = 0x00;
                  Cont = ReadData;    =>Cont  = 0x00;

                 结果 :
                         ReadData  = 0x00
                        Trg           = 0x00
                        Cont         = 0x00


将上面的数据进行汇总、分析
ReadData  Trg           Cont         
没有按键按下 0x00 0x00 0x00
s4刚按下 0x08 0x08 0x08
s4有抖动时 0x00 0x00 0x00
s4长按 0x08 0x00 0x08
  s4松开 0x00 0x00 0x00


Trg只有在按键刚按下时有不到等于0的值,因此我们检测到Trg 不为0时,说明有按键按下;
Cont 只要有按键按下时,它的值就不为0,因此我们定时一段时间,来检测Cont,,若不变,则按键时长按的状态。
注:具体用法见工程逻辑关系消抖

          到这里只是简单的介绍了几种按键消抖,还有很多方法没有介绍,比如,中断消抖,门电路消抖,计时消抖…,但万变不离其中。学会了其中一种,其他的就自然懂了。
         希望这篇帖子能帮助到大家!!!!

全部资料51hei下载地址(全部程序源码):
按键.rar (68.28 KB, 下载次数: 155)


评分

参与人数 2黑币 +105 收起 理由
lakeleeson + 5 很给力!
admin + 100 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏29 分享淘帖 顶2 踩
回复

使用道具 举报

沙发
ID:391536 发表于 2018-8-31 14:09 | 只看该作者
楼主写的非常详细 好资料,51黑有你更精彩!!!
回复

使用道具 举报

板凳
ID:896842 发表于 2021-3-26 14:36 | 只看该作者
楼主写的很好,先收藏研究一下
回复

使用道具 举报

地板
ID:15415 发表于 2023-5-29 16:48 | 只看该作者
非常好的资料,谢谢楼主
回复

使用道具 举报

5#
ID:202023 发表于 2023-6-21 10:55 | 只看该作者
不错,万丈高楼平地起,越是看似简单的东西,越要用心去学。谢谢楼主分享。
回复

使用道具 举报

6#
ID:202023 发表于 2023-6-21 11:01 | 只看该作者
楼主是你的资料有问题,还是我的软件有问题。

error.JPG (50.54 KB, 下载次数: 38)

error.JPG
回复

使用道具 举报

7#
ID:202023 发表于 2023-6-21 11:03 | 只看该作者
oh,在不解压下可以打开,解压了反而打不开了,是我的原因。
回复

使用道具 举报

8#
ID:423911 发表于 2023-8-13 09:16 | 只看该作者
感谢楼主,非常好的资料,很有用。
回复

使用道具 举报

9#
ID:34149 发表于 2023-8-15 10:45 | 只看该作者
分析很透彻!好办法!
回复

使用道具 举报

10#
ID:224580 发表于 2023-8-17 14:08 | 只看该作者
分析很透,佩服这些大神
回复

使用道具 举报

11#
ID:1083996 发表于 2023-8-20 09:55 | 只看该作者
很棒的分析,感谢分享。
回复

使用道具 举报

12#
ID:202023 发表于 2023-8-30 13:19 | 只看该作者

楼主写的非常详细 好资料,51黑有你更精彩!!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表