一乐电子

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

微信扫码登录

搜索
楼主: dianzichina

[其他综合] 按键中断老是按一次跳好几次,谁能给出一个防抖例程?

  [复制链接]
发表于 2012-8-6 14:36 | 显示全部楼层
本帖最后由 gw168sh 于 2012-8-6 14:48 编辑

中断里面做个标志位,主程序里面跑的时候检测到标志就进去判断键盘。中断程序里面不要做那么多事情。

另外关于按键的防抖,教程上面写的都是用延时+等待按键放开。
这样做最大弊端就是你按着不放的时候数码管不扫描了。
做个标志位(也可以叫状态机),主程序进来的时候标志bz=1,主程序里面用if(bz==1)判断现在要不要进去判断按键,进去后如果up_key==0马上就可以执行,比如说h++; 执行完这句,把bz=0;这样bz不等于1,他就再也进不来做h++了(即使按键还没放开)。
紧接着这个if语句下面写
else if(up_key==1) bz=1; 如果按键放开了,就把标志改过来
我测试过,如果这样写,按键程序即使不加延时防抖也没问题,按下不放开数码管也不会停止扫描。
CPU不用再去做那些无用的延时,等待,节省出更多的时间来做别的事情。
回复 1 0

使用道具 举报

 楼主| 发表于 2012-8-6 18:28 | 显示全部楼层
回复 10# 199003326
现在我看到了好几种版本,很多人把显示子程序放在了时钟中断部分(A),有的人把显示子程序放在了按键扫描部分(B),有的人把显示还是放在主程序区循环扫(C)。对于液晶,有一点好处就是它自带刷新电路,不需要刷新。但这样一来,主程序啥都不干了,一条空指令在那里无穷地等待。。。。。。到底哪种方案更好呢。

我现在感觉最好的方案就是我的电子表,无论怎样按键,秒都不停。。。

对于A,估计反对的人多,中断干的事太多了。。。对于B,问题是在没有按键按下的时候显示内容没有更新。。。对于C,貌似没有很好地利用液晶的自带扫描电路,CPU很累的说。。。。。

我个人的思路是:按键处理用中断,设置标志,主程序做时间数值计算,并检测按键标志,有则处理,无则继续作计算。。。。。。
回复

使用道具 举报

发表于 2012-8-6 21:05 | 显示全部楼层
回复  199003326
现在我看到了好几种版本,很多人把显示子程序放在了时钟中断部分(A),有的人把显示子程序 ...
dianzichina 发表于 2012-8-6 18:28 https://www.yleee.com.cn/images/common/back.gif



    相反,俺支持A,草版的程序是用在16*64的点阵屏上的,进中断一次扫描一行,用定时器可保证刷新频率;同时把按键扫描部分也放进定时器中断内(处理函数在外),可保证按键及时响应。
回复

使用道具 举报

发表于 2012-8-6 21:28 | 显示全部楼层
本帖最后由 lihongran 于 2012-8-6 22:33 编辑

首先,不要在中断里放置原地打转的延时。
其实你完全可以按照你延时的思路作消抖的,只是要做成不要原地打转的,将delay(500)换成是一个软件计数器就OK了。
如先做一个变量如unsigned int a,将delay(500)换成:
a++;
if ( a == 500 )
{
   hour++;' [% B5 G2 [) A8 p
   if(hour>=24)
   。。。。。。% T3 A# J9 y& e
};
如果感觉还是太快,可以将a再加大一些。
回复

使用道具 举报

发表于 2012-8-6 22:55 | 显示全部楼层
路过看看
回复

使用道具 举报

发表于 2012-8-6 23:11 | 显示全部楼层
11楼正解
回复

使用道具 举报

发表于 2012-8-9 22:27 | 显示全部楼层
中断设置下标志位好了 ,越短越好。显示按键不要放中断为好。状态机思想不错,系统的实时性非常'重要。
回复

使用道具 举报

发表于 2012-8-10 07:36 | 显示全部楼层
如果用中断的方式来判断按键的话,最好用硬件的方式防抖。
如果用扫描的方式判断按键的话,你的延时可调用显示程序啊,这个防抖绝对没问题,但是如果显示程序太长的话,可能按键灵敏度会差些。
回复

