用户注册



邮箱:

密码:

用户登录


邮箱:

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

发表随想


还能输入: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、请勿发布广告信息或其他无关评论,否则将会删除评论并扣分,严重者给予封号处理。


扫码下载

加载中,请稍后...

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

加载中,请稍后...