整理的网上按键短按、长按,双击的关键代码和思路
(1)
#include "Key_Board.h"

  1. /*记录按键按下时间 时间小于1.5S,按键为短按;时间大于1.5S,按键为长按*/
  2. volatile unsigned int key1_timing = 0;
  3. /*记录两次短按之间的时间间隔*/
  4. volatile unsigned int key1_doublepress_timing = 0;
  5. /*定义按键键值结构体*/
  6. Key_Value k1_value;
  7. /*K1按键短按标志位*/
  8. bool k1_shortpress_happen = 0;
  9. /*K1按键长按标志位*/
  10. bool k1_longpress_happen = 0;
  11. /*K1按键双击标志位*/
  12. bool k1_doublepress_happen = 0;
  13. /*led1闪烁时间标志位,主函数检测到此标志位为1时,led1开始闪烁,否则,结束闪烁*/
  14. bool led1_flash_flag = 0;
  15. /*3个led全部闪烁标志位,主函数检测到此标志为1时,三个led灯开始同时闪烁,否则结束闪烁*/
  16. bool led_all_flash_flag = 0;
  17. /*流水灯事件标志位*/
  1. /*按键键值扫描函数*/
  2. void Key_Scan(void)
  3. {
  4. /*程序不支持两个按键同时按下*/
  5. // if((K1==0&&K2==0) || (K1==0&&K3==0) || (K2==0&&K3==0))
  6. // return ;
  7. if(K1==0) //当K1按键按下
  8. {
  9. if(k1_shortpress_happen==0)
  10. {
  11. k1_shortpress_happen = 1; //开始一次按键键值扫描
  12. key1_timing = 0; //按键按下计时变量清0,开始计时,此值每1ms加1,sysclk中断函数中实现自加
  13. }
  14. if(k1_shortpress_happen==1)
  15. {
  16. if(key1_timing > 1500) //按键按下时间超过1.5S,长按事件发生,置k1_value.long_press为1
  17. {
  18. k1_value.long_press = 1;
  19. k1_shortpress_happen = 0; //按键短按标志位置0
  20. }
  21. }
  22. }
  23. if(K1==1) //当K1按键抬起
  24. {
  25. if(k1_shortpress_happen==1) //按键抬起后,k1_shortpress_happen等于1,说明按键为短按,不是长按
  26. {
  27. k1_shortpress_happen = 0; 
  28. if(k1_doublepress_happen==0)
  29. {
  30. k1_doublepress_happen = 1; //按键双击标志位置1,等待确认按键是否为双击
  31. key1_doublepress_timing = 0; //开始计时,同样1ms自增加1
  32. }
  33. else
  34. {
  35. if(key1_doublepress_timing < 500) //第一次短按发生后,在500ms时间内,发生第二次短按,完成一次双击,跟新按键键值
  36. {
  37. k1_doublepress_happen = 0;
  38. k1_value.double_press = 1;
  39. }
  40. }
  41. }
  42. else
  43. if(k1_doublepress_happen == 1) //第一次短按后,等待500ms,如未再发生短按,跟新按键短按键值
  44. {
  45. if(key1_doublepress_timing > 500)
  46. {
  47. k1_doublepress_happen = 0;
  48. k1_value.short_press = 1;
  49. }
  50. }
  51. else
  52. if(k1_longpress_happen==1)
  53. k1_longpress_happen = 0;
  54. }
  55. }
(2)
typedef enum
{
 KeyDown,
 KeyUp,
 KeyShort,
 KeyLong
}KEYSTATE;
KEYSTATE KeyState;
static u16 KeyDownTimes,KeyDoubleTimes;
void PollingKey(void)
{
 static u8 KeyStep;
 
 switch (KeyStep)
 {
  case 0:
  {
   if (!KeyPin)//有键按下
   {
    //printf("\r\n按下");
    KeyState = KeyDown;
    
    if (KeyDoubleTimes > 0)
    {
     KeyStep = 4;//双击
    }
    else
    {
     KeyStep = 2;//不是双击
    }
   }
   else if(KeyDoubleTimes > 0)
   {
    KeyDoubleTimes--;
    if ((KeyDoubleTimes == 0)&&(KeyState == KeyShort))
    {
     printf("\r\n短按处理");
     KeyState = KeyUp;
    }
   }
   
  }
   break;
  case 1://按下
  {
   if (!KeyPin)
   {
    KeyDownTimes++;
    if (KeyDownTimes < 2800)
    {
     KeyState = KeyShort;
    }
    else if(KeyState != KeyLong)
    {
     KeyState = KeyLong;
     printf("\r\n长按处理");
    }
    else if (KeyDownTimes >= 2800)//防止加满溢出
    {
     KeyDownTimes = 2800;
    }
   }
   else
   {
    KeyStep = 2;
   }
  }
   break;
  case 2://
  {
   if (KeyPin)//弹起
   {
    KeyStep = 3;
   }
   else//按下
   {
    KeyStep = 1;
   }
  }
   break;
  case 3://弹起
  {
   if (KeyPin)//弹起
   {
    if (KeyDownTimes < 2800)
    {
     KeyDoubleTimes = 500;
    }
    KeyDownTimes = 0;
    KeyStep = 0;
   }
   else
   {
    KeyStep = 2;
   }
  }
   break;
  case 4:
  {
   if (KeyPin)//如果弹起的话就执行
   {
    KeyState = KeyUp;
    printf("\r\n双击处理");
    KeyStep = 0;
   }
  }
   break;
 default:
  KeyStep = 0;
  break;
 }
 delay_us(100);
}

