搜索
bottom↓
回复: 52

请教高手:外部按键中断中怎样实现去抖?

[复制链接]

出0入0汤圆

发表于 2005-11-15 10:50:10 | 显示全部楼层 |阅读模式
请教高手:外部按键中断中怎样实现去抖?

出0入0汤圆

发表于 2005-11-15 10:54:40 | 显示全部楼层
在中断服务程序里面加一条数百毫秒的延时程序

出0入0汤圆

发表于 2005-11-15 11:06:59 | 显示全部楼层
中断肯定不能加延时。别上当

出0入0汤圆

发表于 2005-11-15 11:34:53 | 显示全部楼层
为什么不能?我就是用这个方法去抖动的,在实际使用中并没有错呀,双龙的很多入门实例也是用延时去抖动的

出0入0汤圆

发表于 2005-11-15 11:39:41 | 显示全部楼层
中断时间很宝贵,不能有任何延时,只能在里面设置N多的标志位,出中断处理所有需要响应的程序。



按键去抖,我的做法是:

1、响应按键中断后做一个按键开始的标志位,并开始定时器。

2、在定时器20ms后判断按键还存在不,再过20ms后再判断,如果都有按键,说明是真的有按键。

3、关闭定时器,清按键开始标志位,并执行按键程序。

出0入0汤圆

发表于 2005-11-15 11:47:19 | 显示全部楼层
按键的问题,建议到马老师专栏中去看看。

其中的第九章内容很实用的。

<<按键输入接口设计>>

出0入0汤圆

发表于 2005-11-15 12:01:49 | 显示全部楼层
没有错,有些中断的确很紧急,延时去抖动并不是所有地方都可以用的,不过如果要用延时的话一般把延时放在中断服务程序的最后位置,这样就不会影响中断的快速响应了,总之要看场合使用,如果程序的其它地方用过延时函数,那么再次用延时函数时只会增加几个字节的代码(BASCOM多6个字节),4楼的思路很好,我以前没有想过

出0入0汤圆

发表于 2005-11-15 16:19:34 | 显示全部楼层
如果只是实验的话,可以用软件延时的方式,这样简单。

如如是真正的产品,实时性要求都很高,就不能用延时了,因为这样其它的中断就不能处理了。用在中断中设标志的方法很好,我赞成这种方法。

出0入0汤圆

发表于 2005-11-15 17:27:52 | 显示全部楼层
#define KEY_INPUT_ADDR1   0x2000

#define KEY_INPUT_ADDR2   0x6000



#define        ANTI_SHAKE_TIMES                        1                                                //per 50ms

#define        REPEAT_DELAY_TIMES                        20                                                //per 50ms

#define        REPEAT_BETWEEN_TIMES                REPEAT_DELAY_TIMES-3        //per 50ms



#define KEY_MASK                                        0x00E0

#define        NO_KEY_PRESS_CODE                        0xFFFF



bit bdata bKeyEvent;

bit bdata bKeyChanged;



INT16U data PreviousKeyCode;                        //Previous Key Code, Read from Port, Before Anti-Shake

INT16U data PreviousKeyValue;                        //Previous Key Value After Anti-Shake

INT16U data CurrentKeyValue;                        //Current Key Value After Anti-Shake

INT8U  data AntiShakeCount;

INT8U  data RepeatCount;



//Initialize Key Variable

void InitKeyVariable ( void )

{

        PreviousKeyCode = NO_KEY_PRESS_CODE;

        PreviousKeyValue = NO_KEY_PRESS_CODE;

        CurrentKeyValue = NO_KEY_PRESS_CODE;

        AntiShakeCount = 0;

        RepeatCount = 0;

        bKeyEvent = 0;

        bKeyChanged = 0;

}

//Read Key Code

void ReadKey ( void )

{

        INT16U data CurrentKeyCode;                        //Curretn Key Code, Read from Port, Befrore Anti-Shake



        //Get Key Code form Port

        CurrentKeyCode = ( XBYTE[KEY_INPUT_ADDR1] << 8 ) | XBYTE[KEY_INPUT_ADDR2] | KEY_MASK;

        //Anti-Shake Process

        if ( CurrentKeyCode == PreviousKeyCode )

        {

                AntiShakeCount++;

                if ( AntiShakeCount == ANTI_SHAKE_TIMES )

                {

                        AntiShakeCount--;

                        PreviousKeyValue = CurrentKeyValue;

                        CurrentKeyValue = CurrentKeyCode;

                }                       

        }

        else

        {

                PreviousKeyCode = CurrentKeyCode;

                PreviousKeyValue = CurrentKeyValue;

                AntiShakeCount = 0;

        }

        //Creat Key Event

        if ( CurrentKeyValue != NO_KEY_PRESS_CODE )

        {

                if ( PreviousKeyValue != CurrentKeyValue )

                {

                        bKeyChanged = 1;

                        bKeyEvent = 1;

                        RepeatCount = 0;

                }

                else

                {

                        RepeatCount++;

                        if ( RepeatCount == REPEAT_DELAY_TIMES )

                        {

                                bKeyChanged = 0;

                                bKeyEvent = 1;

                                RepeatCount = REPEAT_BETWEEN_TIMES;

                        }

                }

        }

}





