单片机/MCU论坛
直播中

朱海生

12年用户 711经验值
擅长:模拟技术 EDA/IC设计 控制/MCU
私信 关注
[讨论]

一种基于定时中断的按键检测程序 (发烧友首发)

本帖最后由 3htech 于 2012-12-4 21:46 编辑

我的小组
https://bbs.elecfans.com/forum.p ... on=list&fid=343

一种基于定时器的按键检测程序
By—3htech
该程序产生的背景
    话说2012年,小白菜要做一个三相电压电流组合表,这个仪表需要进行数据输入(小白菜以前的项目也有输入,但是小白菜没有仔细的研究过),并且给出的时间很长,小白菜有时间来做一些“研究处理”。拿着以前写的按键检测程序,感觉漏洞百出,于是想着趁着有时间把这部分做出来,于是便用了一个星期(实际是5天,双休思密达)专门写了这部分程序。
小白菜的应用需求
小白菜的仪表仅需要单短击(简称单击)和单长击(简称长击),单短击要在按键松开后才进行识别,单长击要在达到设定的时间阀值时进行识别(这时按键未松开)。
不需要考虑的情况如下,不需要连击(可以做为多次短击)、不需要多键同时击、暂时不需要考虑输入数字时长按某键,数字快速自加或自减。
该检测程序要满目不依赖于任何一种单片机,也不依赖按键连接方式,如独立式,矩阵式(当然你要用按键扫描芯片那就……你要用AD式键盘,我……好吧,你赢了~),能够独立存在。

按键过程分析
1 按键小思考
正常的按键过程(不考虑非法的按键状态)如图2.1.1。
键流程--简单.JPG
图2.1.1 正常按键状态示意图
单击和长击只是时间上的区分而已,但是其识别时稍有区别,单击是在按键松开时进行识别的,长击是在按键闭合时进行识别的。见图2.1.2。
键流程--长短.JPG
图2.1.2 长短击按键状态示意图

2 各种可能出现的按键情况
合法情况不再赘述。下面把非法(仅在本应用中非法)的情况列一下。
(1) 人为或干扰引起的单击时间过短(主要为防干扰)。
(2) 单击时间过长(与(1)对应,凡事有短就有长,要有度嘛~)。
(3) 按下了多个键(与我的应用需要相悖,所以非法)。这里有可能是同时按的,也有可能是异步按下的。
(4) 快速多次按同一个键。这种情况可以归结到(1)。
(5) 我觉得没有了,元芳,你怎么看??

回帖(103)

朱海生

2012-11-9 10:38:18
本帖最后由 3htech 于 2012-11-9 23:04 编辑

3 小综合(理综还是文综??)
综合1和2进行考虑,得出以下几条。
(1)    正常的单击和长击示意图。
   按键--短击识别.JPG
               图2.3.1短击识别示意图


按键--长击识别.JPG
                               2.3.2长击识别示意图

(2)    按键时间过短,应丢弃。
按键--时间太短.JPG
图2.3.3按键时间过短示意图

(3)    多键同时按下时,不响应。
按键--同击.JPG    
图2.3.4多键同时按下示意图


(4)    多键异步按下

按键--同击异步.JPG

图2.3.5多键异步按下示意图
这种情况要考虑一下了。如图2.3.5所示。这种情况不会影响到单击。看图2.3.1可知,单击是在按键松开后才进行识别的;但这种情况对长击有影响,如果t1大于长击的阀值,那么键1是否应该识别为一次有效长击呢?这里小白菜认为键1有效,后面的程序也是按键1有效进行的处理。
既然认为有效,那么这个过程可以分解为两个部分,键1闭合到键2闭合这部分认为是一次合法的长击行为,键2闭合以后认为是“多键同时按下”,按出错处理。
(5)    多键“前仆后继”地按下
按键--前仆后继.JPG 图2.3.6
    这里仍然存在(4)中存在的长击问题。这里小白菜依旧认为长击有效。并且不再响应后面的按键。
(6)    按键因为受到干扰而出现了假松开。如图2.3.7中的尖峰所示。
按键--假松开.JPG 图2.3.7
对付这种假松开,小白菜想到的是设定按键松开计时器,只有计时器到一定的值,并且在此期间,读取到的状态都是键松开,才真正认为是键松开。小白菜在最开始的设计时并未考虑到这种情况的出现,是在写本文的时候才考虑到的,所以第一版未对假松开做处理,但在测试时,无论多么复杂错误的按键,程序未出现误动作,也许只有强干扰才能检验了。在本次发布的代码中,小白菜对假松开作了处理,但由于周末,未能测试。请万能的网友们来进行吧,别忘记把结果(最主要的是程序中的BUG)告诉我一声(QQ:1062509507)。
如果按键完全闭合后还口线电平还到达能够识别的高度,那么这个干扰也够强烈的,你说对么,元芳?
    (7) 还有其他错误情况吗,元芳??
