用户注册



邮箱:

密码:

用户登录


邮箱:

密码:
记住登录一个月忘记密码?

发表随想


还能输入:200字
云代码 - c代码库

按键扫描

2016-06-25 作者: stopshooting举报

[c]代码库

/**************************************************************************************************************************
建立头文件"key.h"
**************************************************************************************************************************/

#ifndef __KEY_H
#define __KEY_H

#include "stm8_macro.h"

/*
                       说      明:
  1.按事件  :按键按下时即产生一次按事件;
  2.长按事件:按下时间超过(最短长按时间)即产生长按事件,任何一次出现的长按操作都属于
              长按事件;长按时,会一直产生长按事件直至长按结束,且每秒更新一次长按事件,
              每秒产生的长按事件不一样。
  3.短按事件:在(最短长按时间)内按下松开之后,在接下来的(最大双击间隔时间)内若没有第二
              次短按操作即产生一次短按事件;
  4.双击事件:2次短按操作间隔时间<(最大双击间隔时间),则2次短按操作为1次双击事件,
              且2次短按都取消。

特别操作情况定义: 
  1.短按操作和长按操作间隔<(最大双击间隔时间),以及,长按操作和短按操作间隔<(最大双击间隔时间),均不产生双击事件;
  2.(最大双击间隔时间)内,连续n次短按操作,最多只产生1次双击事件和n次按事件
*/

//////////////////////// 参数配置 ////////////////////////

//长按识别的最大时间,单位:秒,若长按超过这个时间,则输出此时间
#define LONGKEY_RECOGNITION_MAXTIME  (30ul)

//////////////////////////////////////////////////////////

#if LONGKEY_RECOGNITION_MAXTIME >= (256 - 10)
  #error "LONGKEY_RECOGNITION_MAXTIME is too large!"
#endif


//按键事件
#define KEY_NOKEY        ((u8)0)    //无
#define KEY_DOWN         ((u8)1)    //按事件,  按键按下时即产生一次按事件
#define KEY_SHORT        ((u8)2)    //短按事件,
#define KEY_DOUBLECLICK  ((u8)3)    //双击事件
#define KEY_LONG_S(n)    ((u8)10+n) //长按事件,按下超过(n)秒

//Input Attribute
typedef struct {
  vu8 (*IsPress)(void);  //是否按下按键,输出当前按键状态 1:按下  0:未按下
  vu16 LongPressTime;    //最短长按时间,按下时间>LongPressTime,表示长按,单位MS
  vu16 DCIntervalTime;	 //最大双击间隔时间,双击时,两次短按之间的最长间隔时间,单位MS
} KeyAttr_TypeDef;

//Ouput key status
typedef struct {
  vu8 KeyEvent; //按键事件,KEY_NOKEY,KEY_DOWN,KEY_SHORT,KEY_DOUBLECLICK,KEY_LONG_S(n)
  vu8 Busy;		//忙状态,0:空闲,1:忙,当按键按下及短按后的DCIntervalTime时间内为忙状态
} KeyStat_TypeDef;

//按键控制块
typedef struct {
  KeyAttr_TypeDef Attr;  //Input Attribute, 配置按键属性
  KeyStat_TypeDef Status;//Ouput key status,输出按键状态:事件/闲忙
} Key_TypeDef;

void Key_Init(Key_TypeDef* key,  u8 (*input)(void), u16 longpresstime, u16 dcitvtime);
KeyStat_TypeDef GetKeyStatus(Key_TypeDef *key_structure);

#endif /*__KEY_H*/



/**************************************************************************************************************************
建立源文件"key.c"
**************************************************************************************************************************/

#include "key.h"

//----------------------------------------------------------------
/******** 驱动层 ********/

/*
 @Function : 按键的初始化
 @Input    : key           按键控制块
             input         按键状态     1:按下按键 0:未按下按键
             longpresstime 最短长按时间,按下时间>longpresstime,表示长按,单位MS
             dcitvtime	  最大双击间隔时间(双击时,两次短按之间的最长间隔时间),单位MS
 @Output   : None
 **/
void Key_Init(
  Key_TypeDef* key,  //按键控制块
  u8 (*input)(void), //按键状态 
  u16 longpresstime,  //最短长按时间
  u16 dcitvtime)      //最大双击间隔时间
{
	key->Attr.IsPress = input;
	key->Attr.LongPressTime = longpresstime; //最短长按时间 ms
	key->Attr.DCIntervalTime = dcitvtime;     //双击最长间隔时间 ms

	key->Status.KeyEvent = KEY_NOKEY;
	key->Status.Busy = 0;
}

