找回密码
 立即注册

QQ登录

只需一步,快速开始

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

51单片机怎样用按键控制长短按切换界面,求程序思路

  [复制链接]
跳转到指定楼层
楼主
ID:444712 发表于 2019-7-29 17:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我要用两个按键k1,k2。长按K2,切换到设置界面,短按K2切换到常规界面。弄了好久没有弄好,请高手帮忙指导一下,谢谢!
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:435708 发表于 2019-7-29 19:54 | 只看该作者
请工程化,定制化你的单片机代码
http://www.51hei.com/bbs/dpj-162218-1.html
(出处: 单片机论坛)
回复

使用道具 举报

板凳
ID:332444 发表于 2019-7-29 20:44 | 只看该作者
一般使用状态进行切换,你是怎么弄的不行?
回复

使用道具 举报

地板
ID:213173 发表于 2019-7-29 21:18 | 只看该作者
如果K2只是用于切换界面不必采用长短按方式,只要设置一个标志随操作取反即可。如果K2是多功能键才有必要分长短按。给你一个简单实用的长短按示例程序参考,希望对你有所帮助。
  1. #include <REG51.H>
  2. #define uint unsigned int
  3. #define uchar unsigned char
  4. #define key_S 20                                                //宏定义短按(20ms)
  5. #define key_L key_S*50                                //宏定义长按(1s)

  6. sbit key1=P3^5;
  7. sbit key2=P3^6;
  8. sbit LED1=P1^0;
  9. sbit LED2=P1^2;
  10. sbit LED3=P1^4;
  11. sbit LED4=P1^6;
  12. uchar KeySec=0;

  13. void Timer0Init()//1毫秒@12.000MHz
  14. {
  15.         TMOD= 0x01;                //设置定时器模式
  16.         TL0 = 0x18;                //设置定时初值
  17.         TH0 = 0xFC;                //设置定时初值
  18.         TF0 = 0;                        //清除TF0标志
  19.         TR0 = 1;                        //定时器0开始计时
  20.         EA=1;                                //开总中断
  21.         ET0=1;                        //开定时器0中断
  22. }

  23. void keyscan()                                                        //按键扫描
  24. {
  25.         static uint count1=0;                        //计数变量
  26.         static uint count2=0;                        //计数变量
  27.         if(!key1)   
  28.         {  
  29.                 count1++;  
  30.                 if(count1==key_L)                                //长按
  31.                         KeySec=2;                                        //输出键值2
  32.                 if(count1>key_L)                                //防止count溢出
  33.                         count1=key_L+1;          
  34.         }  
  35.         else                                                                        //按键抬起
  36.         {  
  37.                 if(count1>key_S && count1<key_L)//短按
  38.                         KeySec=1;                                        //输出键值1
  39.                         count1=0;                                        //count清0
  40.         }   
  41.         if(!key2)   
  42.         {  
  43.                 count2++;  
  44.                 if(count2==key_L)                                //长按
  45.                         KeySec=4;                                        //输出键值4
  46.                 if(count2>key_L)                                //防止count溢出
  47.                         count2=key_L+1;          
  48.         }  
  49.         else                                                                        //按键抬起
  50.         {  
  51.                 if(count2>key_S && count2<key_L)//短按
  52.                         KeySec=3;                                        //输出键值3
  53.                         count2=0;                                        //count清0
  54.         }   
  55. }

  56. void key_service()                                        //按键服务程序
  57. {
  58.         switch(KeySec)                                                //按键服务状态切换
  59.         {
  60.                 case 1:LED2=!LED2;KeySec=0;break;
  61.                 case 2:LED1=!LED1;KeySec=0;break;
  62.                 case 3:LED4=!LED4;KeySec=0;break;
  63.                 case 4:LED3=!LED3;KeySec=0;break;
  64.                 default: break;
  65.         }
  66. }

  67. void main()
  68. {
  69.         Timer0Init();                //初始化定时器
  70.         while(1)
  71.         {
  72.                 key_service();        //按键服务程序
  73.         }
  74. }
  75. void timer0() interrupt        1//1毫秒@12.000MHz
  76. {
  77.         TL0 = 0x18;                //设置定时重装值
  78.         TH0 = 0xFC;                //设置定时重装值
  79.         keyscan();                //按键扫描程序
  80. }
