一种相对高效的按键消抖方法

来源:互联网 发布:网络贷被全面叫停政策 编辑:程序博客网 时间:2024/06/06 06:53

按键软件消抖自我接触单片机开始就已经存在这个问题了,网上的办法无非是延时消抖和定时轮询。对于写裸机的我来说这两种方法都不可避免的会有资源浪费掉,今天突然有了灵感,想到了一种相对高效的办法来解决消抖问题。

硬件平台:STM32F103RCT6开发板

开发环境:WIN7-64bit+MDK5+STD库

按键消抖的必要性在此我就不多说了。直接步入正题。

在使用本方法前请注意,本方法需要一个全局时间戳的支持。

第一步:初始化全局时间戳的定时器,一般采用SysTick定时器来产生,每ms一次tick即可。

第二步:初始化按键对应的IO,复用为边沿触发的外部中断。

第三步:在外部中断函数中添加按键事件处理函数。

代码如下:

typedef struct _Key_t{    u32 last_time;    enum    {        May_Press,        Release,    }private_state;    enum    {        No_Press,        Short_Press,        Long_Press,    }state;}Key_t;#define Is_ShortPress_Threshold   1500
简单定义一个按键状态的结构体,用于管理每个按键的状态。顺便再定义一个长短按的识别阈值,用于区分按键的长短按。

if(key_state.private_state==Release)                {    if(KEY==0)    {        key_state.private_state=May_Press;        key_state.last_time=course_ms();    }}else if(key_state.private_state==May_Press){    if(KEY==1)    {        if((course_ms()-key_state.last_time>10)&&(course_ms()-key_state.last_time<Is_ShortPress_Threshold))        {            key_state.state=Short_Press;            key_state.private_state=Release;        }        else if(course_ms()-key_state.last_time>Is_ShortPress_Threshold)        {            key_state.state=Long_Press;            key_state.private_state=Release;        }        else            key_state.private_state=Release;    }}
以上为需要添加到中断处理函数的按键事件处理函数,算法的核心是一个状态机。在本例中,按键被默认上拉,按下接地。course_ms()为获取全局时间戳的函数。

思路解释如下:按键状态结构体有一个用于识别的状态位,默认处于Release,也就是释放的状态。一旦按键被按下,中断触发,此时检查是否是Relase状态,如果是就检查按键是否被拉低,如果是,此时进入May_Press状态,也就是可能是按下的,并且记录此时的时间戳,这一步是消抖的关键。当按键被释放,由于是边沿触发,会再次进行处理,此时检查和上一次触发之间的时间戳之差,如果小于10ms我们就认为是抖动,此时不会对按键输出状态进行修改,而是直接将按键状态置回Relase状态,反之检查差值和长短按阈值之间的关系,将state置位为对应的状态。消抖的核心在于记录时间戳,而这只是一个简单的赋值操作,并不耗费时间。

效率上来说,延时消抖花费时间在无意义延时上,而相对较好的定时轮询还是不可避免的在轮询,而现在这种方式完全是中断性质的。唯一多出的开销(全局时间戳)并不是只可以用于按键消抖,另外在HAL库中存在直接获取tick的函数,这样实现就更方便了。经实际测试,消抖效果可以达到其他两种消抖算法的水平。