/************************************************************************************************************************** |
建立头文件"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; |
|
} |