xiaojia234 发表于 2009-7-28 17:19

同意34楼

其实一次按键多次执行是很头痛的, 这就需要延时处理事件,而且采用释放检测处理事件效果更好,个人觉得。

冷漠 发表于 2009-7-28 18:14

回38楼古道热肠版主

38楼:“&nbsp;瞬间的干扰是存在.&nbsp;”<br /><br />************************************************************<br />我请问:版主可以做这样一个实验验证一下:把一个按键接在51外部中断管脚INT0上,写一个简单中断程序,示意代码如下:<br /><br />static&nbsp;char&nbsp;&nbsp;count=0;<br /><br />count++;&nbsp;&nbsp;&nbsp;//或者P1=count++;&nbsp;&nbsp;P1接8个LED指示灯<br /><br />把这个实验装置放在噪声环境下,不按任何键,通电运行一天,看看count显示几?(我做过了。结论:count4小时无任何变化。也就是说INT0中断一次也没有发生。)<br /><br />按照古道热肠的论点,此现象不好解释了,“瞬间的干扰”的影响到哪里去了?难道只有按键时刻才会出现“瞬间干扰”?难道中断INT0随机受瞬间干扰,经常不断地、无效地打断正常运行的主程序?这种系统硬件设计太差劲了吧。<br /><br />“现在很多MCU已在硬件上采取了施密特触发输入和短脉冲丢失的不响应的设计,但软件消干扰措施还是有必要的.”<br /><br />硬件上的冗余是为了消抖,使按键输入为理想波形。而软件上的延时是为了应对按键的机械抖动特性。假定按键是一个电子按键,显然是不需要程序消抖处理的。但是按照版主的观点:“瞬间的干扰总是存在的。”&nbsp;所以“无论外部管脚上的什么输入,(不仅限于键盘)都要经过软件消干扰措施处理。”<br /><br />软件消抖在一种条件下是必要的:就是当按键动作所触发的关联程序运行的时间开销小于按键的抖动时间时,这是通常的情况,因为很少有什么程序运行开销会大于10ms。所以教材上这么教学生,道理嘛,自己去琢磨。<br />&nbsp;<br />&nbsp;<br />

冷漠 发表于 2009-7-28 18:44

41楼讲到了问题实质。

真正能这么理解的人很少。<br /><br />其实消抖处理,更重要的是检测区分按键释放,——是虚假抖动还是真实释放。<br /><br />而当第一次检测到按键按下时,肯定可以认为是真实“按下”信号,并立即触发关联程序。因为一个处于高电平释放状态的按键,根本不可能受到“干扰”而出现虚假信号。<br /><br />看下面一段示意代码:<br /><br />bit&nbsp;key_flag=0;<br /><br />if(&nbsp;(!key)&nbsp;&&&nbsp;(!key_flag)&nbsp;)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;键按下检测,第一次检测到有效,立即执行。<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;运行关联程序;<br /><br />&nbsp;&nbsp;&nbsp;key_flag=1;<br />}<br /><br />delay(500ms);&nbsp;&nbsp;//延时放在按键关联程序执行完毕之后。<br /><br />if(&nbsp;key&nbsp;&&&nbsp;key_flag&nbsp;)&nbsp;&nbsp;&nbsp;//&nbsp;键释放检测<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;按键释放时关联程序;<br /><br />&nbsp;&nbsp;&nbsp;key_flag=0;<br />}<br /><br />delay(500ms);&nbsp;&nbsp;//&nbsp;示意性。实际应用中是运行其他程序。

ayb_ice 发表于 2009-7-28 20:25

按键可有**了,能体现一个人的编程水平

能够不调用延时搞定按键也算入门了.<br />消抖的本质是降低灵敏度,提高可靠性.<br />产品中按键功能的人性化也是很能体现水平的...

长沙卖菜王 发表于 2009-7-28 22:45

求楼主答案

