微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 一个简单的按键去抖延时程序

一个简单的按键去抖延时程序

时间:11-30 来源:互联网 点击:
按键去抖,一般采用普通延时,如

if((GPIOC->IDR & 0x01)== 0)
{
delay_ms(20);
if(GPIOC->IDR & 0x01)== 0

//进行按键处理函数

}

这个程序,需要有一个普通的延时程序,来检测去抖动,这个延时一般采用for循环和while循环。这样的话,就有一个问题,在延时的这20ms中,cpu一直在判断时间有没有到。如果不是中断,是不会打断cpu的程序的。这样的话,去抖延时,就会浪费cpu的效率。
假如,按键扫描的后面跟一个协议处理的函数。
即:

while(1)

scan_key(); //按键扫描
exe(); //协议解析

这个时候,若接收中断,在按键扫描时已经处理完成,正好按下按键,这个时候就必须要有20ms的间隔,在判断完按键后,才可以进入协议解析函数。也就是说,如果没有扫描函数,协议会立即执行解析并返回响应数据。而添加按键扫描后,协议有可能会在20ms后,进行解析并返回数据,这样的话,就会使产品的实时性无法保证。

所以我想了另一个方法,采用标致位,来实现延时,当然这个方法,肯定不是我第一个想出来的。如有雷同,可采用翻钢镚方法进行选择。
就是采用if语句来实现延时,只不过写程序时比较麻烦,但稳定性在stm8上测试了一下,感觉还可以。

代码如下
首先申请几个全局变量
unsigned int time_ms,time_us,time_ns,time_flag;
//以上这几个是定时标志和定时计数变量
unsigned key_old, key_new;
//这两个是按键键值

/*******************************************************************************
函数名:delay_ms()
函数功能:延时
参数:ms 毫秒
返回:无
备注:此延时函数采用if实现,使用时,必须先申请flag变量然后调用延时函数,最后在
执行中加入flag判断
例:u16 time_flag,time_ms,time_us,time_ns;
delay_ms(u16 ms);
if(time_flag>0){time_flag=0;......内容}
*******************************************************************************/
void key_delay(unsigned int ms)
{
if(time_ms{
if(time_us<10) //在应用时,不同的单片机,不同的频率,需要进行调整
{
if(time_ns<8) //在应用时不同的单片机,不同的频率,需要进行调整
{
time_ns++;
}
else
{
time_us++;
time_ns=0;
}
}
else
{
time_ms++;
time_us=0;
}
}
else
{
time_flag=1;
time_ms=0;
}
}

以上代码,有一个time_flag,变量,这个变量就是定时标致变量。一旦这个标致置一,则说明定时器到时间
使用时可以

///////////////////////////////////////////////////////////
//函数名:scan()
//功能:按键扫描
//参数:无
//返回值:无
//备注:
///////////////////////////////////////////////////////////
void scan()
{
u8 key_new;
key_new = GPIOC->IDR;
if(key_old != key_new)
{
key_delay(150);
if(time_flag == 1)
{
time_flag = 0;
if(key_old != key_new)
{
switch()
{
case 1: k1_exe(); break;
case 2: k2_exe(); break;
case 3: k3_exe(); break;
case 4: k4_exe(); break;
default: break;
}
key_old = key_new;
}
else

time_ms=0;

}
}
}

以上就是代码
在大循环中,直接调用即可,和普通的按键函数一样,只不过,这个的实时性,应该相对较高一些。
while(1)

scan_key(); //按键扫描
exe(); //协议解析

让我们来分析一下,为啥这个函数相对较好一些。
首先,我们来看
scan_key();
首先,扫描IO端口,存放如新按键变量
key_new = GPIOC->IDR;
然后将新按键与老按键号进行对比,如果新的按键号与老按键号不同,说明有按钮按下。
if(key_old != key_new)
当有按钮按下的时候进入,延时函数,
key_delay(150);
这时,进入多个if判断,进行time_ns++;这个函数,最主要的功能就是判断,当前的时间time_ms,与参数时间,是否一致,若不一致,则退出函数。这时time_flag不为1,当前的时间time_ms,与参数时间一致 ,这时time_flag为1。
if(time_flag == 1)
这个判断就是判断到时标致,如果到时,则说明去抖时间完成,则在判断一次if(key_old != key_new),如果为否,则说明按键确实按下,否则则为没有按下。有按键按下时,则会执行按键处理函数。
若没有按键按下,则清楚计数器。程序继续执行。
也就是说,不管是否在延时状态,程序,都会向下执行,而不会卡在某一个函数或循环内不动。这样的话,程序就会向下继续执行。
在程序中,若既有按键,又有一些对待实时性较高,但又不乐意放在中断里的程序。可以采用这种方法来实现按键延时,可以相对的提高程序的运行效率。目前这个程序,不支持长按,但可以实现简单的组合按键。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top