找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6599|回复: 9
收起左侧

51单片机按键消抖方式总结

  [复制链接]
ID:937285 发表于 2021-8-20 16:39 | 显示全部楼层 |阅读模式
电路图如下:
MCU采用89C52单片机,晶振12MHZ。
1.png

1、没有消除抖动的原始代码:
  1. #include <REGX52.H>
  2. #include <intrins.h>
  3. sbit KeyValue=P3^7;
  4. unsigned char code segment[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
  5. //定义数码管显示0~9
  6. void main(){
  7.         static char count=1;
  8.         P2=segment[0]; //开始运行显示0
  9.         while(1){
  10.                 if(KeyValue==0){
  11.                         P2=segment[count];
  12.                         count++;
  13.                         if(count>=10){   //超过0~9,数码管显示回到0
  14.                                 count=0;
  15.                         }
  16.                 }
  17.         }
  18. }

复制代码
2、延时消除抖动

存在如下缺点:

  • delay()延时函数会占用大量时间;
  • 需要while循环不断的扫描按键,对单片机运算资源的浪费。
    1. #include <REGX52.H>
    2. #include <intrins.h>
    3. sbit KeyValue=P3^7;
    4. unsigned char code segment[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
    5. void delay(){ //延时程序
    6.         unsigned int i=20500;
    7.         while(i--);
    8. }
    9. void main(){
    10.         static char count=1;
    11.         P2=segment[0];
    12.         while(1){
    13.                 if(KeyValue==0){//按键按下
    14.                         delay();//延时一段时间
    15.                         if(KeyValue==0){//重新判断按键状态
    16.                                 P2=segment[count];
    17.                                 count++;
    18.                                 if(count>=10){
    19.                                 count=0;
    20.                                 }
    21.                         }
    22.                 }
    23.         }
    24. }

    复制代码

3、使用定时器消抖
原理说明:1次按下+1次抬起构成一个按键动作,当同时检测到这两个动作时,才完成一次按键操作。按下时,将按键值存储为0;抬起时,将按键值存储为1。在前一次的按键值为0的前提下,检测当前按键值是否为1,如果为1,表示此次按键有效,否则此次按键无效。


缺点:会占用一个定时
  1. #include <REGX52.H>
  2. #include <intrins.h>
  3. sbit KeyValue=P3^7;
  4. bit  KeyStatus=1;
  5. unsigned char code segment[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

  6. void main(){
  7.         bit KeySave=1;
  8.         unsigned char count=0;
  9.         P2=segment[0];
  10.         /**************开启中断**************************/
  11.         EA=1;
  12.         TMOD=0x01;
  13.         TH0=0xF8;
  14.         TL0=0xCD;
  15.         ET0=1;
  16.         TR0=1;
  17.         while(1){
  18.                 if(KeyStatus!=KeySave){//检测按键值是否改变,初始时按键值为1,在此检测按键值是否变为0,为0则继续
  19.                         if(KeySave==0){//如果前一次的按键值为0,说明本次按键抬起,本次按键有效;否则为按键按下操作,跳转到最后一步,将按键值取反
  20.                                 count++;//对按键值+1
  21.                                 if (count>=10){
  22.                                         count=0;
  23.                                 }
  24.                                 P2=segment[count];
  25.                         }
  26.                         KeySave=~KeySave;
  27.                 }
  28.         }
  29. }
  30. void InterruptTimer0() interrupt 1 {
  31.         static unsigned KeyBuff=0xff;
  32.         TH0=0xF8;
  33.         TL0=0xCD;
  34.         KeyBuff=(KeyBuff<<1)|KeyValue;
  35.         switch(KeyBuff){
  36.           case 0xff:
  37.                         KeyStatus=1;
  38.                   break;
  39.           case 0x00:
  40.                         KeyStatus=0;
  41.                   break;
  42.           default:
  43.                   break;
  44.   }        
  45. }
复制代码

评分

参与人数 1黑币 +50 收起 理由
admin + 50

查看全部评分

回复

使用道具 举报

ID:872412 发表于 2021-8-25 20:05 | 显示全部楼层
还可以搞两个for嵌套循环! 最外层记录按了多少次,用来处理多次连续按键。内层在规定时间内有按键动作记为真,超过规定时间记为假,这样可以高效消抖
回复

使用道具 举报

ID:964826 发表于 2021-9-9 09:51 来自手机 | 显示全部楼层
我记的网上有人利用标志位进行消抖,用延时的话有点困难
回复

使用道具 举报

ID:398219 发表于 2021-9-9 14:47 | 显示全部楼层
一般来说都是延时5MS,小程序上用不了多少
回复

使用道具 举报

ID:34149 发表于 2021-9-11 19:27 | 显示全部楼层
原理分析到位!多谢分享
回复

使用道具 举报

ID:839438 发表于 2021-9-30 10:42 | 显示全部楼层
其实这个就是状态机
回复

使用道具 举报

ID:969407 发表于 2021-10-4 15:45 来自手机 | 显示全部楼层
挺好的啊,我自己也是这样使用的
回复

使用道具 举报

ID:966104 发表于 2021-10-5 07:10 | 显示全部楼层
这样很难吗?               
                if(K5 == 0)        
                {
                        DelayM(20); q = ~q;                //标志位取反
                        if(q){kai_numl = kai_numl | 1;}
                                     else { kai_numl = kai_numl&0;}
                         if(q){BLK = BLK | 1;}
                                else {BLK= BLK & 0;}
                        while(K5 == 0);
                                
                }
回复

使用道具 举报

ID:970710 发表于 2021-10-9 17:04 | 显示全部楼层
主意不错,站位留存一下!
回复

使用道具 举报

ID:831736 发表于 2021-10-11 16:55 | 显示全部楼层
if(!key)
while(1)
{
//如果有显示程序写一遍在这里
if(key)
  {
  //按键要实现的功能
  break;
  }
}
这样写只能按一次实现一次
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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