/*
 @Function : 按键扫描(10MS扫描一次)
 @Input    : key_input          当前按键状态,是否按下按键 0:未按下,1:按下
             longpresstime      按键超过该时间为长按,单位ms
 @Output   : 0 KEY_NOKEY        无
             1 KEY_DOWN         按下按键瞬间
             2 KEY_SHORT        短按,按下放开,1次短按操作后,间隔0.5s内没有短按操作 
             n>10               长按,按下超过(n-10)秒
 **/
static u8 Key_driver(u8 key_input, u16 longpresstime)
{
	u8 res = KEY_NOKEY;
	static u8  status;
	static u16 keypress_count;

	switch(status)
	{
		case 0:  //确定按键是否按下
			if(key_input)
			{
				status = 1;
				keypress_count = 0;
			}
			break;
		case 1:  //消斗
			if(key_input)
			{
				status = 2;
				res = KEY_DOWN;
			}
			else
			{
				status = 0;
			}
			break;
		case 2:
			if(!key_input)
			{
				res = KEY_SHORT;
				status = 0;
			}
  			else if(++keypress_count >= longpresstime/10)
			{
				res = KEY_LONG_S(1);//按下超过1s
				status = 3;
			}
			break;
		case 3:
			++keypress_count;
			if(keypress_count/100 >= LONGKEY_RECOGNITION_MAXTIME)//按下超过30s
			{
				res = 10 + LONGKEY_RECOGNITION_MAXTIME;
			}
			else
			{
				res = (u8)(10 + (u8)(keypress_count/100));//按下超过(keypress_count/100)秒
			}
			
			if(!key_input)
			{
				status = 0;
			}
			break;
	}
	return res;
}

/*
 @Function : 按键扫描(10MS扫描一次),并将按键的状态记录下来
 @Input    : keyattr            按键属性
 @Output   : 按键状态
 **/
KeyStat_TypeDef GetKeyStatus(Key_TypeDef *key_structure)
{
	static u8  status;
	static u16 key_count;
	u8  key_temp;
	u8  input;
	u16 longpresstime, intervaltime;
	u8  keyevent = KEY_NOKEY;
	u8  busy = 0;
	KeyStat_TypeDef res;

	input         = key_structure->Attr.IsPress();
	longpresstime = key_structure->Attr.LongPressTime;
	intervaltime  = key_structure->Attr.DCIntervalTime;
	
	key_temp = Key_driver(input, longpresstime);

	//双击判别
	switch(status)
	{
		case 0:
			if(key_temp == KEY_SHORT)//检测到第一次短按
			{
				key_count = 0;
				status = 1;
			}
			else
			{
				keyevent = key_temp;//返回原事件
			}
			break;
		case 1:
			if(++key_count < intervaltime/10)//双击最大间隔时间内
			{
				if(key_temp == KEY_SHORT)//检测到第二次短按,返回双击事件
				{
					status = 2;
					keyevent = KEY_DOUBLECLICK;
				}
				else
				{
					keyevent = key_temp;//返回原事件
				}
			}
			else
			{
				status = 0;
				keyevent = KEY_SHORT;
			}
			break;
		case 2:
			//双击最大间隔时间内,连续N次短按,只算一次双击时间
			if(++key_count < intervaltime/10)
			{
				if(key_temp != KEY_SHORT)
				{
					keyevent = key_temp;
				}
			}
			else
			{
				status = 0;
			}
			break;
	}

	//更新忙状态
	if(keyevent != KEY_NOKEY || status != 0)
	{
		busy = 1;
	}

	//output
	key_structure->Status.KeyEvent = keyevent;
	key_structure->Status.Busy     = busy;
	res.Busy     = busy;
	res.KeyEvent = keyevent;

	return res;
	
}





网友评论    (发表评论)


发表评论:

评论须知:

  • 1、评论每次加2分,每天上限为30;
  • 2、请文明用语,共同创建干净的技术交流环境;
  • 3、若被发现提交非法信息,评论将会被删除,并且给予扣分处理,严重者给予封号处理;
  • 4、请勿发布广告信息或其他无关评论,否则将会删除评论并扣分,严重者给予封号处理。


扫码下载

加载中,请稍后...

输入口令后可复制整站源码

加载中,请稍后...