找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3032|回复: 17
收起左侧

单片机如何进行按钮抬起瞬间的防抖?

  [复制链接]
ID:430774 发表于 2019-5-6 16:54 | 显示全部楼层 |阅读模式
  1. #include "reg52.h"                        
  2. typedef unsigned int u16;          //对数据类型进行声明定义
  3. typedef unsigned char u8;

  4. sbit LSA=P2^2;
  5. sbit LSB=P2^3;
  6. sbit LSC=P2^4;
  7. sbit beep=P1^5;           
  8. sbit k=P3^2;
  9. u16 a,b,c;
  10. u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
  11.                                         0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值
  12. u8 mb[2];
  13.         static u8 h;
  14. /*******************************************************************************
  15. * 函 数 名         : delay
  16. * 函数功能                   : 延时函数,i=1时,大约延时10us
  17. *******************************************************************************/
  18. void delay(u16 j)
  19. {
  20.         while(j--);        
  21. }

  22. /*******************************************************************************
  23. * 函 数 名       : main
  24. * 函数功能                 : 主函数
  25. * 输    入       : 无
  26. * 输    出             : 无
  27. *******************************************************************************/
  28. void zhongduan()
  29. {
  30.          IT0=1;//下降沿有效
  31.          EX0=1;  // 哪个外部中断有效
  32.           TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。

  33.         TH0=0XFC;        //给定时器赋初值,定时1ms
  34.         TL0=0X18;        
  35.         ET0=1;//打开定时器0中断允许
  36.         EA=1;//打开总中断
  37.         
  38.         b=0,c=0,beep=0,h=0;
  39. }


  40. void Timer0() interrupt 1
  41. {
  42.         static u16 h;
  43.         TH0=0XFC;        //给定时器赋初值,定时1ms
  44.         TL0=0X18;
  45.         EX0=0;
  46.         h++;
  47.         if(h==8)
  48.         {
  49.          b=1;
  50.          c++;
  51.         }        
  52.         if(h==300)
  53.         {        
  54.    h=0;               
  55.    EX0=1;
  56.          TR0=0;                                
  57.         }        
  58. }


  59. void zhong() interrupt 0
  60. {
  61.          EX0=0;
  62.          TR0=1;
  63.          
  64. }


  65. void DigDisplay()
  66. {
  67.         u8 i;
  68.         for(i=0;i<2;i++)
  69.         {
  70.                 switch(i)         //位选,选择点亮的数码管,
  71.                 {
  72.                         case(0):
  73.                                 LSA=0;LSB=0;LSC=0; break;//显示第0位
  74.                         case(1):
  75.                                 LSA=1;LSB=0;LSC=0; break;//显示第1位        
  76.                 }
  77.                 P0=smgduan[mb[i]];//发送段码
  78.                 delay(1); //间隔一段时间扫描        
  79.                 P0=0x00;//消隐
  80.         }
  81. }
  82. void fengmingqi()
  83. {
  84.         
  85. if(b==1)
  86.         {
  87.                 for(a=0;a<100;a++)
  88.                 {
  89.                         beep=~beep;
  90.                   delay(10);                        
  91.                 }        
  92.                 b=0;            //延时大约100us   通过修改此延时时间达到不同的发声效果        
  93.   }

  94. }        


  95. void main()
  96. {        
  97.         zhongduan();
  98.         
  99.         while(1)
  100. {        
  101.           fengmingqi();
  102.       mb[0]=c%10;           //秒表个位
  103.             mb[1]=c/10;           //秒表十位  
  104.                  DigDisplay();   
  105. }
  106. }
复制代码
回复

使用道具 举报

ID:430774 发表于 2019-5-6 16:55 | 显示全部楼层
有时候会连续加两个数,应该是抬起瞬间有反应,按下的防抖处理好了,抬起的不知道怎么处理了
回复

使用道具 举报

ID:528454 发表于 2019-5-6 18:21 | 显示全部楼层
加个延时程序?
回复

使用道具 举报

ID:503191 发表于 2019-5-6 18:24 | 显示全部楼层
按钮两端并个电容?
回复

使用道具 举报

ID:528454 发表于 2019-5-6 18:40 | 显示全部楼层
加一个电容,这是比较普遍的应用
回复

使用道具 举报

ID:528677 发表于 2019-5-6 18:42 | 显示全部楼层
延时消抖,然后等待手抬起
回复

使用道具 举报

ID:528677 发表于 2019-5-6 18:49 | 显示全部楼层
延时消抖,然后等待手抬起例如:
if(key==0)
{   
    delay();
    while(!key);
}     进入外部中断也能这样,按下键不松手时显示可能会出问题,松开就好了。
回复

