找回密码
 立即注册

QQ登录

只需一步,快速开始

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

单片机程序 长按关机时会触发一次短按,如何解决?

  [复制链接]
跳转到指定楼层
楼主
单片机源程序如下:
#define PD 0x22|(P1&0x51)|(P2<<1&0x80)|(P3<<2&0x0c)   /组合5个按键为1个字节数据

#define S0 0   //状态0
#define S1 1   //状态1
#define S2 2   //状态2
#define S3 3   //状态3

sbit up   = P2^6;   //0111 1111  7f
sbit unit = P1^0;   //1111 1110  fe
sbit down = P3^0;   //1111 1011  fb
sbit md   = P1^6;   //1011 1111  bf
sbit k5   = P3^1;   //1111 0111  f7
sbit k6   = P1^4;   //1110 1111  ef

/*******************************************************************************
* 文件名:按键函数
* 描  述:
* 功  能:
* 参  数:无
*******************************************************************************/        
void key_scan()
{
      bit kflag;
     static u8 state=S0,key_time;
     u8 key;
     key=PD&0xFF;                                
     switch(state)   //检测状态                              
         {
         case S0:                                                    //状态0
                 if(key!= 0xFF) state = S1; break;        
               
        case S1:                                                     //状态1
                if(key==0xFF) state = S0;                  //判断输入是否为1,为1返回状态0
                else                                                 //否则,转入状态2,执行按键程序
                  {
                    state=S2;                                   //按键按下执行短按操作
                    switch(key)
                         {
                         case 0x7F:      加键     break;
                                                                                                        
                        case 0xfe:       单位切换    break;        
                                       
                         case 0xFB:      减键     break;
                                                        
                         case 0xBF:     执行任务      break;
                                                
                         case 0xF7:   执行任务     break;
                                 
                         case 0xEF:    执行任务      break;        
                         default:break;               
                         }
                }
              break;

  case S2:                                                            //状态2
     if(key==0xFF) state = S0;                              //判断输入是否为1,为1返回状态0
     else if(++key_time==200)                          //按下时间等于200时为长按,转入状态3
          {
              key_time=0;state=S3;                                                                       
          }      
                 break;

  case S3:                                                  //状态3
     if(key==0xFF)    state=S0;                               //判断输入是否为1,为1返回状态0                                         
     else if(++key_time==5)                                 //否则开始计时,计时结束按键连击
       {
         key_time=0;
        switch(key)
          {
             case 0x7F:        执行任务                  break;                                                         
             case 0xfe:        单位切换+长按开关机   break;      //短按切换单位,长按开关机。长按开机或关机后都会跟随一次短按,如关机前是P单位,再次开机后不会在P单位,而是P下一个单位K.(此键放在这个位置是不对的,这里是连按识别,应该放在长按识别里的。)
             case 0xFB:       执行任务                    break;                                                                                                                                                                                                                                                                                
          }
      }
      break;
  }
红色标注部分如何解决?在网上查了下,是不是要加个自锁标志?


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

使用道具 举报

沙发
ID:161164 发表于 2022-11-29 09:58 | 只看该作者
要加长按功能,就需要在放开按键后才判断键值
回复

使用道具 举报

板凳
ID:686513 发表于 2022-11-29 11:03 | 只看该作者
lkc8210 发表于 2022-11-29 09:58
要加长按功能,就需要在放开按键后才判断键值

佩服,太厉害了!
回复

使用道具 举报

地板
ID:1001745 发表于 2022-11-29 13:15 | 只看该作者
lkc8210 发表于 2022-11-29 09:58
要加长按功能,就需要在放开按键后才判断键值

void key_pros()
{
if(flag_1ms==1)
{
  flag_1ms = 0;
  if(key1==0)           //判断模式按键是否按下
  {
   if(press_delay<0xffff)press_delay++;
   if(press_delay==20)                 //20ms消抖处理
   {
    click_count++;
   }
   if(press_delay==3000)
   {
    key_val = 10;
   }
   release_delay = 0;
  }
  else
  {
   if(press_delay<0xff)release_delay++;
   if(release_delay==200)
   if(press_delay<3000)
   {
    key_val = click_count;
        click_count = 0;
   }
   press_delay = 0;
  }
  if(key_val > 0)         //若有按键按下
  {
   if(key_val==10)         //长按1.5s
   {
    EN = ~EN;      //HG控制端状态取反
        LED_R = ~LED_R;
   }
   else if(key_val==1)
   {
    HC = ~HC;     //HC控制端状态取反
        LED_3 = ~LED_3;
   }
   else if(key_val==2)
   {
    FLK = ~FLK;    //闪光控制端口状态取反
        LED_T = ~LED_T;
   }
    else if(key_val==3)
   {
    FAN = ~FAN;           //手动开启散热风扇,连续按3次状态取反关闭风扇。
        LED_6 = ~LED_6;
   }
   key_val = 0;
  }
}
}
大师,我的这个按键程序也有这样的问题,长按之后就会触发短按的功能,这个该如何修改?谢谢!
回复

使用道具 举报

5#
ID:161164 发表于 2022-11-29 13:42 | 只看该作者
mcuhui 发表于 2022-11-29 13:15
void key_pros()
{
if(flag_1ms==1)

很熟悉的代码
长按成立后要把click_count清零
22行也有点问题



回复

使用道具 举报

6#
ID:1001745 发表于 2022-11-29 14:10 | 只看该作者
lkc8210 发表于 2022-11-29 13:42
很熟悉的代码
长按成立后要把click_count清零
22行也有点问题

谢谢大师指导,小弟不才,这段代码也是参考论坛上的程序进行修改移植的。
回复

使用道具 举报

7#
ID:1034262 发表于 2022-11-29 14:37 | 只看该作者
短按释放执行,按下不执行键码。
回复

使用道具 举报

8#
ID:686513 发表于 2022-11-30 14:16 | 只看该作者
lkc8210 发表于 2022-11-29 09:58
要加长按功能,就需要在放开按键后才判断键值

大师,今天又测试了一下,之前长按松手后会触发一次短按,按您的代码修改后,显示上是对的了,但实际好像还是触发了一次短按。这个是关机后长按开机发现的,本来我是把上次的单位保存到了EEPROM中,开机后会跳到下个单位。
回复

使用道具 举报

9#
ID:161164 发表于 2022-11-30 15:55 | 只看该作者
zhth1979 发表于 2022-11-30 14:16
大师,今天又测试了一下,之前长按松手后会触发一次短按,按您的代码修改后,显示上是对的了,但实际好像 ...

试试这样

回复

使用道具 举报

10#
ID:686513 发表于 2022-11-30 16:42 | 只看该作者

刚刚试过了,还是不行!
回复

使用道具 举报

11#
ID:1054812 发表于 2022-11-30 16:51 | 只看该作者
设定一个阈值,键按下开始计数,键释放开始判断:小于阈值为短按,大于阈值为长按
回复

使用道具 举报

12#
ID:161164 发表于 2022-11-30 17:08 | 只看该作者
zhth1979 发表于 2022-11-30 16:42
刚刚试过了,还是不行!

这样呢?


回复

使用道具 举报

13#
ID:213173 发表于 2022-11-30 20:43 | 只看该作者
zhth1979 发表于 2022-11-30 16:42
刚刚试过了,还是不行!

给你一个验证程序,看懂了就可以自由发挥了。
  1. #include <REG51.H>
  2. #define uint unsigned int
  3. #define uchar unsigned char
  4. #define key_S 1100           //宏定义短按(约20ms)
  5. #define key_L key_S*50       //宏定义长按(约1s)

  6. sbit key=P3^6;
  7. sbit LED1=P1^0;
  8. sbit LED2=P1^4;

  9. void keyscan()               //按键扫描
  10. {
  11.         static uint count=0;     //计数变量
  12.         if(!key)   
  13.         {  
  14.                 count++;  
  15.                 if(count==key_L)    //长按
  16.                         LED2=~LED2;     //长按任务
  17.                 if(count>key_L)     //防止count溢出
  18.                         count=key_L+1;         
  19.         }  
  20.         else                    //按键抬起
  21.         {  
  22.                 if(count>key_S && count<key_L)//短按
  23.                         LED1=~LED1;     //短按任务
  24.                 count=0;            //count清0
  25.         }   
  26. }

  27. void main()
  28. {
  29.         while(1)
  30.         {
  31.                 keyscan();
  32.         }
  33. }
复制代码
回复

使用道具 举报

14#
ID:686513 发表于 2022-12-1 08:23 | 只看该作者

仍然不行,我再描述一下:长按关机时不会出现一次短按,长按开机时会出现一次短按。
回复

使用道具 举报

15#
ID:686513 发表于 2022-12-1 09:04 | 只看该作者
wulin 发表于 2022-11-30 20:43
给你一个验证程序,看懂了就可以自由发挥了。

这个程序只能识别长按和短按,我还要有连按功能就没办法识别了吧?
回复

使用道具 举报

16#
ID:686513 发表于 2022-12-1 09:17 | 只看该作者
此按键扫描功能:短按  长按加连按三种功能!
回复

使用道具 举报

17#
ID:161164 发表于 2022-12-1 09:26 | 只看该作者
zhth1979 发表于 2022-12-1 08:23
仍然不行,我再描述一下:长按关机时不会出现一次短按,长按开机时会出现一次短按。

长按开机代码?
回复

使用道具 举报

18#
ID:686513 发表于 2022-12-1 10:15 | 只看该作者
本帖最后由 zhth1979 于 2022-12-1 10:18 编辑
lkc8210 发表于 2022-12-1 09:26
长按开机代码?

可能我描述的不清楚,case 0xfe  这个键短按是单位切换长按是开关机,放在S3这个状态里是不对的,这里是连按识别,应该放在长按识别里的(else if(++key_time==200) 这个地方的,但这个地方我没法判断长按抬起,所以后面直接放到了连按里了,问题应该出在这  )。开机代码就是在休眠前开个外部中断,这个键我连到外部中断1上了,按下会进中断,中断里退出休眠,关机是这个键长按直接给Low_Power赋值,这个值是大于77,所以就直接休眠了。
//休眠 ---------------------------------------------------------------------------------------------                                                
  if(XmCnt==1)
                {
                 if(T1Cnt == 0)                        
                          {
                                 Low_Power ++;        
                                }        
      else
                          {                        
                                 Low_Power = 0;
                          }        
                }                                
                 if(Low_Power > 77)
                      {        
           IT1=1;
           EX1=1;
                                                
                                         ET0=0;
                                         ET1=0;
                                         EIE &= 0xfb;        //关闭SG ADC 中断
                                                                        
                        //确保关闭24位-ADC
                                PD_CON    = 0x02;                                //解锁P2 解锁sgadcon,sgadcon2; 并确保关闭LDO;        
                                SGADCON &= 0x3f;                                //关闭24ADC
                                
                        //配置低漏电模式:
                                PCON2  &= 0xfe;                                //解锁PD_CON2\PD_CON3
                                PCON2  = 0x00;                                //确保PD_CON2为默认值
                        //通过PCON3来配置STOP2的休眠模式
                                WD_TA = 0x05;
                                WD_TA = 0x0a;
                                PCON3  = 0xf3;                                //0xf3 1111 0011 STOP2: por_high_en同步关闭; 允许关闭PDM2; 不关闭PDM1; 关闭看门狗; 数字LDO切换到低功耗;
                                                
                                        P0 = 0xff;P1 = 0xff;P2 = 0xff;
                                        P3 = 0xff;P4 = 0xff;         
                                        md1=0;                 
                                                
                                 _nop_();
                                        PCON |= 0x00;                        //进入休眠模式
                                 _nop_();
          Power_Down_F = 0;                                         
                      //-- 关机 : 等待外部中断唤醒 ---         
                while(1)
                          {
                                  if(Power_Down_F)        
                                //        PCON |= 0x40;
                      PCON        = 0x0C;        
                          }
                   }        
   }
}