&nbsp;戒指320&nbsp;如果你的按键坏了,或者客户人为的按着一个按键不动(实际中很正常),又怎么处理呢!(本人发现空调的遥控器,在一个按键按着不动的情况下,其它按键就不能用,要不你试试!)&nbsp;&nbsp;急求答案!&nbsp;&nbsp;本人觉得你说的那个高干扰环境下&nbsp;&nbsp;它可得罪的是整个系统,为什么单独要按键出头!而不从整体出发考虑?

沈洁 发表于 2009-7-28 22:54

确实很有建设性,这个帖子我要保存

戒指320 发表于 2009-7-28 23:10

回复45楼

你说的这个遥控器问题是指&nbsp;hs5104做的遥控吗?<br />如果是的话,那么这样的反应是对的。因为hs5104在多个键同时按下的情况下是不发码的。<br />如果是自己用单片机写的发码程序,这个问题可以在检测按键时解决。<br />如果客户按着一个键不放,又怎么处理的问题,那要看客户是怎么个要求了。<br />另外&nbsp;就算按着一个键不放的话,根本不会影响对其他按键的检测啊。

chen_sf 发表于 2009-7-29 00:12

呵呵,各位新按键是没有问题,几千次后你的产品不消抖会

highgear 发表于 2009-7-29 00:47

顶戒指320

可以肯定是原创,虽然戒指320的发现已经是老生常谈。鄙视冷漠34楼的发言。为什么总是把技术问题变成人身攻击呢?真是本性不改。<br /><br />1)“也就是说INT0中断一次也没有发生“,典型的呆板书生做法,一个具有丰富经验的产品设计工程师决不会说这样的话。把这样的产品作1万个分发给1万个客户使用,总会有几个客户会报告异常。<br /><br />2)消抖的目的在于保证可靠的检测,显然,“经过软件消干扰措施处理“肯定比“不经过软件消干扰措施处理“更可靠。<br /><br />3)消抖的策略:<br /> --延时检测避开抖动是非常简单的方法,循环延时还是定时中断延时只是软件处理方法的不同,不值得小题大做。<br /> --另一种是seal&nbsp;in,&nbsp;就是说重触发时延,软件或硬件延时计时器不断的被有效电平复位,计时器timeout则检测结束。这种方法通常用于高速输入。<br />

原野之狼 发表于 2009-7-29 01:01

。。。

<a href="http://space.**/Upload/Blog/2008/1/4/521dfa08-5650-448d-b123-068e76203ec4.pdf" target=_blank>http://space.**/Upload/Blog/2008/1/4/521dfa08-5650-448d-b123-068e76203ec4.pdf</a>

badbird1234 发表于 2009-7-29 07:20

呵呵

现在出的书一般都是时基了<br />一般按键我用两种办法去处理<br />一个就是你们的那个时基<br />还有一种思想差不多就是把延时时间分割成小时间分段去延时

戒指320 发表于 2009-7-29 19:04

谢谢49楼

谢谢49楼的支持<br />同时&nbsp;我也学习了!

lyxq 发表于 2009-7-30 11:09

定时扫描键盘

