按键扫描是每个搞单片机的都会遇到的问题,也是一个开发人员必须具备的基本功。先从最基本的说起。在此声明,没有代码,也不要向我要代码,也不想穿裤子,如果你看了帖子还写不出代码,那么我只能说你太笨了。。。。。。。。还是那句话,搞开发重要的是思想,而不是代码,代码只是工具
通常的按键扫描程序是这样做的
键盘按下?YES---延时去抖----键盘按下?YES-----确实按下了,按键有效---退出
NO NO
退出 退出
很多教材上都是这样写,但这个程序却是误人子第的
问题来了,这个程序不太好用,有时按一下,或按久一点,程序会认为你按了很多次!!为什么???
因为没有判断按键释放,当我们按下键盘时,程序可能已经跑了N个来回了。
好了,我们来个改进版的按键扫描程序
键盘按下?YES---延时去抖----键盘按下?YES-----确实按下了,按键有效---A按键释放?YES--退出
NO NO NO
退出 退出 返回A
这是大多数人的按键扫描程序,在一般的场合也能用。这个程序比第一个要好点,但也好不到哪里去。为什么?判断按键释放的方法太笨了,如果我们一直按下这个键盘会怎么样?程序在此死等,可能你说我还有中断,但中断处理完了你还得回来傻等!而且其他按键也将被屏蔽。
那么,让我们好好想想该怎么做。。。。。。。(未完待续,欢迎大家跟贴,谈一下自己的解决方法;看有没有同道中人)
继上:
谢谢大家的跟贴,看来同道中人还很多
在这里严重BS一下自以为是老鸟的菜鸟【2楼】 xingcn 星尘 你除了模仿别人的东西还会什么?如果你
有原创的东西就让大家看看。
;=========================================================================================
言归正传,其实楼下很多人都给出了较好的按键扫描程序,但没有人解释一下为什么要那么做。
现在我来谈谈自己的看法 。先假设按键平时是高电平,按下后是低电平。也就是按键低电平有效
那么一个完整的按键过程会发生什么?按键输入脚电平变化顺序是 高----》低----》高
未按键 按下键 键释放
真正的高手看到这里就恍然大悟,后面的基本不用看了。
好的按键扫描程序不是判断按键是否被按下,而是判断按键电平变化的变化顺序是否符合 高----》低
----》高 ,其他的按键电平变化顺序都是非法的 。这是按键扫描的基本原理。那么该怎么来判断呢?
进入按键扫描后,我们可能会扫到高电平,那么就需要判断到底是未按键导致的高电平还是按下后键释
放导致的高电平,这里用一个位变量(取名为键前状态,1=曾经按下,0=未按下)做为标志就可以了;
也可能会扫到低电平,那么需要判断这个低电平是由未按键到按下键得到的,还是扫描之前本来就是低
电平,这里也用一个位变量(取名为键有效1=有效,0=无效)做为标志。好了,下面给一个简单的流程
主程序初始化操作,键前状态=0,键有效=0
按键扫描流程
键盘===高电平----》键有效=1--》A1键盘曾经按下后变成高电平,键盘已释放,复位键前状态=0---》退出
! !
! --》键有效=0--》未按下---》退出
!
!
!
!===低电平----》键前状态=1--》键盘曾经按下,现在仍然是低电平--》退出
!
--》键前状态=0--》未按下---》A2键盘由高电平变成低电平,置键有效=1,键前状态=1;---》退出
为了突出重点,这个流程没有加去抖处理,想要稳定的效果,必须加延时去抖处理。按这个流程处理按键,响应速度快,
也不会误判。你就是按一天也,不会傻等。按键有效之后,每次只进来看一下就走。最大的好处就是可以实现真正的模块化
按键处理完全由这个程序控制,不必在其他地方判断按键释放没有。
另外再简单谈一下长按,短按的判断。要判断长按,在按键有效之后(A2处)启动定时器,然后在按键释放(A1处)后判断时
间的长短,大于一定时间算长按。至于组合键盘的处理,在上面的流程上稍加改动就可以实现,等有时间再详谈。
回复 楼主 的帖子
我一般用第二种方法。
通常情况下,按键过程中除了中断(多数是显示中断这些直观的东西),你还指望程序干别的吗?
回复 沙发 的帖子
稍微用代码表示一下更能说明问题
按键处理的事情的确很多,按下后只处理一次,等待一段时间后连续处理,处理的间隔时间随按住的时间增加而减少,按键的组合,长按和短按,单次和双击,密切关注LZ这些功能是不是都能讲到。
回复 板凳 的帖子
我的按键是这样处理的
1.读健状态,与上次健状态比较,不同,更新健状态和当前时间,相同则时间不变(或者加一)
2.当前时间与最后一次更新按键时间比较,超出规定时间,则可以判断健已经稳定。
3.与以前比较,就可以进行健处理了。
缺点,用的RAM多,优点,不等待
#include
#include
void ReadKey(void)
{
byte i,Temp0;
bit KeyFlag;
static byte Q0;
P1 = 0xff;
Temp0 = ~P1;
if(Temp0 != Qsw0)
{
Qsw0 = Temp0;
KeyTime = Time20ms;
}
else
{
if(Time20ms - KeyTime > 3)
{KeyFlag = 1;}
}
if(KeyFlag)
{ KeyFlag = 0;
i = Qsw0 &~Q0 & 0xbb; //健按下
if(i)
{
if(i & 0x80) {KeyValue = BryRightKey;}
if(i & 0x20) {KeyValue = AddRightKey;}
if(i & 0x10) {KeyValue = SubbRightKey;}
if(i & 0x08) {KeyValue = ReadPhotoRightKey;}
if(i & 0x02) {KeyValue = LgyRightKey;}
if(i & 0x01) {KeyValue = LightRightKey;}
}
i = Q0 &~Qsw0 & 0xbb; //健松开
if(i)
{
//健松开,处理代码;
}
Q0 = Qsw0;
}
}
回复 4楼 的帖子
我也贴一段吧,这是我的一个项目中的键盘扫描函数,基于UCOSII的,功能有按下处理一次,连续按住一段时间能连续处理,函数返回键值,键盘扫描是单独一个任务,定时扫描的,在时间上没有大的等待,这样说可以帮助理解
INT8U KeyScan(void)
{
static INT8U keyrepeat,keyprevalue,times,fastad;
INT8U KeyOut=0xfb;
INT8U keyvalue;
INT8U keyfirst;
for(;KeyOut!=0x1f;KeyOut=KeyOut>>1)
{
KeyOutPort &= 0xf8;
KeyOutPort |= (KeyOut&0x07);
__delay_cycles(5);
keyvalue = KeyInputPort&0x38;
if(keyvalue!=0x38)
{
keyvalue |= (KeyOut&0x07);
if(keyprevalue==keyvalue)
{
if(keyrepeat!=0xff) keyrepeat=0xff;
else if((keyvalue==KeyLeft)||(keyvalue==KeyRight)||(keyvalue==KeyUp)||(keyvalue==KeyDown))
{
if(fastad==0xff) //针对调整按键 进行快速按键处理
{
if(times>=(100/KeyScanDelay)) times=0;
else
{
times++;
keyvalue=0xff;
}
}
else if(times>=(1000/KeyScanDelay))
{
fastad=0xff;
times=0;
}
else
{
times++;
keyvalue=0xff;
}
}
else keyvalue=0xff;
}
else
{
keyprevalue = keyvalue;
keyfirst = 0xff;
}
break;
}
else keyvalue = 0;
}
if(keyvalue==0)
{
keyrepeat = 0;
keyprevalue = 0;
times = 0;
fastad = 0;
}
else if((keyvalue==0xff)||(keyfirst==0xff)) keyvalue = 0;
return keyvalue;
}
LZ仍然在误人子弟
直接言归正传不行吗, 延时等待不一样很笨吗?
Re: [讨论] 思路决定出路--键盘扫描详解
条理还好,但有代码说明更好
楼主是不是原创阿, 这些介绍和代码网上很多 长得一模一样
期待原创
支持开源