使用道具 举报

ID:528642 发表于 2019-5-6 21:26 | 显示全部楼层

RE: 单片机如何进行按钮抬起瞬间的防抖?

消除方法有两种:软件除抖和硬件除抖,其中硬件除抖是应用了电容对高频信号短路的原理。
软件除抖是检测出键闭合后执行一个延时程序,产生5ms~10ms的延时,让前沿抖动消失后再一次检测键的状态,如果仍保持闭合状态电平,则确认为真正有键按下。
回复

使用道具 举报

ID:486487 发表于 2019-5-6 21:58 | 显示全部楼层
首先:硬件设计上必须要求在入口处并一个104电容。
然后:用示波器多抓几次按键按下和抬起的波形,找到按下和抬起的按键的干扰波形的宽度。
最后:程序再延时读取按键值,延时时间为:干扰波宽度*1.5,其中1.5可以视具体情况调整。
回复

使用道具 举报

ID:529213 发表于 2019-5-7 09:47 来自手机 | 显示全部楼层
加电容好些,在按键两端并联零点一到零点零一微法的无极性电容,千万别别用电解电容,因为电解电容漏电大,要用mkp之类的薄膜电容,严禁并电解电容。
回复

使用道具 举报

ID:123289 发表于 2019-5-7 11:09 | 显示全部楼层
消抖不分上下沿:
例如:
每间隔4ms检测一次,连续8次检测结果一样,则可判定为稳定。
回复

使用道具 举报

ID:430774 发表于 2019-5-7 13:49 | 显示全部楼层
yzwzfyz 发表于 2019-5-7 11:09
消抖不分上下沿:
例如:
每间隔4ms检测一次,连续8次检测结果一样,则可判定为稳定。

我现在用的就是这种,定时器里检测5毫秒一直是按下状态就+1
回复

使用道具 举报

ID:123289 发表于 2019-5-8 14:20 | 显示全部楼层
这样也只是可以知道状态稳定了。
稳定了,有以下几种状态况,需要你进行一下甄别:
1、一直未按。
2、按下了还未松开。
3、松开后的稳定(与1同类,需要你区分)。
……
这是难点!!有技巧,自己想想。(提示:将各种可能情况做标记,进行分析。)
回复

使用道具 举报

ID:530796 发表于 2019-5-8 17:06 | 显示全部楼层
改善硬件
回复

使用道具 举报

ID:162317 发表于 2019-5-9 09:52 | 显示全部楼层
unsigned char key_ret = 0;//外部文件调用需申明 extern unsigned char key_ret;

unsigned char Key_Scan(void)
{
static unsigned char key_num = 0;
static unsigned char del_count,tim_count;
static bit key_flag = 0;
/////////////////////////////////////////////////////
if(KEY==1) key_ret = 0;       
if(KEY==0) /*判断是否有键按下可以是多个按键,例:if((KEY1==0)||(KEY2==0)||(KEY3==0))*/
   {
          if(++del_count>25)/*计数消抖(一般放在中断里,计数完大于20ms即可)*/
          {
            del_count = 0;
                  if(++tim_count>25)/*长按识别*/
                   {
                                        key_flag = 0;/*短按无效*/
                                        tim_count = 25;/*锁定长按*/
                                        switch(key_num)
                                                {
                                                 case 1:key_ret = 2;break;
                                                }                   
                        }                       
                 else/*短按有效*/
                   {
                          key_flag = 1;/*短按标志位*/
                          if(KEY==0) { key_num = 1;}/*一下用于识别按键*/                
                       
                    }        
                }       
        }                                           
        else/*松手之后*/
          {
                        tim_count = 0;
                        del_count = 0;
                        if(key_flag)/*松手*/
                                {
                                        key_flag = 0;
                                        switch(key_num)
                                                {
                                                case 1:key_ret = 1;break;
                                                }  
                                }                                        
          }                                               
        return key_ret;
                                        }
///////使用方法//
/*                                       
if(key_ret==1)
{
        key_ret=0;
        要执行的程序
}               

*/

回复

使用道具 举报

ID:531713 发表于 2019-5-9 16:38 | 显示全部楼层
延时消抖
   if(S1==0) {
            Delay10ms();
             if(S1==0) {      
                //要做的事
            }
}
回复

使用道具 举报

ID:505065 发表于 2019-5-9 21:29 | 显示全部楼层
一个是用延时消抖,另一个就是用外部中断
回复

使用道具 举报

ID:514901 发表于 2019-5-10 00:13 | 显示全部楼层
延时消抖有时候不管用,这时候要用暴力消抖
if(key==0)
{
while(!key);
……
}
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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