复制代码



回复

使用道具 举报

5#
ID:136106 发表于 2019-7-29 22:34 | 只看该作者
这个可以用定时器来操作,假设K2按下的时间超过2S进入设置界面。配置好定时器计时计数,当检测到K2按下时开启计时。比如说100ms来一次中断,计数值temp++,当来20次中断后时间就为2S。判断按键松开时temp的值是否大于20?当temp的值大于20就进入你所说的设置界面,小于20就进入页面切换。这样的小程序用51来操作很容易,但是要注意定时器计数器的初值装载的问题,还有就是51单片机所用的晶振。12MHz的晶振和11.0592MHz的初值装载是不一样的。没看懂的话就要回去看看51的定时器的知识了
回复

使用道具 举报

6#
ID:388197 发表于 2019-7-29 23:59 | 只看该作者
随手写的,就写了1个按键长按短按不同功能,不保证没BUG.注释标得也自认为是清楚了,你对着你想要的修改调试下应该就可以了.


#define Long_Push_Time    n        //长按功能按键时长(n乘以定时器中断周期)
#define Short_Push_Time   m       //短按功能按键时间,需注意必须n 大于 m
sbit KEY = Px^x;                               //按键IO口定义
bit Flag_Short_Push_Funcation = 0;    //短按触发标志
bit Flag_Long_Push_Funcation = 0;    //长按触发标志
bit Flag_KEY_Pushed               = 0;   //按键曾经按下标志

void Init_T0()                                 //定时器中断设置
{
   .....
}

void Short_Push_Prog()
{
    ..........
}

void Long_Push_Prog()
{
     ............
}
void mian()
{
     Init_T0();
     while(1)
     {
        if(Flag_Short_Push_Funcation)                      //如果短按功能被置1
        {
              Short_Push_Prog();                              //执行短按功能对应的函数
              Flag_Short_Push_Funcation = 0;           //清短按功能标志.
        }
        if(Flag_Long_Push_Funcation)                    //长按功能,跟上面类同.
       {
               Long_Push_Prog();
               Flag_Long_Push_Funcation = 0;
       }
     }
}

void T0_ISR() interrupt 1
{
    TH0 = XXXX;
    TL0 = XXXX;
     if(!KEY)                                             //按键按下
     {
        KEY_CNT++;                                 //开始计时
        Flag_KEY_Pushed= 1;                    //按键已经按过的标志置1
        Flag_Short_Push_Funcation = 0;                   //短按无效
        Flag_Long_Push_Funcation  = 0;                   //长按无效
     }
     if(KEY && Flag_KEY_Pushed == 1 && KEY_CNT < Short_Push_Time)
     /*如果按键没有按下但按键曾经按下,可是按下时间很短,不足以触发短按的设定时间,则认为是干扰*/
    {
         Flag_KEY_Pushed= 0;                                  //清按键曾经按下标志
         KEY_CNT = 0;                                            //清按键按下计时变量
         Flag_Short_Push_Funcation = 0;                   //短按无效
         Flag_Long_Push_Funcation  = 0;                   //长按无效
         return;                                          //如判断为干扰,则下面的代码无须执行,直接跳出.  
    }
     if(KEY && Flag_KEY_Pushed == 1 && KEY_CNT>=Short_Push_Time &&
       KEY_CNT < Long_Push_Time)
      /*如果按键没有按下, 但按键已经按过(用来判断按过后弹起),
            并且曾经按下时间超过 设定短按时间且不超过长按时间*/
     {
           Flag_Short_Push_Funcation = 1;         //短按功能有效
           Flag_Long_Push_Funcation = 0;         //长按功能无效
           KEY_CNT             = 0;                      //清按键计时变量
           Flag_KEY_Pushed=  0;                      //清按键曾经按下标志
           return;                       //判断完成,直接跳出
     }
}

      if(KEY && Flag_KEY_Pushed == 1 && KEY_CNT>=Long_Push_Time )
      /*如果按键没有按下, 但按键已经按过(用来判断按过后弹起),
            且曾经按下时间超过 长按时间*/
       {
           Flag_Short_Push_Funcation = 0;         //短按功能无效
           Flag_Long_Push_Funcation = 1;         //长按功能有效
           KEY_CNT             = 0;                      //清按键计时变量
           Flag_KEY_Pushed=  0;                      //清按键曾经按下标志
       }
}
回复