(3)

http://amobbs.com/thread-4991902-1-1.html

题目:多功能按键设计。利用一个I/O口,接一个按键,实现3功能操作:单击 + 双击 + 长按。  
============================================================================
用户基本操作定义:
    1。短按操作:按键按下,按下时间<1s,属于一次短按操作
    2。长按操作:按键按下,按下时间>1s,属于一次长按操作

在正常0.5s内无按键操作为启始按键扫描条件下,扫描按键将产生以下3种按键事件:
    1。长按事件:任何1次出现的长按操作都属于长按事件
    2。单击事件:1次短按操作后,间隔0.5内没有短按操作
    3。双击事件:2次短按操作间隔时间<0.5s,则2次短按操作为1次双击事件,且2次短按都取消

特别操作情况定义:
    1。短按操作和长按操作间隔<0.5s,以及,长按操作和短按操作间隔<0.5s,均不产生双击事件
    2。连续n次(n为奇数)短按操作,且间隔均<0.5s,产生(n-1)/2次双击事件+1次单击事件
    3。连续n次(n为偶数)短按操作,且间隔均<0.5s,产生n/2次双击事件

对按键操作者的建议:     
    由于按键的多功能性质,建议操作者每次在单击/长按/双击按键事件发生后,隔0.5s后再进行下一次的按键操作。因为在特别操作情况下,程序是保证按定义进行判断和处理的,主要是怕操作者自己记不清楚导致操作失误。

对软件设计者的要求:
    1。应该全面进行分析,给出严格定义和判断条件,如上所示。如果自己都不清楚,你的设计出的系统就不稳定,不可靠。
    2。在1的基础上,编写出符合要求的程序,并进行全面测试。

/*=============
低层按键(I/0)扫描函数,即低层按键设备驱动,只返回无键、短按和长按。具体双击不在此处判断。参考本人教材的例9-1,稍微有变化。教材中为连_发。
===============*/

#define key_input    PIND.7    // 按键输入口

#define N_key    0             //无键
#define S_key    1             //单键
#define D_key    2             //双键
#define L_key    3             //长键

#define key_state_0 0
#define key_state_1 1
#define key_state_2 2

unsigned char key_driver(void)
{
    static unsigned char key_state = key_state_0, key_time = 0;
    unsigned char key_press, key_return = N_key;

key_press = key_input;                    // 读按键I/O电平

switch (key_state)
    {
      case key_state_0:                              // 按键初始态
        if (!key_press) key_state = key_state_1;      // 键被按下,状态转换到按键消抖和确认状态
        break;
      
      case key_state_1:                      // 按键消抖与确认态
        if (!key_press)
        {
             key_time = 0;                   //  
             key_state = key_state_2;   // 按键仍然处于按下,消抖完成,状态转换到按下键时间的计时状态,但返回的还是无键事件
        }
        else
             key_state = key_state_0;   // 按键已抬起,转换到按键初始态。此处完成和实现软件消抖,其实按键的按下和释放都在此消抖的。
        break;
      
      case key_state_2:
        if(key_press)
        {
             key_return = S_key;        // 此时按键释放,说明是产生一次短操作,回送S_key
             key_state = key_state_0;   // 转换到按键初始态
        }
        else if (++key_time >= 100)     // 继续按下,计时加10ms(10ms为本函数循环执行间隔)
        {
             key_return = L_key;        // 按下时间>1000ms,此按键为长按操作,返回长键事件
             key_state = key_state_3;   // 转换到等待按键释放状态
        }
        break;

case key_state_3:                 // 等待按键释放状态,此状态只返回无按键事件
        if (key_press) key_state = key_state_0; //按键已释放,转换到按键初始态
        break;
    }
    return key_return;
}

