[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;
}