【按键】短按,长按,按键释放,三种模式的按键扫描程序(软件消抖动)
2015-10-15 11:23
375 查看
先来说一下这三种模式的意思:
1. 短按模式:单击按键时,返回一次有效按键值;长按时也只返回一次有效按键值。这样可以有效地排除因不小心长按带来的返回多次有效按键,进而执行多次按键处理程序。
2. 长按模式: 单击按键时,返回一次有效按键;长按时,返回多次有效按键值。这样可以很快的调节某个较大的参数,比如时间的时分秒参数。
3. 按键释放模式:这个模式与短按模式是相对的。短按模式只要按键按下去,立即返回有效键值,进而试行按键处理程序;二按键释放模式,却是要等到按下键,释放之后,才会返回有效键值,进而执行按键处理程序。
接下来说一下扫描程序:
1)采用的是轮询的方式(非中断)
2)消抖动的方式:多次扫描,来确定按键值。下面的程序的是设定了5次。主要是根据扫描周期来确定,次数的多少。
注:
扫描周期:从进入按键扫描程序开始,直到到下一次进入按键扫描程序时 结束,之间所用的时间。
下面是整个按键扫描程序的源码,可以读一读,语句都很简单,而且每一句都有注释,一步一步看下去,应该能明白。
如果不明白,可以留言谈论。
以下是 KeyScan.c 文件的内容,
以下是KeyScan.h文件内容
使用注意:
1.作为按键使用的相应IO口,必须设置为输入模式(如果是51单片机的话,无需关心)
2.按键的硬件连接必须是一端接GND,一端接IO口。
下面介绍一下程序的使用方法:
这里以51单片机的 按键点亮和熄灭LED灯作为例子。
硬件:
1)按键使用单片机的P0端口
2)LED灯使用P1.0的IO口,低电平点亮
返回的按键值:
没有键按下, 返回键值是0xFF
如果P0.0按下,返回键值是0xFE
如果P0.1按下,返回键值是0xFD
如果P0.2按下,返回键值是0xFB
如果P0.3按下,返回键值是0xF7
…
如果P0.7按下,返回键值是0x7F
下面是例子的参考源码:
Pillar Peng
2015.5.25 - 18:23
log:
感谢网友“Shiow1984”的提醒,有漏掉和不足的地方,我已经修改。
之前写的文章意在按键程序的思路,就没有将定时扫描程序添加进去,怕影响按键程序的理解,若要稳定地运用于程序中,就要使用定时扫描了,这样按键扫描的时间就可以确定,调节好扫描次数后,几乎就没有什么误触了。
我也在上面的程序中添加了定时扫面程序。
扩展篇:
该方法的矩阵键盘程序
1. 短按模式:单击按键时,返回一次有效按键值;长按时也只返回一次有效按键值。这样可以有效地排除因不小心长按带来的返回多次有效按键,进而执行多次按键处理程序。
2. 长按模式: 单击按键时,返回一次有效按键;长按时,返回多次有效按键值。这样可以很快的调节某个较大的参数,比如时间的时分秒参数。
3. 按键释放模式:这个模式与短按模式是相对的。短按模式只要按键按下去,立即返回有效键值,进而试行按键处理程序;二按键释放模式,却是要等到按下键,释放之后,才会返回有效键值,进而执行按键处理程序。
接下来说一下扫描程序:
1)采用的是轮询的方式(非中断)
2)消抖动的方式:多次扫描,来确定按键值。下面的程序的是设定了5次。主要是根据扫描周期来确定,次数的多少。
注:
扫描周期:从进入按键扫描程序开始,直到到下一次进入按键扫描程序时 结束,之间所用的时间。
下面是整个按键扫描程序的源码,可以读一读,语句都很简单,而且每一句都有注释,一步一步看下去,应该能明白。
如果不明白,可以留言谈论。
以下是 KeyScan.c 文件的内容,
//====================================================== //KeyScan.c //====================================================== //注意:该宏定义,定义在keyscan.h文件中 //#define KEYDEBOUNCE 0x05 //消抖动,按键扫描次数。如果连续5次都是扫描的都是相同键值,则认为是有效键值,否则是误触发 unsigned int g_uiCurrKey; //当前按键值 unsigned int g_uiLastKey; //上次按键值 unsigned int g_uiKeyScanCount; //按键扫描计数,作用:消抖动 unsigned int g_uiPreKeyValue; // 上一次的有效按键值 unsigned int g_uiKeyDown; //键被按下,返回的键值。 作用:单次按键,单次返回有效键值;按住不放,也只返回被按下的一个键值 unsigned int g_uiKeyRelease; //键被释放后,返回的键值。 作用:只有按下的按键被释放后,才返回按下的键值 unsigned int g_uiKeyContinue; //键连续按键,重复返回的键值。 作用:只要按住不放,就会重复地返回相同键值 //P0口的低八位作为按键 //没有按键时,返回的是0xff, void Int_Key_Scan(void) { static unsigned short LastReadKey; //上次从IO口读取的键值 ,注意是静态变量 unsigned short CurrReadKey; //当前从IO口读取的键值 CurrReadKey = P0 & 0x00ff; //获取当前的键值 if(CurrReadKey == LastReadKey) //如果当前读取的键值与上次从IO口读取的键值相同 { if(g_uiKeyScanCount >= KEYDEBOUNCE) //首先判断是否大于等于debounce的设定值(即是,是否大于等于设定的采样次数) { //按住不放,多次响应 g_uiCurrKey = CurrReadKey; //如果是,将当前的读取值判定为有效按键值(如果是,在采样周期中,都是这个值,则判定为有效按键值) g_uiKeyContinue = g_uiCurrKey ; //长按,多次响应 按键值 //按住不放只响应一次 if(g_uiPreKeyValue == g_uiCurrKey) { g_uiKeyDown = 0xff; //没有键值 } else { g_uiKeyDown = g_uiCurrKey; //如果不同,按键有效,(就是第一次有效值时) } //按键释放时,按键值才有效 if(g_uiCurrKey == 0xff) //当有效按键值从非0到0的状态时(即是,从有按键到无按键,表示已经释放了),表示之前按键已经释放了 { g_uiKeyRelease = g_uiPreKeyValue; } g_uiLastKey = g_uiCurrKey; //记录上次有效按键值 } else //如果否,则debounce加一(如果否,则继续采样键值) { g_uiKeyScanCount++; } } else //如果当前读取的键值与上次从IO口读取的键值不同,说明按键已经变化 { g_uiKeyDown = 0xff; //放开按键后第一次进入扫描程序,清零g_uiKeyDown.作用:消除一个BUG(你猜BUG是什么?) g_uiKeyScanCount = 0; //清零之前的按键的debounce计数 LastReadKey = CurrReadKey; //将当前读取的键值记录为上次读取的按键值 } }
以下是KeyScan.h文件内容
//====================================================== //KeyScan.h //====================================================== //宏定义 #define KEYDEBOUNCE 0x05 //消抖动,按键扫描次数。如果连续5次都是扫描的都是相同键值,则认为是有效键值,否则是误触发 //声明变量 extern unsigned int g_uiCurrKey; //当前按键值 extern unsigned int g_uiLastKey; //上次按键值 extern unsigned int g_uiKeyScanCount; //按键扫描计数,作用:消抖动 extern unsigned int g_uiPreKeyValue; //上一次的有效按键值 extern unsigned int g_uiKeyDown; //键被按下,返回的键值。 作用:单次按键,单次返回有效键值;按住不放,也只返回被按下的一个键值 extern unsigned int g_uiKeyRelease; //键被释放后,返回的键值。 作用:只有按下的按键被释放后,才返回按下的键值 extern unsigned int g_uiKeyContinue; //键连续按键,重复返回的键值。 作用:只要按住不放,就会重复地返回相同键值 //函数声明 void Int_Key_Scan(void);
使用注意:
1.作为按键使用的相应IO口,必须设置为输入模式(如果是51单片机的话,无需关心)
2.按键的硬件连接必须是一端接GND,一端接IO口。
下面介绍一下程序的使用方法:
这里以51单片机的 按键点亮和熄灭LED灯作为例子。
硬件:
1)按键使用单片机的P0端口
2)LED灯使用P1.0的IO口,低电平点亮
返回的按键值:
没有键按下, 返回键值是0xFF
如果P0.0按下,返回键值是0xFE
如果P0.1按下,返回键值是0xFD
如果P0.2按下,返回键值是0xFB
如果P0.3按下,返回键值是0xF7
…
如果P0.7按下,返回键值是0x7F
下面是例子的参考源码:
//====================================================== //main.c //====================================================== #include "reg51.h" #include "KeyScan.h" sbit LED = P1.0; //定义LEDIO口 char time_10ms_ok; // 10ms 定时标志 void init_timer0(void) { //定时器的初始化 TMOD = 0x01; //选择定时器的工作模式:定时器0,方式1 TH0 = (65535 - 10000)/256; //定时器的初值 TL0 = (65535 - 10000)%256; EA = 1; //开打总中断使能 ET0 = 1; //打开定时器0 的使能 TR0 = 1; //打开定时器0 ,开始工作 } void main(void) { P0 = 0xff; LED = 0; //点亮LED init_timer0(); //初始化定时器 定时10ms while(1) { if(time_10ms_ok) //这里表示10ms扫描一次 { time_10ms_ok = 0; //清除10ms定时标志 Int_Key_Scan(); //按键扫描程序 } //第一种:KeyDown的使用 //单按时和长按时,都只返回一次有效键值(无需等到按键释放,就可以返回有效键值) switch(g_uiKeyDown) { case 0xFE: //P0.0按键程序 LED = !LED; break; case 0xFD: //P0.1按键程序 //... break; case 0xFB: //P0.2按键程序 //... break; case 0xF7: break; case 0xEF: break; case 0xDF: break; case 0xBF: break; case 0x7F: break; case 0xFF: //没有按键程序 //... break; } //第二种:KeyRelease的使用 //只有当按键释放之后,才返回一次有效键值,即是按键释放后,才执行相应的函数 switch(g_uiKeyRelease) { case 0xFE: //P0.0按键程序 LED = !LED; break; case 0xFD: //P0.1按键程序 //... break; case 0xFB: //P0.2按键程序 //... break; case 0xF7: break; case 0xEF: break; case 0xDF: break; case 0xBF: break; case 0xEF: break; case 0xFF: //没有按键程序 //... break; } //第三种:KeyContinue的使用 //1)单次按键(非长按),返回一次有效值。 //2)长按,返回多次相同有效值 switch(g_uiKeyContinue) { case 0xFE: //P0.0按键程序 LED = !LED; break; case 0xFD: //P0.1按键程序 //... break; case 0xFB: //P0.2按键程序 //... break; case 0xF7: break; case 0xEF: break; case 0xDF: break; case 0xBF: break; case 0xEF: break; case 0xFF: //没有按键程序 //... break; } } } void timer0(void) interrupt 1 //用的是定时器0, 这个“interrupt 1”中的“1”代表1号中断即是定时器0中断。如果是“0”就是外部中断0;“2“=外部中断1;”3“定时器1中断;”4“=串行口中断 { TH0 = (65535 - 10000)/256; TL0 = (65535 - 10000)%256; //定时器0的方式1,得在中断程序中重复初值。 time_10ms_ok = 1; //定时10MS 的标志 }
Pillar Peng
2015.5.25 - 18:23
log:
感谢网友“Shiow1984”的提醒,有漏掉和不足的地方,我已经修改。
之前写的文章意在按键程序的思路,就没有将定时扫描程序添加进去,怕影响按键程序的理解,若要稳定地运用于程序中,就要使用定时扫描了,这样按键扫描的时间就可以确定,调节好扫描次数后,几乎就没有什么误触了。
我也在上面的程序中添加了定时扫面程序。
扩展篇:
该方法的矩阵键盘程序
相关文章推荐
- C#控制键盘按键的常用方法
- javascript 响应键盘特定按键(只响应数字键)
- JavaScript Event学习第十一章 按键的检测
- Python可跨平台实现获取按键的方法
- Python实现windows下模拟按键和鼠标点击的方法
- vbs之sendkey
- 模拟按键
- (一)Qt:键盘输入,两行editline
- iOS&&Swift入门(三)Button/按键
- stm32 CT117E之按键(扫描)
- 键盘ascll码
- 笔者分享:在不同BIOS上如何让U盘启动【mfxp】
- 移植 tiny210 的按键驱动
- Android按键拦截处理最佳实践范例(以Back事件为例)
- button 使用方法一
- 多个Button监听
- Dev gridcontrol 捕获按键事件
- Android事件—单选按键和下拉按键
- Linux输入子系统(4):设备驱动层实例之按键驱动
- 按键驱动的恩恩怨怨之概述