/*=============
中间层按键处理函数,调用低层函数一次,处理双击事件的判断,返回上层正确的无键、单键、双键、长键4个按键事件。
本函数由上层循环调用,间隔10ms
===============*/

unsigned char key_read(void)
{
    static unsigned char key_m = key_state_0, key_time_1 = 0;
    unsigned char key_return = N_key,key_temp;
     
    key_temp = key_driver();
     
    switch(key_m)
    {
        case key_state_0:
            if (key_temp == S_key )
            {
                 key_time_1 = 0;               // 第1次单击,不返回,到下个状态判断后面是否出现双击
                 key_m = key_state_1;
            }
            else
                 key_return = key_temp;        // 对于无键、长键,返回原事件
            break;

case key_state_1:
            if (key_temp == S_key)             // 又一次单击(间隔肯定<500ms)
            {
                 key_return = D_key;           // 返回双击键事件,回初始状态
                 key_m = key_state_0;
            }
            else                                
            {                                  // 这里500ms内肯定读到的都是无键事件,因为长键>1000ms,在1s前低层返回的都是无键
                 if(++key_time_1 >= 50)
                 {
                      key_return = S_key;      // 500ms内没有再次出现单键事件,返回上一次的单键事件
                      key_m = key_state_0;     // 返回初始状态
                 }
             }
             break;
    }
    return key_return;
}

下面,根据程序分析按键事件的反映时间:
1。对于长键,按下超过1s马上响应,反映最快
2。对于双键,第2次按键释放后马上得到反映。
3。对于单键,释放后延时拖后500ms才能响应,反映最慢。这个与需要判断后面是否有双击操作有关,只能这样。实际应用中,可以调整两次单击间隔时间定义,比如为300ms,这样单击的响应回快一点,单按键操作人员需要加快按键的操作过程。如果产品是针对老年人的,这个时间不易太短,因为年纪大的人,反映和动作都比较慢。

当然,上面两段可以合在一起。我这样做的目的,是为了可以方便的扩展为N击(当然,需要做修改)。可是最底层的就是最基本的操作处理短按和长按,不用改动的。至于双击,还是N击,在中间层处理。这就是程序设计中分层结构的优点。

测试代码环境如下:

interrupt [TIM0_COMP] void timer0_comp_isr(void)       // 定时器10ms中断服务
{
       time_10ms_ok = 1;
}

main(viod)  
{  
    .........

while  
    {  
        if (time_10ms_ok)            //每10ms执行一次,  
        {  
             time_10ms_ok =0;  
             key = key_read();       //《====== 10ms一次调用按键中间层函数,根据返回键值,点亮不同的LED灯,全面测试按键操作是否正常  
             if (key == L_key)  
                 ........//点亮A_LED,关闭B_LED和C_LED  
             else if(key == D_key)  
                 ........//点亮B_LED,关闭A_LED和C_LED  
             else if(key == S_key)  
                 ........//点亮C_LED,关闭A_LED和B_LED  
         }  
     }  
}

(4)

https://blog.csdn.net/su_fei_ma_su/article/details/105091193?utm_medium=distribute.pc_relevant.none-task-blog-title-11&spm=1001.2101.3001.4242

(5)51单片机学习笔记:基于状态机的按键对时程序(短按,长按,连发)

4个独立按键中用到3个,

keys5用于切换对时分秒等状态,keys2是减小数值,keys3是增加数值

同时可以判断按键的"短按,长按,连发"等功能

小于2秒视为短按,

大于2秒视为长按,

在长按状态下每0.2秒自动连发一次, 这样对时的时候就不用按N次了

欢迎一起交流,qq 102351263   验证码 iteye

程序分很多个文件 ,Keil uVision4 打包

