[C] 按键扫描 →→→→→进入此内容的聊天室

来自 , 2019-11-01, 写在 C, 查看 149 次.
URL http://www.code666.cn/view/b1301141
  1. /**************************************************************************************************************************
  2. 建立头文件"key.h"
  3. **************************************************************************************************************************/
  4.  
  5. #ifndef __KEY_H
  6. #define __KEY_H
  7.  
  8. #include "stm8_macro.h"
  9.  
  10. /*
  11.                        说      明:
  12.   1.按事件  :按键按下时即产生一次按事件;
  13.   2.长按事件:按下时间超过(最短长按时间)即产生长按事件,任何一次出现的长按操作都属于
  14.               长按事件;长按时,会一直产生长按事件直至长按结束,且每秒更新一次长按事件,
  15.               每秒产生的长按事件不一样。
  16.   3.短按事件:在(最短长按时间)内按下松开之后,在接下来的(最大双击间隔时间)内若没有第二
  17.               次短按操作即产生一次短按事件;
  18.   4.双击事件:2次短按操作间隔时间<(最大双击间隔时间),则2次短按操作为1次双击事件,
  19.               且2次短按都取消。
  20.  
  21. 特别操作情况定义:
  22.   1.短按操作和长按操作间隔<(最大双击间隔时间),以及,长按操作和短按操作间隔<(最大双击间隔时间),均不产生双击事件;
  23.   2.(最大双击间隔时间)内,连续n次短按操作,最多只产生1次双击事件和n次按事件
  24. */
  25.  
  26. //////////////////////// 参数配置 ////////////////////////
  27.  
  28. //长按识别的最大时间,单位:秒,若长按超过这个时间,则输出此时间
  29. #define LONGKEY_RECOGNITION_MAXTIME  (30ul)
  30.  
  31. //////////////////////////////////////////////////////////
  32.  
  33. #if LONGKEY_RECOGNITION_MAXTIME >= (256 - 10)
  34.   #error "LONGKEY_RECOGNITION_MAXTIME is too large!"
  35. #endif
  36.  
  37.  
  38. //按键事件
  39. #define KEY_NOKEY        ((u8)0)    //无
  40. #define KEY_DOWN         ((u8)1)    //按事件,  按键按下时即产生一次按事件
  41. #define KEY_SHORT        ((u8)2)    //短按事件,
  42. #define KEY_DOUBLECLICK  ((u8)3)    //双击事件
  43. #define KEY_LONG_S(n)    ((u8)10+n) //长按事件,按下超过(n)秒
  44.  
  45. //Input Attribute
  46. typedef struct {
  47.   vu8 (*IsPress)(void);  //是否按下按键,输出当前按键状态 1:按下  0:未按下
  48.   vu16 LongPressTime;    //最短长按时间,按下时间>LongPressTime,表示长按,单位MS
  49.   vu16 DCIntervalTime;   //最大双击间隔时间,双击时,两次短按之间的最长间隔时间,单位MS
  50. } KeyAttr_TypeDef;
  51.  
  52. //Ouput key status
  53. typedef struct {
  54.   vu8 KeyEvent; //按键事件,KEY_NOKEY,KEY_DOWN,KEY_SHORT,KEY_DOUBLECLICK,KEY_LONG_S(n)
  55.   vu8 Busy;             //忙状态,0:空闲,1:忙,当按键按下及短按后的DCIntervalTime时间内为忙状态
  56. } KeyStat_TypeDef;
  57.  
  58. //按键控制块
  59. typedef struct {
  60.   KeyAttr_TypeDef Attr;  //Input Attribute, 配置按键属性
  61.   KeyStat_TypeDef Status;//Ouput key status,输出按键状态:事件/闲忙
  62. } Key_TypeDef;
  63.  
  64. void Key_Init(Key_TypeDef* key,  u8 (*input)(void), u16 longpresstime, u16 dcitvtime);
  65. KeyStat_TypeDef GetKeyStatus(Key_TypeDef *key_structure);
  66.  
  67. #endif /*__KEY_H*/
  68.  
  69.  
  70.  
  71. /**************************************************************************************************************************
  72. 建立源文件"key.c"
  73. **************************************************************************************************************************/
  74.  
  75. #include "key.h"
  76.  
  77. //----------------------------------------------------------------
  78. /******** 驱动层 ********/
  79.  
  80. /*
  81.  @Function : 按键的初始化
  82.  @Input    : key           按键控制块
  83.              input         按键状态     1:按下按键 0:未按下按键
  84.              longpresstime 最短长按时间,按下时间>longpresstime,表示长按,单位MS
  85.              dcitvtime    最大双击间隔时间(双击时,两次短按之间的最长间隔时间),单位MS
  86.  @Output   : None
  87.  **/
  88. void Key_Init(
  89.   Key_TypeDef* key,  //按键控制块
  90.   u8 (*input)(void), //按键状态
  91.   u16 longpresstime,  //最短长按时间
  92.   u16 dcitvtime)      //最大双击间隔时间
  93. {
  94.         key->Attr.IsPress = input;
  95.         key->Attr.LongPressTime = longpresstime; //最短长按时间 ms
  96.         key->Attr.DCIntervalTime = dcitvtime;     //双击最长间隔时间 ms
  97.  
  98.         key->Status.KeyEvent = KEY_NOKEY;
  99.         key->Status.Busy = 0;
  100. }
  101.  
  102. /*
  103.  @Function : 按键扫描(10MS扫描一次)
  104.  @Input    : key_input          当前按键状态,是否按下按键 0:未按下,1:按下
  105.              longpresstime      按键超过该时间为长按,单位ms
  106.  @Output   : 0 KEY_NOKEY        无
  107.              1 KEY_DOWN         按下按键瞬间
  108.              2 KEY_SHORT        短按,按下放开,1次短按操作后,间隔0.5s内没有短按操作
  109.              n>10               长按,按下超过(n-10)秒
  110.  **/
  111. static u8 Key_driver(u8 key_input, u16 longpresstime)
  112. {
  113.         u8 res = KEY_NOKEY;
  114.         static u8  status;
  115.         static u16 keypress_count;
  116.  
  117.         switch(status)
  118.         {
  119.                 case 0:  //确定按键是否按下
  120.                         if(key_input)
  121.                         {
  122.                                 status = 1;
  123.                                 keypress_count = 0;
  124.                         }
  125.                         break;
  126.                 case 1:  //消斗
  127.                         if(key_input)
  128.                         {
  129.                                 status = 2;
  130.                                 res = KEY_DOWN;
  131.                         }
  132.                         else
  133.                         {
  134.                                 status = 0;
  135.                         }
  136.                         break;
  137.                 case 2:
  138.                         if(!key_input)
  139.                         {
  140.                                 res = KEY_SHORT;
  141.                                 status = 0;
  142.                         }
  143.                         else if(++keypress_count >= longpresstime/10)
  144.                         {
  145.                                 res = KEY_LONG_S(1);//按下超过1s
  146.                                 status = 3;
  147.                         }
  148.                         break;
  149.                 case 3:
  150.                         ++keypress_count;
  151.                         if(keypress_count/100 >= LONGKEY_RECOGNITION_MAXTIME)//按下超过30s
  152.                         {
  153.                                 res = 10 + LONGKEY_RECOGNITION_MAXTIME;
  154.                         }
  155.                         else
  156.                         {
  157.                                 res = (u8)(10 + (u8)(keypress_count/100));//按下超过(keypress_count/100)秒
  158.                         }
  159.                        
  160.                         if(!key_input)
  161.                         {
  162.                                 status = 0;
  163.                         }
  164.                         break;
  165.         }
  166.         return res;
  167. }
  168.  
  169. /*
  170.  @Function : 按键扫描(10MS扫描一次),并将按键的状态记录下来
  171.  @Input    : keyattr            按键属性
  172.  @Output   : 按键状态
  173.  **/
  174. KeyStat_TypeDef GetKeyStatus(Key_TypeDef *key_structure)
  175. {
  176.         static u8  status;
  177.         static u16 key_count;
  178.         u8  key_temp;
  179.         u8  input;
  180.         u16 longpresstime, intervaltime;
  181.         u8  keyevent = KEY_NOKEY;
  182.         u8  busy = 0;
  183.         KeyStat_TypeDef res;
  184.  
  185.         input         = key_structure->Attr.IsPress();
  186.         longpresstime = key_structure->Attr.LongPressTime;
  187.         intervaltime  = key_structure->Attr.DCIntervalTime;
  188.        
  189.         key_temp = Key_driver(input, longpresstime);
  190.  
  191.         //双击判别
  192.         switch(status)
  193.         {
  194.                 case 0:
  195.                         if(key_temp == KEY_SHORT)//检测到第一次短按
  196.                         {
  197.                                 key_count = 0;
  198.                                 status = 1;
  199.                         }
  200.                         else
  201.                         {
  202.                                 keyevent = key_temp;//返回原事件
  203.                         }
  204.                         break;
  205.                 case 1:
  206.                         if(++key_count < intervaltime/10)//双击最大间隔时间内
  207.                         {
  208.                                 if(key_temp == KEY_SHORT)//检测到第二次短按,返回双击事件
  209.                                 {
  210.                                         status = 2;
  211.                                         keyevent = KEY_DOUBLECLICK;
  212.                                 }
  213.                                 else
  214.                                 {
  215.                                         keyevent = key_temp;//返回原事件
  216.                                 }
  217.                         }
  218.                         else
  219.                         {
  220.                                 status = 0;
  221.                                 keyevent = KEY_SHORT;
  222.                         }
  223.                         break;
  224.                 case 2:
  225.                         //双击最大间隔时间内,连续N次短按,只算一次双击时间
  226.                         if(++key_count < intervaltime/10)
  227.                         {
  228.                                 if(key_temp != KEY_SHORT)
  229.                                 {
  230.                                         keyevent = key_temp;
  231.                                 }
  232.                         }
  233.                         else
  234.                         {
  235.                                 status = 0;
  236.                         }
  237.                         break;
  238.         }
  239.  
  240.         //更新忙状态
  241.         if(keyevent != KEY_NOKEY || status != 0)
  242.         {
  243.                 busy = 1;
  244.         }
  245.  
  246.         //output
  247.         key_structure->Status.KeyEvent = keyevent;
  248.         key_structure->Status.Busy     = busy;
  249.         res.Busy     = busy;
  250.         res.KeyEvent = keyevent;
  251.  
  252.         return res;
  253.        
  254. }
  255.  
  256.  
  257.  
  258.  

回复 "按键扫描"

这儿你可以回复上面这条便签

captcha