我做的程序,送给大家。本人从不用软件延时,只用定时器,根据程序量决定定时器周期,如果所有程序在10ms时间内都能处理完毕,则程序扫描周期10ms,否则20ms1.(液晶刷新部分除外,因为液晶刷新在单片机来说不是实时的)<br />//=================================================================================<br />//文&nbsp;件&nbsp;名&nbsp;:&nbsp;read_key()<br />//功&nbsp;&nbsp;&nbsp;&nbsp;能&nbsp;:&nbsp;读键值,&nbsp;利用定时器产生的&nbsp;10&nbsp;毫秒进行键盘去抖,连续40毫秒的的按键为有效<br />//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;按键,&nbsp;对该键做键值译码.&nbsp;有效键值为非零值<br />//寄&nbsp;存&nbsp;器&nbsp;:&nbsp;key_last&nbsp;----&nbsp;上个周期读到的键值,&nbsp;全局变量<br />//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;key_code&nbsp;----&nbsp;读到的有效键码,&nbsp;全局变量<br />//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keyshake&nbsp;----&nbsp;键盘去抖<br />//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lkey_time&nbsp;---&nbsp;首次检测连续按键时间=800ms,&nbsp;0.8秒后按键没有抬起,0.1秒<br />//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;更新一次键值<br />//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long_key_flag;是否检测连续按键标识<br />//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wait_esc_flag&nbsp;---&nbsp;等待键盘抬起标志,&nbsp;全局变量<br />//输&nbsp;&nbsp;&nbsp;&nbsp;出&nbsp;:&nbsp;key_code&nbsp;---&nbsp;读到的有效键码,&nbsp;为非零值,全局变量<br />//=================================================================================<br />//<br />void&nbsp;read_key()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;uchar&nbsp;i;<br />&nbsp;&nbsp;&nbsp;&nbsp;keyshake&lt&lt=1;&nbsp;keyshake&=0X0F;<br />&nbsp;&nbsp;&nbsp;&nbsp;key_data=keyboard_port;<br />&nbsp;&nbsp;&nbsp;&nbsp;i=key_data&0x3f;<br />&nbsp;&nbsp;&nbsp;&nbsp;if(i!=key_last){key_last=i;long_key_flag=0;lkey_time=80;return;}&nbsp;//抖动状态<br />&nbsp;&nbsp;&nbsp;&nbsp;keyshake|=1;<br />&nbsp;&nbsp;&nbsp;&nbsp;if(keyshake==0x0f)<br />&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;if(i==0x3f)&nbsp;&nbsp;//无键按下,退出<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;wait_esc_flag=0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long_key_flag=0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lkey_time=80;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep_min=0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!lcd_light&&!wait_esc_flag)//背光原来是关闭的,启动背光然后退出<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;wait_esc_flag=1;&nbsp;lcd_light=1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(wait_esc_flag)&nbsp;//已有键按下,检查重复按键或等待键抬起<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;if(long_key_flag)&nbsp;&nbsp;//等待重复按键<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;if(--lkey_time==0)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;lkey_time=10;&nbsp;keyp_flag=1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(i==0x37)key_code=3;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//连续加<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(i==0x1f)key_code=4;&nbsp;&nbsp;&nbsp;//连续减<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;{lkey_time=80;keyp_flag=0;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;//首次检测到按键<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;buzzer=0;&nbsp;buz_time=12;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keyp_flag=1;wait_esc_flag=1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(i==0x3d)key_code=1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//上<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(i==0x2f)key_code=2;&nbsp;&nbsp;//下<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(i==0x37)key_code=3;&nbsp;&nbsp;//左<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(i==0x1f)key_code=4;&nbsp;&nbsp;//右<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(i==0x3e)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ECS<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;if(lcd_light&&(main_menu_code==0))//背光原来是开的,关背光然后退出<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;lcd_light=0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keyp_flag=0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;key_code=5;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//有效按键<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(i==0x3b)key_code=6;&nbsp;&nbsp;//ENTER<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;keyp_flag=0;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}

caoyannay 发表于 2009-7-30 11:40

做个标记

做个标记,继续

5761193jia 发表于 2009-7-30 17:39

用状态机

用状态机的思路来处理!

qiuming 发表于 2009-7-30 22:10

书上只是一个方法吧,

书上只是一个方法吧,带你入门而以,实战中看你的安排吧,分时也可以的,交换机好象就是这样。

zyboy 发表于 2009-7-31 00:08

0点打酱油!

干扰无处不在,做个静电实验估计都会有问题,太不严谨了,42楼

yuands 发表于 2009-7-31 08:40

在中断中查询按键我很早就想过

教科书上只是教会你一个思想而已,它是单个程序只是举个例子,并不代表这种按键检测方法是最好的,最高效的。具体实按键检测有很多方法。<br /><br />实际使用中几乎没有人会用教科书上那种延时检测,除非单片机这个时候确实没有什么其它的事情做。

qiao1102 发表于 2009-7-31 14:57

定时扫描!!!

贺信 发表于 2009-7-31 15:24

板等
页: 1 2 [3] 4 5 6 7
查看完整版本: 按键可有**了,能体现一个人的编程水平