void EX_Int1 (void) interrupt 2       //INT1
{         
Power_Down_F = 1 ;
        
}
回复

使用道具 举报

19#
ID:686513 发表于 2022-12-3 16:25 | 只看该作者
coody_sz 发表于 2022-11-29 14:37
短按释放执行,按下不执行键码。

是的,在哪步判断呢?
回复

使用道具 举报

20#
ID:1040651 发表于 2024-2-16 21:22 | 只看该作者
遇到了这个问题,找答案的同时自己想到了办法,在按键时检测长按,松键检测短按,长按条件满足时 设置一个按键保护时间,在松键判断之前判断一下保护时间,保护时间为0再执行短按判断,因为一般长按后不会马上操作
回复

使用道具 举报

21#
ID:1109793 发表于 2024-2-17 07:59 | 只看该作者
fww223 发表于 2024-2-16 21:22
遇到了这个问题,找答案的同时自己想到了办法,在按键时检测长按,松键检测短按,长按条件满足时 设置一个 ...

马上操作也需要断开一次的,在识别为长按之后设定一个标志,在断开时看下没有标志就是短按,有旧忽略并且清除掉这个标志
回复

使用道具 举报

22#
ID:1109793 发表于 2024-6-28 18:13 | 只看该作者
按照输入点处理,下降沿,上升沿,低电平保持,高电平保持,保持中连续触发
回复

使用道具 举报

23#
ID:420836 发表于 2024-6-30 01:21 | 只看该作者
判断键盘按下是长按还是短按,必须插入一个按键释放状态来判断按键是否完成。
回复

使用道具 举报

24#
ID:329625 发表于 2024-7-1 21:38 | 只看该作者
加上松手检测与定时器判断就可以解决了
回复

使用道具 举报

25#
ID:1127816 发表于 2024-7-2 00:40 来自手机 | 只看该作者
在软件设计上,可以在长按逻辑执行完毕后,添加一个忽略短按的缓冲时间,在这个时间内不响应任何短按事件。
回复

使用道具 举报

26#
ID:521990 发表于 2024-7-3 16:34 | 只看该作者
收藏学习
回复

使用道具 举报

27#
ID:1104510 发表于 2024-7-5 13:47 | 只看该作者
wulin 发表于 2022-11-30 20:43
给你一个验证程序,看懂了就可以自由发挥了。

大佬  你这个程序很好  效果很赞  我想问下  你那个#define key_S 1100  #define key_L key_S*50   这两个按键按下去的时间时怎么得来的呢?我想要赋值其他的时间数值进去  求告知
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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