1 举报

zhihuizhou

2012-11-9 10:47:44
很期待 mark {:soso__5382138823488878830_1:}
举报

朱海生

2012-11-9 10:48:30
本帖最后由 3htech 于 2012-11-9 23:12 编辑

“伪状态”的抽象
为什么要加上“伪”字呢,因为小白菜对于状态机这个东西,认识的不够清楚,为了避免老鸟们的拍砖,加上伪字。嘎嘎~
根据第二部分,小白菜大致能抽象出一些东西了。
1 确定所使用的变量
(1) 首先要有一个按键状态是否正确合法的标志 KeyErrFlg。
(2) 按键时长计时器KeyTimer。用这个变量来确定键按下了多长时间。
单击时间范围 TS < t < TL 。这里Ts代表短按最短时间,TL 代表长按最短时间。
长击时间范围 t ≥ TL 。
(3) 为了防止第二部分图2.3.6【多键“前仆后继”地按下】这种情况的出现,小白菜自以为是的增加了两个变量,当前按键值KeyCurrent和上次按键值KeyLast。通过两个变量的比较来防止二(5)的出现。
(4) 键松开计时器KeyOffTimer。
设置本变量主要是为了防止图2.3.7【假松开】情况的出现。KeyOffTimer必须大于某个值才算完全松开。
这里为何不不对键按下时做处理呢(出现假按下的情况)?因为假按下的延续时间比较短,达不到我们所设置的Ts时间,所以可以忽略。如果假按下的时间超过了Ts,让你来处理的话,你还认为是假按下?
(5) 键值寄存器 KeyValue和KeyReg,用户可以直接查询变量KeyValue,最重要的是不需要用户清零;而KeyReg则由检测程序和键值读取函数使用,用户不可使用
2 所有可能的情况
KeyErrFlg          TRUE = 无错误,ERR = 有错误。
KeyCurrentKeyLastNULL = 本次无键按下,OK = 键值合法,ERR = 键值非法。
KeyErrFlg
KeyCurrent
KeyLast
此时的操作
合法性
TRUE
NULL
NULL
无键按下或完全松开
OK
按键刚松开
ERR
防错处理
×
TRUE
OK
NULL
键刚按下
OK
(KeyCurrent相等)键正在按下
OK
(KeyCurrent不等) (5)
×
ERR
情况太多
×
TRUE
ERR
忽略
错误按键
×
ERR
NULL
忽略
错误按键松开
×
OK
  
/  ERR
忽略
错误按键未松开
×
3 “伪”状态转换图

状态转换图.JPG

图3.3.1状态转换图

为了在一张图上能画的下,这里面把Key都省略了。图中的粗线是正常按键时的状态转换。
举报

朱海生

2012-11-9 10:50:05
本帖最后由 3htech 于 2012-11-10 01:49 编辑

4 程序传统流程图
这里面需要注意一点,在长按键的识别时,有两种方法,一是检查KeyTimer == TL 这样可以保证只识别一次,二是检查KeyTimer >= TL 然后把KeyErrFlg置为Err,这样可以转换其状态,另其不再识别按键。第一种方法的好处是清晰明了,但是却仅检查了TL 这一个点,小白菜很担心,也许你会说,正常运行时没问题,但是,我就怕不正常运行;基于安全的考虑,小白菜选用了方法二。
传统流程图.JPG


3.4.1传统流程图

代码编写(略)
举报

朱海生

2012-11-9 10:51:40
本帖最后由 3htech 于 2012-11-10 01:50 编辑