#include "MY51.H"
#include "keyScan.h"
#include "smg.h"
#include "myClock.h"void show();   //数码管显示extern s8  shi;
extern s8  fen;
extern s8  miao;
extern u8  changeTimeFlag;
extern u8  timeMultipleFlag;void main()
{startT0(10,100);  //开T0启定时器     10毫秒*100=1秒while(1){show();       }
}void T0_Work()  //T0定时器调用的工作函数
{u8 key_stateValue;u8* pKeyValue;*pKeyValue=0;key_stateValue=read_key(pKeyValue);if(timeMultipleFlag)  //到1秒了{timeMultipleFlag=0;     //标志清零clock();          //走时,秒++}if( (return_keyPressed==key_stateValue)&&(*pKeyValue==KEYS5_VALUE) ){      //短按keyS5时改变对时状态changeTimeState(); //改变changeTimeFlag的3种状态,分别修改时或分或秒}if((return_keyPressed==key_stateValue)||(key_stateValue&return_keyAuto) ){    //短按s2或s3可加减响应数值,长按keyS2或keyS3时每0.1秒加减一次数值if(changeTimeFlag)                //changeTimeFlag不为0时,允许修改{if(KEYS2_VALUE == *pKeyValue){changeTime(TRUE);    //KEYS2,秒++}if(KEYS3_VALUE == *pKeyValue){changeTime(FALSE);    //KEYS3,秒--}}}
}void show()  //显示时钟
{u8 oneWela,twoWela,threeWela,foreWela,fiveWela,sixWela; //oneWela是最左边的数码管sixWela =miao%10;fiveWela=miao/10;  foreWela=fen%10;threeWela=fen/10;twoWela=shi%10;oneWela=shi/10;displaySMG(oneWela,twoWela,threeWela,foreWela,fiveWela,sixWela,0xf5); //0xf5是小数点的位置
}
#ifndef _MY51_H
#define _MY51_H
#include <reg52.h>
#include <math.h>
#include <intrins.h>
#include "mytype.h"#define high   1   //高电平
#define low     0   //低电平#define led P1     //灯总线控制
sbit led0=P1^0;     //8个led灯,阴极送低电平点亮
sbit led1=P1^1;
sbit led2=P1^2;
sbit led3=P1^3;
sbit led4=P1^4;
sbit led5=P1^5;
sbit led6=P1^6;
sbit led7=P1^7;sbit lcdEN=P3^4;   //液晶通讯使能端en,高脉冲有效
sbit lcdRS=P3^5;   //液晶第4脚,RS,低电平是指令模式,高电平是数据模式
//sbit lcdR/W       //液晶第5脚,低电平是写入模式,因为我们只写不读,所以接地sbit csda=P3^2;      //DAC0832模数转换cs口
sbit adwr=P3^6;    //ADC0804这个同DAC0832
sbit dawr=P3^6;
sbit adrd=P3^7;    //ADC0804
sbit beep=P2^3;     //蜂鸣器void delayms(u16 ms);
void T0_Work();
void startT0(u32 ms,u16 t_multiple);
////#endif
#include "MY51.h"u8   TH0Cout=0 ;      //初值
u8   TL0Cout=0 ;
u16  T0IntCout=0;       //中断计数
u16  timeMultiple=0;     //中断复用时间的倍数
u8   timeMultipleFlag=0; //中断时间复用置位标志void delayms(u16 ms)     //软延时函数
{u16 i,j;for(i=ms;i>0;i--){for(j=113;j>0;j--){}}
}//开启定时器,定时完成后需要手动关闭TR0,否则将循环定时
//参数一是定时的毫秒数,参数二是定时的倍率数(定时复用)
void startT0(u32 ms,u16 t_multiple)      //定时器初始化设定
{   u32   N=11059.2*ms/12;                  //定时器总计数值TH0Cout =(65536-N)/256;               //装入计时值零头计数初值TL0Cout =(65536-N)%256;timeMultiple=t_multiple;TMOD=TMOD | 0x01;                    //设置定时器0的工作方式为1EA =OPEN;          //打开总中断ET0=OPEN;           //打开定时器中断TH0=TH0Cout;          //定时器装入初值TL0=TL0Cout;TR0=START;           //启动定时器
}/*  方法二,此方法用于长时间的定时,以利于减少中断次数,减小误差
void startT0(u32 one_ms,u16 two_multiple)
{   u32         N=11059.2*one_ms/12;       //定时器总计数值TH0Cout =(65536-N%65536)/256;             //装入计时值零头计数初值TL0Cout =(65536-N%65536)%256;T0IntCountAll=(N-1)/65536+1;            //总中断次数T0IntCountAll2=T0IntCountAll*two_multiple;TMOD=TMOD | 0x01;                        //设置定时器0的工作方式为1EA =OPEN;   //打开总中断ET0=OPEN;   //打开定时器中断TH0=TH0Cout;  //定时器装入初值TL0=TL0Cout;TR0=START;   //启动定时器
}*/void T0_times() interrupt 1 //T0定时器中断函数
{TH0=TH0Cout;      TL0=TL0Cout;T0IntCout++;if(T0IntCout==timeMultiple)  //复用定时器{  T0IntCout=0;            //中断次数清零,重新计时timeMultipleFlag=1;}T0_Work();                   //调用工作函数
}
#ifndef   _MYTYPE_H
#define   _MYTYPE_H/typedef float                             f32   ;
typedef double                        d64  ;
typedef float  const                   fc32 ;
typedef double  const               dc64  ;
typedef volatile float                vf32   ;
typedef volatile double             vd64  ;
//typedef volatile float     const   vfc32   ;
//typedef volatile double  const   vdc64  ;
//typedef signed long  s32;
typedef signed short s16;
typedef signed char   s8;typedef signed long  const sc32;  /* Read Only */
typedef signed short const sc16;  /* Read Only */
typedef signed char  const sc8;   /* Read Only */typedef volatile signed long  vs32;
typedef volatile signed short vs16;
typedef volatile signed char  vs8;//typedef volatile signed long  const vsc32;  /* Read Only */
//typedef volatile signed short const vsc16;  /* Read Only */
//typedef volatile signed char  const vsc8;   /* Read Only */typedef unsigned long  u32;
typedef unsigned short u16;
typedef unsigned char  u8;typedef unsigned long  const uc32;  /* Read Only */
typedef unsigned short const uc16;  /* Read Only */
typedef unsigned char  const uc8;   /* Read Only */typedef volatile unsigned long  vu32;
typedef volatile unsigned short vu16;
typedef volatile unsigned char  vu8;//typedef volatile unsigned long  const vuc32;  /* Read Only */
//typedef volatile unsigned short const vuc16;  /* Read Only */
//typedef volatile unsigned char  const vuc8;   /* Read Only */typedef enum {FALSE = 0, TRUE = !FALSE} bool;typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;typedef enum {CLOSE = 0, OPEN = !CLOSE} OPEN_CLOSE;
typedef enum {GND = 0, VCC = !GND} GND_VCC;
typedef enum {NO = 0, YES = !NO} YES_NO;
typedef enum {STOP = 0, START = !STOP} START_STOP;#define U8_MAX     ((u8)255)
#define S8_MAX     ((s8)127)
#define S8_MIN     ((s8)-128)
#define U16_MAX    ((u16)65535u)
#define S16_MAX    ((s16)32767)
#define S16_MIN    ((s16)-32768)
#define U32_MAX    ((u32)4294967295uL)
#define S32_MAX    ((s32)2147483647)
#define S32_MIN    ((s32)-2147483648)#endif
#ifndef _KEYSACN_H
#define _KEYSACN_H
#include <reg52.h>
#include "mytype.h"#define state_keyUp         0       //初始状态,未按键
#define state_keyDown       1       //键被按下
#define state_keyLong       2       //长按
#define state_keyTime       3       //按键计时态#define return_keyUp        0x00    //初始状态
#define return_keyPressed   0x01    //键被按过,普通按键
#define return_keyLong      0x02    //长按
#define return_keyAuto      0x04    //自动连发#define key_down             0      //按下
#define key_up              0xf0    //未按时的key有效位键值
#define key_longTimes       200     //10ms一次,200次即2秒,定义长按的判定时间
#define key_autoTimes       20      //连发时间定义,20*10=200,200毫秒发一次sbit keyS2=P3^4;   //4个独立按键
sbit keyS3=P3^5;
sbit keyS4=P3^6;
sbit keyS5=P3^7;#define KEYS2_VALUE              0xe0             //keyS2 按下
#define KEYS3_VALUE              0xd0              //keyS3 按下
#define KEYS4_VALUE              0xb0              //keyS4 按下
#define KEYS5_VALUE              0x70              //keyS5 按下//void KeyInit(void);        //初始化,io口未复用时可省略此步
static u8 getKey(void);      //获取P口的连接key的io值,其他io位屏蔽为0
u8 read_key(u8* pKeyValue);  //返回按键的各种状态,pKeyValue保存键值#endif
#include "keyScan.h"
#include <reg52.h>/*按键初始化,若io没有复用的话可以省略此步骤
void KeyInit(void)
{ keyS2 = 1 ; keyS3 = 1 ; keyS4 = 1 ; keyS5 = 1 ;//即P3|=0xf0;
}*/static u8 getKey(void)          //获取P3口值
{ if(key_down == keyS2){return KEYS2_VALUE ; }if(key_down == keyS3 ){return KEYS3_VALUE ; }if(key_down == keyS4 ){return KEYS4_VALUE ;}if(key_down == keyS5 ){return KEYS5_VALUE ; }return key_up ;    //0xf0  没有任何按键
}//函数每10ms被调用一次,而我们弹性按键过程时一般都20ms以上
//所以每次按键至少调用本函数2次
u8 read_key(u8* pKeyValue)
{static u8  s_u8keyState=0;        //未按,普通短按,长按,连发等状态static u16 s_u16keyTimeCounts=0;  //在计时状态的计数器static u8  s_u8LastKey = key_up ; //保存按键释放时的P3口数据u8 keyTemp=0;                  //键对应io口的电平s8 key_return=0;            //函数返回值keyTemp=key_up & getKey();  //提取所有的key对应的io口switch(s_u8keyState)           //这里检测到的是先前的状态{case state_keyUp:   //如果先前是初始态,即无动作{if(key_up!=keyTemp) //如果键被按下{s_u8keyState=state_keyDown; //更新键的状态,普通被按下 }}break;case state_keyDown: //如果先前是被按着的{if(key_up!=keyTemp) //如果现在还被按着{s_u8keyState=state_keyTime; //转换到计时态s_u16keyTimeCounts=0;s_u8LastKey = keyTemp;     //保存键值}else{s_u8keyState=state_keyUp; //键没被按着,回初始态,说明是干扰}}break;case state_keyTime:  //如果先前已经转换到计时态(值为3){  //如果真的是手动按键,必然进入本代码块,并且会多次进入if(key_up==keyTemp) //如果未按键{s_u8keyState=state_keyUp; key_return=return_keyPressed;    //返回1,一次完整的普通按键//程序进入这个语句块,说明已经有2次以上10ms的中断,等于已经消抖//那么此时检测到按键被释放,说明是一次普通短按}else  //在计时态,检测到键还被按着{if(++s_u16keyTimeCounts>key_longTimes) //时间达到2秒{s_u8keyState=state_keyLong;  //进入长按状态s_u16keyTimeCounts=0;         //计数器清空,便于进入连发重新计数key_return=return_keyLong;   //返回state_keyLong}//代码中,在2秒内如果我们一直按着key的话,返回值只会是0,不会识别为短按或长按的}}break;case state_keyLong:  //在长按状态检测连发  ,每0.2秒发一次{if(key_up==keyTemp) {s_u8keyState=state_keyUp; }else //按键时间超过2秒时{if(++s_u16keyTimeCounts>key_autoTimes)//10*20=200ms{s_u16keyTimeCounts=0;key_return=return_keyAuto;  //每0.2秒返回值的第2位置位(1<<2)}//连发的时候,肯定也伴随着长按}key_return |= return_keyLong;  //0x02是肯定的,0x04|0x02是可能的}break;default:break;}*pKeyValue = s_u8LastKey ; //返回键值return key_return;
}
#ifndef _51SMG_H_
#define _51SMG_H_#include <reg52.h>
#include "mytype.h"
sbit dula =P2^6;       //段选锁存器控制  控制笔段
sbit wela =P2^7;       //位选锁存器控制  控制位置#define dark 0x11    //在段中,0x11是第17号元素,为0是低电平,数码管不亮
#define dotDark 0xff    //小数点全暗时void displaySMG(u8 one,u8 two,u8 three,u8 four,u8 five,u8 six,u8 dot);  //数码管显示函数#endif
#include "smg.h"
#include "my51.h"u8 code table[]= {          //0~F外加小数点和空输出的数码管编码0x3f , 0x06 , 0x5b , 0x4f , // 0 1 2 30x66 , 0x6d , 0x7d , 0x07 , // 4 5 6 70x7f , 0x6f , 0x77 , 0x7c , // 8 9 A B0x39 , 0x5e , 0x79 , 0x71 , // C D E F0x80 , 0x00 ,0x40           // . 空  负号    空时是第0x11号也就是第17号元素};u8 code dotTable[]={        //小数点位置0xff ,                 //全暗0xfe , 0xfd , 0xfb ,   //1 2 30xf7 , 0xef , 0xdf     //4 5 6
};//数码管显示
void displaySMG(u8 oneWela,u8 twoWela,u8 threeWela,u8 fourWela,u8 fiveWela,u8 sixWela,u8 dot)
{   //控制6位数码管显示函数,不显示的位用参数dark,保留ADC0804的片选信号u8 csadState=0x80&P0;                 //提取最高位,即ADC0804的片选信号u8 tempP0=((csadState==0)?0x7f:0xff); //数码管位选初始信号,阴极全置高电平P0=tempP0;        //0x7f表示数码管不亮,同时ADC0804片选有效wela=1;         //注:wela和dula上电默认为1P0=tempP0;wela=0;P0=0;                //由于数码管是共阴极的,阳极送低电平,灯不亮,防止灯误亮dula=1;P0=0;dula=0;             //段选数据清空并锁定
//oneWela{  //消除叠影,数码管阴极置高电平,并锁存P0=tempP0;wela=1;         P0=tempP0;wela=0;}P0=0;          //低电平送到数码管阳极,避免数码管误亮dula=1;P0=table[oneWela]|((0x01&dot)?0x00:0x80);   //送段数据,叠加小数点的显示dula=0;P0=tempP0;          //送位数据前关闭所有显示,并保持csad信号wela=1;P0=tempP0 & 0xfe;   //0111 1110最高位是AD片选,低6位是数码管位选,低电平有效wela=0;delayms(1);/twoWela{  //消除叠影P0=tempP0;wela=1;         P0=tempP0;wela=0;}P0=0;dula=1;P0=table[twoWela]|((0x02&dot)?0x00:0x80);dula=0;P0=tempP0;wela=1;P0=tempP0 & 0xfd;    //0111 1101wela=0;delayms(1);/threeWela{  //消除叠影P0=tempP0;wela=1;           P0=tempP0;wela=0;}P0=0;dula=1;P0=table[threeWela]|((0x04&dot)?0x00:0x80);dula=0;P0=tempP0;wela=1;P0=tempP0 & 0xfb;    //0111 1011wela=0;delayms(1);/fourWela{  //消除叠影P0=tempP0;wela=1;          P0=tempP0;wela=0;}P0=0;dula=1;P0=table[fourWela]|((0x08&dot)?0x00:0x80);dula=0;P0=tempP0;wela=1;P0=tempP0 & 0xf7;   //0111 0111wela=0;delayms(1);/fiveWela{  //消除叠影P0=tempP0;wela=1;            P0=tempP0;wela=0;}P0=0;dula=1;P0=table[fiveWela]|((0x10&dot)?0x00:0x80);dula=0;P0=tempP0;wela=1;P0=tempP0 & 0xef;      //0110 1111wela=0;delayms(1);/sixWela{  //消除叠影P0=tempP0;wela=1;          P0=tempP0;wela=0;}P0=0;dula=1;P0=table[sixWela]|((0x20&dot)?0x00:0x80);dula=0;P0=tempP0;wela=1;P0=tempP0 & 0xdf;   //0101 1111wela=0;delayms(1);
}
#ifndef        _MYCLOCK_H
#define     _MYCLOCK_H
#include "mytype.h"
#include "my51.h"void clock(void);                    //走时
void changeTimeState(void);         //改变对时状态
void changeTime(bool add_or_sub);   //修改时间,true为增加,false为减少
#endif
#include "myClock.h"u8  changeTimeFlag=0;
s8  shi=22;   //对时
s8  fen=45;
s8  miao=0;
void clock(void)
{if(!changeTimeFlag)   //不在对时状态{miao++;if(miao>59){miao=0;fen++;}if(fen>59){fen=0;shi++;} if(shi>23){shi=0;}}
}void changeTimeState(void)      //在满足条件时改变对时状态,时或分或秒,同时改变指示灯
{changeTimeFlag=(++changeTimeFlag)%4;switch(changeTimeFlag){case 0:{led=0xff;                                  }break;case 1:{led=0xff;led7=0;}break;case 2:{led=0xff;led5=0;}break;case 3:{led=0xff;led3=0;}break;default:break;}
}void changeTime(bool add_or_sub)    //修改时分秒
{if(add_or_sub){switch(changeTimeFlag){case 1:{shi++;if(shi>23){shi=0;}                                      }break;case 2:{fen++;if(fen>59){fen=0;}}break;case 3:{miao++;if(miao>59){miao=0;}}break;default:break;}}else{switch(changeTimeFlag){case 1:{shi--;if(shi<0) {shi=23;}                                       }break;case 2:{fen--;if(fen<0){fen=59;}}break;case 3:{miao--;if(miao<0){miao=59;}}break;default:break;}  }
}

