当前位置:   article > 正文

按键短按、长按,双击_按键的双击和三击检测代码

按键的双击和三击检测代码
整理的网上按键短按、长按,双击的关键代码和思路
 
(1)
 
 
#include "Key_Board.h"
  1.  
     
  2.  
    /*记录按键按下时间 时间小于1.5S,按键为短按;时间大于1.5S,按键为长按*/
  3.  
    volatile unsigned int key1_timing = 0;
  4.  
     
  5.  
    /*记录两次短按之间的时间间隔*/
  6.  
    volatile unsigned int key1_doublepress_timing = 0;
  7.  
     
  8.  
    /*定义按键键值结构体*/
  9.  
    Key_Value k1_value;
  10.  
     
  11.  
    /*K1按键短按标志位*/
  12.  
    bool k1_shortpress_happen = 0;
  13.  
     
  14.  
    /*K1按键长按标志位*/
  15.  
    bool k1_longpress_happen = 0;
  16.  
     
  17.  
    /*K1按键双击标志位*/
  18.  
    bool k1_doublepress_happen = 0;
  19.  
     
  20.  
    /*led1闪烁时间标志位,主函数检测到此标志位为1时,led1开始闪烁,否则,结束闪烁*/
  21.  
    bool led1_flash_flag = 0;
  22.  
     
  23.  
    /*3个led全部闪烁标志位,主函数检测到此标志为1时,三个led灯开始同时闪烁,否则结束闪烁*/
  24.  
    bool led_all_flash_flag = 0;
  25.  
     
  26.  
    /*流水灯事件标志位*/
  27.  
  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.  
     
  8.  
    if(K1==0//当K1按键按下
  9.  
    {
  10.  
    if(k1_shortpress_happen==0)
  11.  
    {
  12.  
    k1_shortpress_happen = 1//开始一次按键键值扫描
  13.  
    key1_timing = 0//按键按下计时变量清0,开始计时,此值每1ms加1,sysclk中断函数中实现自加
  14.  
    }
  15.  
     
  16.  
    if(k1_shortpress_happen==1)
  17.  
    {
  18.  
    if(key1_timing > 1500//按键按下时间超过1.5S,长按事件发生,置k1_value.long_press为1
  19.  
    {
  20.  
    k1_value.long_press = 1;
  21.  
    k1_shortpress_happen = 0//按键短按标志位置0
  22.  
    }
  23.  
    }
  24.  
    }
  25.  
     
  26.  
    if(K1==1//当K1按键抬起
  27.  
    {
  28.  
    if(k1_shortpress_happen==1//按键抬起后,k1_shortpress_happen等于1,说明按键为短按,不是长按
  29.  
    {
  30.  
    k1_shortpress_happen = 0
  31.  
    if(k1_doublepress_happen==0)
  32.  
    {
  33.  
    k1_doublepress_happen = 1//按键双击标志位置1,等待确认按键是否为双击
  34.  
    key1_doublepress_timing = 0//开始计时,同样1ms自增加1
  35.  
    }
  36.  
    else
  37.  
    {
  38.  
    if(key1_doublepress_timing < 500//第一次短按发生后,在500ms时间内,发生第二次短按,完成一次双击,跟新按键键值
  39.  
    {
  40.  
    k1_doublepress_happen = 0;
  41.  
    k1_value.double_press = 1;
  42.  
    }
  43.  
    }
  44.  
    }
  45.  
    else
  46.  
    if(k1_doublepress_happen == 1//第一次短按后,等待500ms,如未再发生短按,跟新按键短按键值
  47.  
    {
  48.  
    if(key1_doublepress_timing > 500)
  49.  
    {
  50.  
    k1_doublepress_happen = 0;
  51.  
    k1_value.short_press = 1;
  52.  
    }
  53.  
    }
  54.  
    else
  55.  
    if(k1_longpress_happen==1)
  56.  
    k1_longpress_happen = 0;
  57.  
    }
  58.  
    }
(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)

 

 

题目:多功能按键设计。利用一个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的工作方式为1
	
	EA =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的工作方式为1
	
	EA =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 3
	0x66 , 0x6d , 0x7d , 0x07 , // 4 5 6 7
	0x7f , 0x6f , 0x77 , 0x7c , // 8 9 A B
	0x39 , 0x5e , 0x79 , 0x71 , // C D E F
	0x80 , 0x00 ,0x40           // . 空  负号    空时是第0x11号也就是第17号元素
 };

u8 code dotTable[]={		   //小数点位置
    0xff ,                 //全暗
	0xfe , 0xfd , 0xfb ,   //1 2 3
	0xf7 , 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上电默认为1
    P0=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 1101
    wela=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 1011
    wela=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 0111
    wela=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 1111
    wela=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 1111
    wela=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;
	    }	
	}
}
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/527054
推荐阅读
相关标签
  

闽ICP备14008679号