使用道具 举报

7#
ID:511461 发表于 2019-7-30 08:27 | 只看该作者
cjm82 发表于 2019-7-29 23:59
随手写的,就写了1个按键长按短按不同功能,不保证没BUG.注释标得也自认为是清楚了,你对着你想要的修改调试下 ...

谢谢分享
回复

使用道具 举报

8#
ID:123289 发表于 2019-7-30 08:31 | 只看该作者
要点:做一个计数器CJ来判定长按与短按,CJ的规则如下:
1、CJ计数只发生于定时器的中断服务程序中,每次中断+1,计满不再计,即不回0。
2、CJ计数只发生于键按下的时候,未按下不计。
3、做一个键状态判定触发标记:B_OK,如果键未按下,但CJ<>0,则置B_OK=1,表示是判断键状态的时候了。
4、当B_OK=1,判断键状态的界定法则是:CJ<某个值为短按,CJ>某个值为长按,某个值是多少由你决定。建议事先将长短两个界定值放置在某个寄存器中,这样可以随意变更界定值。
5、状态界定完成后将:B_OK清0、CJ清0以备下次再界定。
回复

使用道具 举报

9#
ID:123289 发表于 2019-7-30 08:40 | 只看该作者
设置界面、常规界面各做一个标记如:B_SET、B_NOR。在哪个界面哪个置1。再多的界面也这样做。如果只有两个界面可以只用一个标记。界面分层叠进叠退时还需要增加次序(层面记忆),这里不说了。
长按以后的动作是:B_SET=1、其它B_NOR=0。
短按以后的动作是:B_NOR=1、其它B_SET=0。
回复

使用道具 举报

10#
ID:123289 发表于 2019-7-30 08:41 | 只看该作者
界面的切换,发生于B_SET、B_NOR有变化的时候。
回复

使用道具 举报

11#
ID:307020 发表于 2019-7-30 10:47 | 只看该作者
参考文章“请工程化,定制化你的单片机代码”,用中断服务对按下键进行计数,根据计数的多少便可换算时间长短、便可根据不同时间长短执行不同的程序了。
回复

使用道具 举报

12#
ID:592379 发表于 2019-7-30 15:31 | 只看该作者
用定时器做,按下按钮开始计数,放开按钮结束计数,按钮函数里面要加个防抖延时
回复

使用道具 举报

13#
ID:444712 发表于 2019-8-1 16:47 | 只看该作者
谢谢!
回复

使用道具 举报

14#
ID:444712 发表于 2019-8-2 16:45 | 只看该作者
cjm82 发表于 2019-7-29 23:59
随手写的,就写了1个按键长按短按不同功能,不保证没BUG.注释标得也自认为是清楚了,你对着你想要的修改调试下 ...

Init_T0,void Short_Push_Prog(),void Long_Push_Prog().里边的内容能否帮忙提供一下.谢谢!
回复

使用道具 举报

15#
ID:415527 发表于 2019-8-4 10:47 | 只看该作者
当按键按下时,开启定时器,并且在定时器中断里面用一个变量来计数,当按键松开时再来判断计数时间,如果小于0.5s,则判断为短按,标志位给0,如果大于0.5s,标志位给1,然后根据标志位进行界面切换。定时器的计数时间要设置一个上限,否则如果时间太长可能会溢出,判断按键按下或松开,可以用经典的三行代码,其中有两个变量,一个变量是用来判断按键的“下降沿”(其实准确来说并不能定义为下降沿,只是按键按下时,第一遍执行程序时,对应的位会发生改变,当执行第二遍时就又变为0,有点类似于static的作用),另一个变量是用来检测按键是否为按下状态,可以用这两个变量来判断按键按下和松开,从而开启或改变定时器,读取计数值,读取完计数值后需要将计数值清零,否则,第二次按下按键时则判断不了短按。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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