按键短按、长按,双击相关推荐

  1. 按键短按长按连发双击

    功能:实现按键 长按 短按 连发 双击 处理 平台:GD32 用到的外设:GPIO.定时器 作者:霍宏鹏 交流:1045338804@qq.com /************************* ...

  2. STM32超级简便的按键代码 只需三行 可实现短按+长按

    [蓝桥杯]STM32三行按键详解 长按 短按 用的是国信长天的嵌入式方向的开发板,使用的芯片是STM32F103RBT6,基于stm32f1的固件库编程. 当初写下这篇博客的本意也是让自己的知识更加巩 ...

  3. STM32-蓝桥杯嵌入式之三行按键检测(按键的长、短,单击、双击)

    STM32-蓝桥杯嵌入式之三行按键检测(按键的长.短,单击.双击) 目录 STM32-蓝桥杯嵌入式之三行按键检测(按键的长.短,单击.双击) 一.检测按键下降沿分析 二.检测按键上升沿分析 三.按键检 ...

  4. 51单片机——矩阵按键逐行扫描短按长按一直按方案1.2

    1.删减了<51单片机--独立按键.矩阵按键多种方案1.1>里的一些不怎么用的代码. 2.添加了逐行扫描按键(需要定时器20毫秒配合使用). 3.支持按键短按.长按.一直按,代码里只做了短 ...

  5. stm32f407zgt6的KEY实例:长按键+短按键(查询方法,非中断)+LCD显示

    1.实验目的 按键key.h 按键key.c 的理解和使用,修改 使用查询方式进行判断按键 返回按键长按的数值,和短按的数值 2.实验理论 短按和长按 按下- 判断是不是等于0 ----延时去抖动 - ...

  6. 51单片机学习笔记:基于状态机的按键对时程序(短按,长按,连发)

    之前的电子钟程序中,用的按键消抖处理方法是10ms的延时,这种方法效率比较低 所以现在利用状态机原理重写一下,效率很高啊 4个独立按键中用到3个, keys5用于切换对时分秒等状态,keys2是减小数 ...

  7. 单片机按键检测程序c语言,单片机检测按键短击,连击c程序

    /****************************************************************************/ //文 件 名:key.c //功 能:短 ...

  8. [Android开发] 从后台恢复前台界面需要输入密码的demo|监听Home短按长按锁屏

    一.效果图 二.实现原理 通过接收系统广播来判断home按键,广播Application全局,在接收到广播的时候在BaseActivity的onStop里面打开输入密码的对话框,再次回到界面就已经是显 ...

  9. 【按键】[独立按键] - 1: 单击,双击,三击以及N击

    此按键程序的实现的功能是单个独立按键的[单击],[长按],[双击],[三击]以及[多击].本文分为三个部分, 第一个部分是说[单击],[长按]的程序: 第二部分是讲[双击]: 第三部分是讲[三击],[ ...

  10. LeetCode简单题之按键持续时间最长的键

    题目 LeetCode 设计了一款新式键盘,正在测试其可用性.测试人员将会点击一系列键(总计 n 个),每次一个. 给你一个长度为 n 的字符串 keysPressed ,其中 keysPressed ...

最新文章

  1. Spring集成Redis方案(spring-data-redis)(基于Jedis的单机模式)(待实践)
  2. Class.forName 和 ClassLoader 到底有啥区别?
  3. 一起玩树莓派3+手把手带您入门树莓派(3000字+超详细图解版)
  4. Windows下配置IDEA开发环境
  5. RandomizedSearchCV 和GridSearchCV
  6. [詹兴致矩阵论习题参考解答]习题1.3
  7. SQL ROW_NUMBER() OVER函数的基本用法用法
  8. java 子类必须实现_Java学习之接口的子类必须实现接口的全部方法吗?
  9. python 选择文件对话框插件_[ PyQt入门教程 ] PyQt5基本控件使用:消息弹出、用户输入、文件/目录选择对话框...
  10. java报错信息怎么看_AE-E3D插件无效或提示OPENGL E3D Debug等错误报错信息怎么办?...
  11. Python学习——编码转换
  12. java可选参数_Java可选
  13. invocation, 作者 Medwyn Goodall,女巫医 [搜索 invocation Medwyn Goodall]
  14. 多元统计分析matlab,matlab与应用多元统计分析..doc
  15. 【找规律】求123456789的第几个全排列
  16. Centos Linux破解开机密码
  17. 4484: [Jsoi2015]最小表示(拓扑序+bitset维护连通性)
  18. 微信小程序刷新当前页面
  19. EasyCVR出现只有HLS协议可播放,其他协议均无法播放是什么原因?
  20. Sql Server 时间格式转换

热门文章

  1. Django基础(16): 模板标签(tags)的介绍及如何自定义模板标签
  2. mysql查看cpu使用率_MySQL高CPU使用率
  3. 12306崩了,90%的人都用过这三款抢票工具
  4. 山重水复疑无路 柳暗花明又一村
  5. 如何让Bing快速收录你的网站?
  6. 【线性代数(6)】范德蒙德行列式及克莱姆法则
  7. 情境领导者的三体思维
  8. 将文件夹压缩成zip文件的php代码、实现批量下载
  9. unbuntu 安装vscode
  10. xampp运行不成功或者安装过程中提示找不到文件“-n”,没有安装vcredist_x86的解决方法