使用道具 举报

发表于 2012-12-2 17:17 | 显示全部楼层
本帖最后由 LBQ691477940 于 2012-12-2 17:36 编辑

我认为中断函数太长是不好,但楼主程序中的问题其实根本就不关中断函数里面有无延时函数的事,中断里面用延时好像也不会死呀?以下是我写的程序两个中断都用了,功能为按下后给串口分别返回不同的一个值,带颜色部分的语句可以有效保证中断一次只响应一次。在实际使用中暂未发现有多次触发的问题。
/****************************************************************
按P3.2口开关时产生外部中断同时由串口输出 01
按P3.3口开关时产生外部中断同时由串口输出 02
晶振:11.0592_22.1184MHZ   波特率57600

程序设计:lbq691477940                        21-03-2012        
/****************************************************************/
#include<AT89X52.h>
#define uchar unsigned char
#define uint unsigned int
void delay_1ms(uint x);//1MS延时
bit key0 = 0;
bit key1 = 0;
/****************************************************************/
void main()
{
        SP = 0X60;            //堆栈指针
        TMOD = 0x21;        //设置定时器1为模式2;定时器0为模式1         
        TH1 = 0xff;            //装初值设定波特率//22.1184MHZ=57600
        TL1 = TH1;            //19200=0xfd
        PCON = 0x80;        //波特率加倍
                                   //若为PCON = 0x80波特率加倍(11.0592MHZ = 57600)
        TR1 = 1;              //启动定时器                SM0  SM1
        SM0 = 0;           //串口通信模式设置         0          0 = 0
        SM1 = 1;                                  //         0          1 = 1
                                                      //          1          0 = 2
                                                      //          1          1 = 3
        SM1 = 1;
        EX0 = 1;                //使能外部中断0中断
        IT0 = 1;                //设为下降沿触发方式
        EX1 = 1;                //使能外部中断1中断
        IT1 = 1;                //设为下降沿触发方式
        //ES=1;                        //开串中断
        EA = 1;                        //开总中断        
        while(1)
        {
                if(P3_2)                //如果P3.2口的开关已放开
                        key0 = 0;        //将KEY0置0,目的使下次中断生效
                if(P3_3)                //如果P3.3口的开关已放开
                        key1 = 0;        //将KEY1置0,目的使下次中断生效

        }
}
/****************************************************************/
//向串口发送一个字符
void send_char_com(uchar ch)  
{
    EA = 0;                        //开总中断        
        SBUF = ch;
    while(!TI);                //如果TI为0等待
    TI = 0;
        EA = 1;                        //开总中断        
}
/****************************************************************/
//外部中断0子函数
void int_0 () interrupt 0 //using 0
{
        EX0 = 0;                                        //暂停外部中断0中断
        delay_1ms(5);                                //稍作延时
        if((P3_2 == 0)&&(!key0))        //中断进来后如果P3.2和key0都为0
        {        
                send_char_com(0x01);        //向串口发 01
                key0 = 1;                                //将key0置1防止按一次产生多次的效果
        }
        EX0 = 1;                                        //使能外部中断0中断
}
/****************************************************************/
//外部中断1子函数
void int_1 () interrupt 2 //using 2
{
        EX1 = 0;                                        //暂停外部中断1中断
        delay_1ms(5);                                //稍作延时
        if((P3_3 == 0)&&(!key1))        //中断进来后如果P3.3和key1都为0
        {        
                send_char_com(0x02);
                key1 = 1;                                //将key1置1防止按一次产生多次的效果
        }
        EX1 = 1;                                        //使能外部中断1中断
}
/****************************************************************/
/*22.1184MHZ时 = 1.0026MS为单位的延时程序*/
void delay_1ms(uint x)
{
        uchar j;
        while(x--)
        {
                for(j = 0;j < 227;j++)
                {;}
        }   
}
/****************************************************************/
回复

使用道具 举报

发表于 2012-12-7 19:43 | 显示全部楼层
按键做弹起检测就不会抖动了
回复

使用道具 举报

本版积分规则

QQ|一淘宝店|手机版|商店|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2025-8-19 03:32 , Processed in 0.033478 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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