写一50ms中断或者主程序运行N周后调用一次ReadKey函数,检测bKeyEvent和bKeyChanged的状态;

bKeyEvent = 1 、bKeyChanged = 1时有新按键按下事件发生,键码在CurrentKeyValue中;bKeyEvent = 1 、bKeyChanged = 0时有按键被持继按下事件发生,键码在CurrentKeyValue中;

注:

CurrentKeyCode = ( XBYTE[KEY_INPUT_ADDR1] << 8 ) | XBYTE[KEY_INPUT_ADDR2] | KEY_MASK;与键盘硬件电路有关,可按实际情况调整。


-----此内容被fatboy于2005-11-15,17:39:14编辑过

出0入0汤圆

发表于 2005-11-15 18:21:28 | 显示全部楼层
买一块7279用岂步省事?<img src=./emotion/em035.gif

出0入0汤圆

发表于 2006-3-10 14:10:59 | 显示全部楼层
//PD0:key1;PD1:key2;

void Key_Press_Scan(void)

{

Press_Keys = 0;

if ( (PIND&0x01) == 0)   

{

  Delay_Ms(50);

  if ((PIND&0x01) == 0)

  {

   Press_Keys = 1;

  }

}

else if ((PIND&0x02) == 0)

{

  Delay_Ms(50);

  if ((PIND&0x02) == 0)

  {

   Press_Keys = 2;

  }

}

}

出0入0汤圆

发表于 2006-5-28 21:24:13 | 显示全部楼层
加个硬件去抖电路不就行了

出0入0汤圆

发表于 2006-5-28 22:01:58 | 显示全部楼层
7219很贵啊

出0入0汤圆

发表于 2006-7-13 14:24:50 | 显示全部楼层
4楼hankw说的方法很好,实现也很简单的。

出0入0汤圆

发表于 2006-7-13 16:33:12 | 显示全部楼层
可以用一个定时器,在中断里面进行几次的确认是否有按键有效,外部中断用拉也是浪费的。况且按键去抖动都会有100ms左右吧,若用15.6ms的定时器中断都可以去抖动好几次了,

出0入0汤圆

发表于 2006-7-14 17:30:27 | 显示全部楼层
用外部中断是为了唤醒深度睡眠的MCU

出0入0汤圆

发表于 2006-7-14 20:55:10 | 显示全部楼层
15楼正解,在中断服务中放延时的确不合适。

出0入0汤圆

发表于 2006-7-14 22:45:42 | 显示全部楼层
去抖真的要用100MS吗?

马老师说10ms就行了。。。。。?

出0入0汤圆

发表于 2006-7-15 00:07:31 | 显示全部楼层
关于按键中断中怎样实现去抖,记得hotpower有出过怪招.....

出0入0汤圆

发表于 2006-8-4 14:55:18 | 显示全部楼层
在中断中延时去抖动是很不实用的方法。如果用在产品中会被人骂死。

在代码中应该避免使用延时的方法,如果在时序上需要延时,应该把CPU时间让出来给别的任务执行,当然,如果你的任务很简单可以在按键的地方傻等,如果你同事有多个任务要做,比如要写EEP,要刷新显示,则可以把想办法把等待的时间利用起来完成其他的任务,以提高系统性能。

在硬件上一般加上一个电容就可以去掉大部分毛刺,再加上软件的操作就可以完成功能了

关于去抖动的时间,则根据应用环境不同而不一样。如果开关的感性比较强,则去抖动的时间就需要长一点,具体可以用示波器看看。一般继电器开关100ms左右,至于一般的按键,如果希望灵敏一点,则10ms就够了,如果要稳定一点,则40ms差不多,这个根据产品不同而有差异

出0入0汤圆

发表于 2006-8-4 19:13:03 | 显示全部楼层
加个小电容

出0入0汤圆

发表于 2006-8-5 01:00:25 | 显示全部楼层
各位说的不错,在中断里应该尽量的少用延时语句,我上面的帖子是错的,sorry



另外

下面的帖子对外部中断按键防抖动有一定的参考作用

http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=623872&bbs_page_no=1&bbs_id=1000

出0入0汤圆

发表于 2006-8-23 18:28:36 | 显示全部楼层
按键去抖问题最好用软件解决,费点神但会节省成本,这是精髓所在。不然说句担杠的话:另用单片机了,你用BJT+R+L+C搭电路吧!

出0入0汤圆

发表于 2007-4-25 09:06:48 | 显示全部楼层
不错!

出0入0汤圆

发表于 2007-4-25 09:17:31 | 显示全部楼层
如果专用一个定时器来处理按键的去抖动实在很浪费了.特别是那种定时1xms产生中断的那种思路.

出0入0汤圆