应用说明
说了半天,还没有中断的事。下面说一下,同学们,注意听哈。
1 while(1)式检测和中断式检测的对比
(1) 在网上也看过一些人发的按键检测,自己以前也写过按键检测,但是无论这些检测程序多么美妙,绝大部分是在while(1)里执行按键检测程序(先管它叫while(1)式吧),这其实有一个很大的隐患。
当MCU负担不重时,while(1)式检测程序也许能好好的工作,这是由于while(1)的平均执行时间(不是最大执行时间)与按键检测程序的最长调用间隔时间相差无几或更小。但当MCU负担很重时,while(1)式反应就会明显变慢,甚至会丢失按键信息;这是由于while(1)的平均执行时间过大所造成的。举个极端例子,while(1)平均执行时间为1000ms,短按时间为300ms,显然按键检测程序会丢失按键信息。
一句话总结while(1)式的按键检测程序:时间不可控,耗时长,易丢失信息。
(2) 下面说一下在定时中断服务函数中进行按键检测(管它叫中断式吧)的优缺点。
首先说缺点:
由于是在中断中执行检测程序,增加的中断执行时间。但由于仅仅是几个【字节变量】的大小判断,所以耗时很短,小白菜曾在自己所用的平台上测试过,不超过50us,对,没错,就是50us不是50ms,而我的中断时间是10ms对其的影响小于5‰。
下面说一下优点。
优点一:中断式检测的调用时间是可预测,是可控的。中断的发生和while(1)的执行可以看成是并行的(老鸟不要拍砖啊),这显然为按键检测程序按我们设定的间隔执行。
优点二:几乎每个系统中都会出现定时中断(这里不用RTOS,因为小白菜不懂RTOS,只会裸了个奔),并且小白菜接触到的系统都是以10ms,20ms左右这样的定时中断。
优点三:一但把按键检测程序放在中断处理函数中执行,那我们就不需要再考虑之了,只需要在需要使用按键值的地方(比如菜单)调用一个获取键值函数就可以了,而获取键值函数也仅仅是把一个变量的值返回。
优点四:巧妙的躲过了抖动区。小白菜的系统中用的10ms中断。如图5.1.1所示。
抖动说明.JPG
图5.1.1 抖动区示意图
大家知道单片机IO对高低电平识别是有范围的,如图5.1.1中所示,所以,虽然aa’、dd’段存在抖动,但是这一段的电平仍然在“松开”范围内,同理,bb’、cc’段的电平仍在“闭合”的范围内。实际中肯定有ab段时长大于a’b’段时长。而我们真正要躲避的是a’b’c’d’段,这才是真正的抖动区,因为其处于单片机不能识别的电平范围。
一般地,抖动区在10ms左右(我是听说的,这个我真没测试过),而我的中断时间是10ms,由图5.1.1可以,正好可以完美地跨过ab段和cd段,同要也跨过了a’b’和c’d’,从而实现了利用中断间隔达到普通延时去抖动的目的。
小白在实验定时间隔时发现,10-20ms的定时时间对按键响应比较好。中断时间过短,会因中断太频繁而降低系统性能;中断时间过长又不能及时地响应短按键。万能的亲们,你们自己试试吧。
举报

朱海生

2012-11-9 10:52:45
本帖最后由 3htech 于 2012-11-10 01:51 编辑

2 函数说明,首先申明,发布的代码未测试过,也未编译过!
下周一(2012-11-12)发布测试版本。
(1)  externvoid App_Init_Key(void);按键检测初始化函数。必须在中断服务程序执行前调用,使变量一个合法的初始值开始运行,以防止因为变量随机值而出现误动作的情况!!!
(2)  externvoid App_Detect_Key(void); 核心函数,好吧,直接放到定时中断服务程序中就行了。不需要做什么工作。
(3)  externuint8 App_Get_Key_Value(void);读取按键函数。返回值是当前的键值,一定要在使用键值前先调用本函数,否则会出现严重的错误!在一个循环中本函数只能调用一次,请看一下本函数的设计,你会明白为什么。
3 简单的应用举例
主函数中
void main(void)
{
    uint8 u8Key;
App_Init_Key();    //初始化按键
xxx();//初始化定时器
while(1)
{
    u8Key = App_Get_Key_Value();  // 读取键值
    if(KEY_NULL == u8Key)
       {// 什么都不做
     }
   else if(xxxx1)
   { // 处理1
   }
}
}
中断ISR
Tn_ISR()
{
    App_Detect_Key();
}
联系小白菜? QQ = 1062509507
END
举报

zhihuizhou

2012-11-9 10:59:25
我把我的删除了给你? 哈哈
举报

张三

2012-11-9 11:08:41
不知道你们在干嘛!感觉有点欠***,呵呵
举报

lstcspring

2012-11-9 20:31:20
什么情况?{:soso_e132:}
举报

朱海生

2012-11-9 23:20:10
本帖最后由 3htech 于 2012-11-12 14:17 编辑

你如果耐心的看到了这里,那么恭喜你,可以无限制地下载了。
举报

朱海生

2012-11-11 13:34:05
大侠们,尽情的拍砖吧。
看看这个东西有存在的意义么?

如果有,里面是否还有不足之外?
举报

朱海生

2012-11-12 14:17:56
终于完工了。嘎嘎
举报

朱靖

2012-11-12 14:28:01
谢谢
举报

zhihuizhou

2012-11-12 16:00:34
我以为骗人的 真的有耶
举报

朱海生

2012-11-12 16:16:12
引用: zhihuizhou 发表于 2012-11-12 16:00
我以为骗人的 真的有耶

切……{:soso__11824716995429377336_2:}
举报

一台塔吊

2012-11-15 08:56:29
LZ会画流程图……厉害
举报

傻少子

2012-11-15 11:09:20
看哈咯
举报

1653281587.026900

2012-11-15 23:04:48
举报

1653206499.860500

2012-11-16 00:00:36
来看看 不错哦
举报

更多回帖

发帖
×
20
完善资料,
赚取积分