找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9100|回复: 3
打印 上一主题 下一主题
收起左侧

基于单片机按键的长按与短按功能是实现(PS:有自己的想法)

[复制链接]
跳转到指定楼层
楼主
ID:99624 发表于 2015-12-27 03:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
纵观现在的智能硬件产品,按键少,功能多。在保证产品外观漂亮的同时,如何用最少的按键,来实现较多的功能。
  所以就去网上搜了,按键长按与短按实现的方法。其中精华代码,是我在其他人的博客【http://www.51hei.com/bbs/dpj-41706-1.html】学来的。他的核心代码写的很棒,但是在后边函数调用的时候,要根据自己功能的实现去适当的更改代码。
    核心算法

   unsigned char Trg;

   unsigned char Cont;

   void KeyRead( void )

    {

       unsigned char ReadData =GPIO_ReadInputDataBit(GPIO*,GPIO_Pin)^0xff;  // 1

       Trg = ReadData & (ReadData ^Cont);     // 2

        Cont=ReadData;                              // 3

   }

作为一个新手来说,还是要具体其分析分析的:

我们就按键开始为高电平 ,按下为低电平,进行分析。

程序解读:

Trg(triger) 代表的是触发,Cont(continue)代表的是连续按下。

1:GPIO_ReadInputDataBit()这个函数,就是读取按键GPIO*按键引脚的输入状态。^0xff,和前面读取到的状态,取反。并将数值储存到ReadData中;

2:用来计算触发变量;

3:用来计算连续变量。

(1)没有按键的时候

端口为0xff,ReadData读端口并且取反,很显然,就是 0x00 了。

Trg = ReadData & (ReadData ^ Cont);(初始状态下,Cont也是为0的)很简单的数学计算,因为ReadData为0,则它和任何数“相与”,结果也是为0的。

Cont = ReadData; 保存Cont 其实就是等于ReadData,为0;

结果就是:

ReadData = 0;

Trg = 0;

Cont = 0;

(2) 第一次PB0按下的情况

端口数据为0xfe,ReadData读端口并且取反,很显然,就是 0x01 了。

Trg = ReadData & (ReadData ^ Cont);因为这是第一次按下,所以Cont是上次的值,应为为0。那么这个式子的值也不难算,也就是 Trg = 0x01 &(0x01^0x00) = 0x01

Cont = ReadData = 0x01;

结果就是:

ReadData = 0x01;

Trg = 0x01;  (Trg只会在这个时候对应位的值为1,其它时候都为0)

Cont = 0x01;

(3)      PB0按着不松(长按键)的情况

端口数据为0xfe,ReadData读端口并且取反是 0x01 了。

Trg = ReadData & (ReadData ^ Cont);因为这是连续按下,所以Cont是上次的值,应为为0x01。那么这个式子就变成了 Trg = 0x01 &(0x01^0x01) = 0x00

Cont = ReadData = 0x01;

结果就是:

ReadData = 0x01;

Trg = 0x00;

Cont = 0x01;

因为现在按键是长按着,所以MCU会每隔一段时间就会,不断的执行这个函数,那么下次执行的时候情况会是怎么样的呢?

ReadData = 0x01;这个不会变,因为按键没有松开

Trg = ReadData & (ReadData ^ Cont) = 0x01 & (0x01 ^ 0x01) =0 ,只要按键没有松开,这个Trg值永远为 0 !!!

Cont = 0x01;只要按键没有松开,这个值永远是0x01!!

(4)      按键松开的情况

端口数据为0xff,ReadData读端口并且取反是 0x00 了。

Trg = ReadData & (ReadData ^ Cont) = 0x00 & (0x00^0x01) =0x00

Cont = ReadData = 0x00;

结果就是:

ReadData = 0x00;

Trg = 0x00;

Cont = 0x00;

很显然,这个回到了初始状态,也就是没有按键按下的状态。

该代码的精华之处就在于:Trg只有在按一按键的时候才为0x01,只要按键没有放开Trg从第二次进入KeyRead()后,就一直为0x00;Cout,只要按键是按下的,这个值就一直为0x01。

理解基本就是这样了,下面说一下用到的例子:

1:原文中博主的例子,有一个是这样的,类似小时候玩过的电子表调节时间。

按一个键不放手(直到到达指定的功能在放手),从按下,到放手,这个键盘包含了两个功能——切换模式、累计加数(针对他的例子说的功能,意会即可)。其实总的意思就是,从按下,到松手,Trg开始的时候(第一下)为0x01,因为没有放手,故第二次执行KeyRead()的时候,Trg就变为了0x00;故根据原博主的if(Trg & 0x01)和if(Cont & 0x01)这个的判断,从按下,到松手,这个两个函数都会执行过去。[注:原博主的KEY_PLUS的宏定义应该为错误的,若为0x02,这个if永远都不会执行]

上述讲述的这个键盘的功能,做项目可能用得到。

2:在一个就是,我自己做东西遇到的一个问题。按键,短按一个功能,长按一个功能(两个功能不能同时到来)。显然例子1的代码满足不了我的需求。下面看我的代码:

void Key_Proc(void)
{
  if(Trg&0x01)    //短按
  {
   DelayMs(200);   //200ms
   if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13)==1)   //判断读取出的键盘输入状态是否为高电平

   {
   运行代码;

    b=0;
   }
  }
  
  if(Cout&0x01)    //长按
  {
   b++;
   if(b>20)
   {  
   运行代码;

    b=0;
   }
  }
}

int main()

{

    KeyRead();

    Key_Proc();

    while(1)

   {

        DelayMs(10);

        break;

   }

}

我改的代码,除了   DelayMs(200);   //200ms
                              if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13)==1)   //判断读取出的键盘输入状态是否为高电平

其他的基本相同,这段代码,主要解决长按按键,两种功能同时出现的事件。

分析:按键按一下,即按下立马松开。键盘一开始为高电平,Delay,消除键盘按下到放开的反应时间,200MS足以,然后在检测按键输入状态,若为高,说明,已经放开了,判断这是一次短按。

         按下不放手,按键开始为高电平,不放手,延迟过后,检测按键依然为低,不进入if,也就屏蔽掉了这个短,按的功能,然后进行后边的if(Cout&0x01),判断为真,进入,b++,后边有10MS的延迟。b一会就会加到20,执行程序,并清除b的值。

         为什么短按里面要加一个b=0呢?如果不加的话,你按键盘,若的时间为达到长按的要求,这时候b也会++,可能会出现这样的情况,连续点击键盘,按下松开,按下松开.......虽然你没有长按,但是连续的点击会使b++到20,导致触发功能。故在短按里面加一个b=0.

大致就是这个样子了,还有就是在一个程序中,一个键盘,在不同的地方有不同的功能,这个又该如何实现呢?


我想出来的就是用switch() case 语句实现。switch判断处于程序的哪一个阶段,在找对应的case去执行就好了。今天太累了,具体怎么实现我就不贴代码了。


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏4 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:79544 发表于 2015-12-29 10:00 | 只看该作者
楼主辛苦啦,学习啦,学习分享!
回复

使用道具 举报

板凳
ID:65323 发表于 2019-3-6 09:28 | 只看该作者
原博主的
#define KEY_MODE 0x01    // 模式按键
#define KEY_PLUS 0x02     // 加
这个是定义了两个按键,在示例中,KEY_MODE键只有短按有效,KEY_PLUS键只有长按有效。
回复

使用道具 举报

地板
ID:299626 发表于 2021-5-14 13:17 | 只看该作者
mark一下,学习了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表