发表于 2011-9-7 19:05:36 | 显示全部楼层
学习了

出0入0汤圆

发表于 2011-9-7 19:16:25 | 显示全部楼层
设定时间  间断性的取值 做对比!

出0入0汤圆

发表于 2011-9-7 21:58:16 | 显示全部楼层
我自制的小玩样都是软件延时与硬件加小电容结合的,使用过程中没发现什么大问题...可能和我结构功能简单有关吧

出0入0汤圆

发表于 2012-3-2 13:53:01 | 显示全部楼层
Mark

出0入0汤圆

发表于 2012-5-16 09:56:33 | 显示全部楼层
学习了,受教了~~~~~~~~~~~~

出0入0汤圆

发表于 2013-9-14 13:13:13 | 显示全部楼层
假如是 触摸屏 的触摸按键勒

出0入0汤圆

发表于 2013-9-14 13:18:18 | 显示全部楼层
lakefrog 发表于 2006-8-4 19:13
加个小电容

我一般也是这么干的!

出0入0汤圆

发表于 2013-9-15 19:30:19 来自手机 | 显示全部楼层
好文,留石           

出0入0汤圆

发表于 2013-9-15 20:58:04 | 显示全部楼层
Gallen.Zhang 发表于 2013-9-14 13:18
我一般也是这么干的!

那如果向E71那样的手机按键 得加多少个电容啊,哈哈

出0入0汤圆

发表于 2013-9-15 23:57:54 | 显示全部楼层
原来是这样子的,又学习了啊

出0入0汤圆

发表于 2013-9-16 12:46:16 | 显示全部楼层
学习了......

出0入0汤圆

发表于 2013-9-16 13:26:25 | 显示全部楼层
panxiaoyi 发表于 2005-11-15 10:54
在中断服务程序里面加一条数百毫秒的延时程序

数百毫秒,不干别的了?开玩笑吧

出0入0汤圆

发表于 2013-9-16 13:27:30 | 显示全部楼层
hankw 发表于 2005-11-15 11:39
中断时间很宝贵,不能有任何延时,只能在里面设置N多的标志位,出中断处理所有需要响应的程序。



按键去抖 ...

呵呵,三步状态机是吧

出0入0汤圆

发表于 2013-9-16 14:49:32 | 显示全部楼层
跟输入滤波的道理差不多,用定时中断连续采样比较

出0入0汤圆

发表于 2013-11-2 10:27:35 | 显示全部楼层
个人觉得看实际的应用场合,要求高的软件加电容中断中做标记,利用主程序的执行时间去抖最好,要求不高的话在中断里加延时也可以,但要注意像8s这种会嵌套的中断,进去之后先关闭全局中断,退出之前再开,否则会有连续两三次中断的

出0入0汤圆

发表于 2013-11-10 14:14:11 | 显示全部楼层
mark      

出0入0汤圆

发表于 2013-11-10 16:14:54 | 显示全部楼层
闷鱼 发表于 2013-9-14 13:13
假如是 触摸屏 的触摸按键勒

触摸按键跟一般的按键没有什么区别吧···
就用前面说的各种方法都行的

出0入0汤圆

发表于 2013-11-15 20:23:01 | 显示全部楼层
ljcfree 发表于 2013-11-2 10:27
个人觉得看实际的应用场合,要求高的软件加电容中断中做标记,利用主程序的执行时间去抖最好,要求不高的话 ...

关全局中断 这个还得看看 没找到寄存器 stm32f103

出0入0汤圆

发表于 2013-11-15 20:23:19 | 显示全部楼层
woshiqinyikun 发表于 2013-11-10 16:14
触摸按键跟一般的按键没有什么区别吧···
就用前面说的各种方法都行的

液晶屏的触摸

出0入0汤圆

发表于 2013-11-17 22:43:40 | 显示全部楼层
硬件去抖,参考数电。

出0入0汤圆

发表于 2013-12-6 15:58:00 | 显示全部楼层
学习了

出0入0汤圆

发表于 2017-4-9 20:49:40 | 显示全部楼层
hankw 发表于 2005-11-15 11:39
中断时间很宝贵,不能有任何延时,只能在里面设置N多的标志位,出中断处理所有需要响应的程序。



按键去抖 ...

赞,谢谢学习了!!

出0入0汤圆

发表于 2017-4-10 10:19:30 | 显示全部楼层
05年的坟都挖出来了 ORZ

出0入0汤圆

发表于 2017-4-10 16:51:45 | 显示全部楼层
学习一下     

出0入0汤圆

发表于 2017-4-10 17:35:26 | 显示全部楼层
panxiaoyi 发表于 2005-11-15 10:54
在中断服务程序里面加一条数百毫秒的延时程序

不要误导别人,中断中只做标志位的设置,不要做运算。

出0入0汤圆

发表于 2017-4-10 18:13:46 | 显示全部楼层
我去……  居然是10年前的帖子……  谁挖的坟
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-3 22:51

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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