单片机按键处理框架

时间:2024-02-24 18:14:08

写过一段时间单片机程序,也看了一些单片机程序,书上的,网上的,基本都是非常原始的读取按键,延时判断,这些按键相关代码穿插于整个程序,着实不够美观,最重要的是不能复用,so俺就想做个按键框架,只需提供按键处理代码即可,言归正传,先简介一下几个文件,ringfifo.c提供了一个简单的环形缓冲队列,用以通知按键消息,key.c 实现的按键的框架处理(读取按键,调用按键处理函数),key_port.c 需提供底层硬件接口及用户的按键处理函数,目前支持的按键消息类型有4类:keyDown,keyRelease,longPress, double click.

key.h中提供了4个函数:InitKey()为初始化, KeyProc() 须在主循环中调用,KeyScan()须定时(10-20ms)调用,SetKeyHandler()用来设置按键处理函数

 1 #ifndef __KEY_H__
 2 #define __KEY_H__
 3 
 4 #define NULL 0
 5 
 6 typedef enum{
 7     KEY_EVENT_DOWN = 0,
 8     KEY_EVENT_UP,
 9     KEY_EVENT_LONGPRESS,
10     KEY_EVENT_DOUBLECLICK,
11     KEY_EVENT_COMBO_KEYDOWN,
12 }KeyEventType;
13 
14 typedef void (*pKeyEventCB)(void *para);
15 
16 typedef struct _tagKeyInfo
17 {
18     unsigned char keyCode;
19     unsigned char keyStatus;
20     unsigned char comboKeyFlag;
21     unsigned int keyDbClickTime;    
22     unsigned int keyDownTime;
23     unsigned int keyRepeatTime;
24     pKeyEventCB FuncCB[5]; 
25     void * para[5];    
26 }KeyInfo;
27 
28 typedef struct _tagMessageInfo
29 {
30     unsigned int keyEvent;
31     unsigned int keyCode;
32     KeyInfo* pContext;
33 }MessageInfo;
34 
35 
36 
37 void InitKey(void);        // 
38 
39 void KeyProc(void);// call this func in main loop
40 
41 void KeyScan(void);    // call it in timer service, 20ms
42 
43 pKeyEventCB SetKeyHandler(unsigned char key,KeyEventType event,pKeyEventCB pFunc,void *para);
44 
45 #endif
key.h
  1 #include "key_port.h"
  2 #include "key.h"
  3 #include "ringfifo.h"
  4 #include <string.h>
  5 
  6 #define KEY_STATE_UP 0X0
  7 #define KEY_STATE_DOWN 0X3
  8 #define KEY_STATE_LONGRESS 0XF
  9 #define KEY_STATE_RELEASE 0XC
 10 
 11 static KeyInfo kInfo[KEY_AMOUNT];
 12 static RingFifo MsgQ;
 13 
 14 
 15 void PostMessage(MessageInfo* pMsg)
 16 {
 17     PushFifo(&MsgQ,pMsg);    
 18 }
 19 
 20 unsigned char GetMessage(MessageInfo*pMsg)
 21 {
 22     return PopFifo(&MsgQ,pMsg);
 23 }
 24 
 25 // call it in timer service
 26 void KeyScan(void)
 27 {
 28     int i = 0;
 29     unsigned char c = 0;
 30     KeyInfo * pInfo = kInfo; 
 31     MessageInfo Msg;
 32     for(i=0;i<KEY_AMOUNT;++i)
 33     {
 34         Msg.pContext = pInfo;
 35         Msg.keyCode = pInfo->keyCode;
 36         c = ReadKeyStatus(Msg.keyCode);    //
 37         pInfo->keyStatus |= c;
 38         pInfo->keyStatus &= 0xF;
 39         switch(pInfo->keyStatus)
 40         {
 41             case KEY_STATE_UP:
 42                     pInfo->keyDownTime = 0;
 43                     break;
 44             case KEY_STATE_DOWN:
 45                     Msg.keyEvent = KEY_EVENT_DOWN;
 46                     PostMessage(&Msg);                                    // post event
 47                     break;
 48             case KEY_STATE_LONGRESS:
 49                     if(pInfo->keyDownTime < KEY_LONGPRESS_TIME /POLLING_INTERVAL)
 50                     {
 51                         pInfo->keyDownTime++;
 52                     }
 53                     else
 54                     {
 55                         if(pInfo->keyRepeatTime <  KEY_LONGPRESS_REPEAT_INTERVAL/POLLING_INTERVAL)
 56                         {
 57                             ++pInfo->keyRepeatTime;
 58                         }
 59                         else
 60                         {
 61                             pInfo->keyRepeatTime = 0;
 62                             Msg.keyEvent = KEY_EVENT_LONGPRESS;
 63                             PostMessage(&Msg);    // post event
 64                         }
 65                     }
 66                     break;
 67             case KEY_STATE_RELEASE:
 68                     Msg.keyEvent = KEY_EVENT_UP;                            
 69                     PostMessage(&Msg);                                        // post event
 70                     if(pInfo->keyDbClickTime)    //double click 
 71                     {
 72                         Msg.keyEvent = KEY_EVENT_DOUBLECLICK;
 73                         PostMessage(&Msg);                                        // post event
 74                     }
 75                     pInfo->keyDbClickTime = KEY_DBCLICK_TIME /POLLING_INTERVAL;
 76                     break;
 77         }
 78         if(pInfo->keyDbClickTime)pInfo->keyDbClickTime--;
 79         pInfo->keyStatus <<= 1;
 80         ++pInfo;
 81     }
 82     
 83 }
 84 
 85 
 86 
 87 // call this func in main()
 88 void KeyProc(void)
 89 {
 90     KeyInfo * pInfo = 0;
 91     int k = 10;
 92     MessageInfo msg;
 93     while(GetMessage(&msg) &&(k--))
 94     {
 95         pInfo = msg.pContext;
 96         if(pInfo->FuncCB[msg.keyEvent])
 97         {
 98             pInfo->FuncCB[msg.keyEvent](pInfo->para[msg.keyEvent]);
 99         }
100     }
101 }
102 
103 pKeyEventCB SetKeyHandler(unsigned char key,KeyEventType event,pKeyEventCB pFunc,void *para)
104 {
105     pKeyEventCB pf = NULL;
106     int i = 0;
107     for(i = 0;i<KEY_AMOUNT;++i)
108     {
109         if(key == kInfo[i].keyCode)
110         {
111             pf = kInfo[i].FuncCB[event];
112             kInfo[i].FuncCB[event] = pFunc;
113             kInfo[i].para[event] = para;
114             break;
115         }
116     }
117     return pf;
118 }
119 
120 void InitKey(void)
121 {
122     int i = 0;
123     InitFifo(&MsgQ);
124     memset(kInfo,0,sizeof(kInfo));
125     for(i = 0;i<KEY_AMOUNT;++i)
126     {
127         kInfo[i].keyCode = KeyCodeTable[i];
128     }
129     
130     RegisterKeyHandler();
131 }
key.c
 1 #ifndef __RINGFIFO_H__
 2 #define __RINGFIFO_H__
 3 
 4 #include "key.h"
 5 
 6 #define FIFO_SIZE 10
 7 
 8 typedef  MessageInfo ElemDataType;
 9 
10 typedef struct _tagFifo
11 {
12     ElemDataType data[FIFO_SIZE];        // message 
13     unsigned char read;                    //
14     unsigned char write;                //
15 }RingFifo;
16 
17 void InitFifo(RingFifo * pFifo);
18 unsigned char PopFifo(RingFifo * pFifo,ElemDataType * pMsg);
19 unsigned char PushFifo(RingFifo * pFifo,ElemDataType * pMsg);
20 unsigned char PeekFifo(RingFifo * pFifo,ElemDataType * pMsg);
21 
22 #endif
RingFifo.h
 1 #include "RingFifo.h"
 2 #include <string.h>
 3 //#include <assert.h>
 4 
 5 #define assert(x)
 6 
 7 void InitFifo(RingFifo * pFifo)
 8 {
 9         assert(pFifo);
10         memset(pFifo,0,sizeof(RingFifo));
11 }
12 
13 unsigned char PopFifo(RingFifo * pFifo,ElemDataType * pMsg)
14 {
15         assert(pFifo&&pMsg);
16         if(pFifo->read == pFifo->write)
17         {
18             return 0;
19         }
20         else
21         {
22             memcpy(pMsg,pFifo->data+pFifo->read,sizeof(ElemDataType));
23             pFifo->read = (pFifo->read+1)%FIFO_SIZE;
24             return 1;
25         }
26     
27 }
28 
29 unsigned char PushFifo(RingFifo * pFifo,ElemDataType * pMsg)
30 {
31     assert(pFifo&&pMsg);
32     memcpy(pFifo->data+pFifo->write,pMsg,sizeof(ElemDataType));
33     pFifo->write = (pFifo->write + 1) % FIFO_SIZE;
34     return 1;
35 }
36 
37 unsigned char PeekFifo(RingFifo * pFifo,ElemDataType * pMsg)
38 {
39     assert(pFifo&&pMsg);
40     if(pFifo->read == pFifo->write)
41     {
42         return 0;
43     }
44     else
45     {
46         memcpy(pMsg,&pFifo->data[pFifo->read],sizeof(ElemDataType));
47         return 1;
48     }
49 }
RingFifo.c

key_port.h中, KEY_AMOUNT代表能识别的按键个数,      用户需实现ReadKeyStatus(),RegisterKeyHandler()这2个函数,其中

ReadKeyStatus()用来读取硬件按键状态,具体可参见key_port.c示例

RegisterKeyHandler()用来设置按键处理函数。

 1 #ifndef __KEY_PORT_H__
 2 #define __KEY_PORT_H__
 3 
 4 #define KEY_AMOUNT 6
 5 
 6 #define KEY_LONGPRESS_TIME 3000                        //   3S
 7 #define KEY_DBCLICK_TIME 500    
 8 #define POLLING_INTERVAL 20                                //timer interval
 9 #define KEY_LONGPRESS_REPEAT_INTERVAL 500
10 extern unsigned char KeyCodeTable[KEY_AMOUNT];
11 unsigned char ReadKeyStatus(unsigned char key);
12 void RegisterKeyHandler(void);
13 
14 #endif
Key_Port.h
  1 #include "key_port.h"
  2 #include "key.h"
  3 #include "stm32f10x.h"
  4 #include "timer.h"
  5 #include "stepper.h"
  6 
  7 #define KEY_1  1
  8 #define KEY_2  2
  9 #define KEY_3  3
 10 #define KEY_4  4
 11 #define KEY_5  5
 12 #define KEY_6  6
 13 
 14 unsigned char KeyCodeTable[KEY_AMOUNT]=
 15 {
 16     KEY_1,
 17     KEY_2,
 18     KEY_3,
 19     KEY_4,
 20     KEY_5,
 21     KEY_6
 22 };
 23 
 24 void startStateMachine(void);
 25 void key1handler(void *p)    //
 26 {
 27    startStateMachine();
 28 }
 29 
 30 void key2handler(void *p)    //reset
 31 {
 32    
 33 }
 34 
 35 
 36 void key3handler(void *p)    // reserve
 37 {
 38    
 39         
 40 }
 41 
 42 void key3handler_up(void *p)    // 
 43 {
 44     
 45 }
 46 
 47 void key4handler(void *p)
 48 {
 49 
 50 }
 51 
 52 void key5handler(void *p)
 53 {
 54 
 55 }
 56 
 57 void key6handler(void *p)
 58 {
 59 
 60 }
 61 
 62 // get key status,return 1 if key down ,
 63 unsigned char ReadKeyStatus(unsigned char key)
 64 {
 65     unsigned char c = 0;
 66     switch(key)
 67     {
 68         case KEY_1:
 69             c = !GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5);
 70             break;
 71         case KEY_2:
 72             c = !GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15);
 73             break;
 74         case KEY_3:
 75             c = GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_4);
 76             break;
 77         case KEY_4:
 78             
 79             c = 0;
 80             break;
 81         case KEY_5:
 82             
 83             c= 0;
 84             break;
 85         case KEY_6:
 86             c= 0;
 87             break;
 88     }
 89     return c;
 90 }
 91 
 92 void RegisterKeyHandler(void)
 93 {
 94     // Add you key event func here
 95     SetKeyHandler(KEY_1,KEY_EVENT_DOWN,key1handler ,0);
 96     SetKeyHandler(KEY_2,KEY_EVENT_DOWN,key2handler ,0);
 97     SetKeyHandler(KEY_3,KEY_EVENT_DOWN,key3handler ,0);
 98     SetKeyHandler(KEY_3,KEY_EVENT_UP,key3handler_up ,0);
 99     SetKeyHandler(KEY_4,KEY_EVENT_DOWN,key4handler ,0);
100     SetKeyHandler(KEY_5,KEY_EVENT_DOWN,key5handler ,0);
101     SetKeyHandler(KEY_6,KEY_EVENT_UP,key6handler ,0);
102 }
Key_Port.c

在key_port.c中,提供了一个示例,分别设置了3个按键key_1,key_2,key_3的keydown处理函数,同时设置了key_3的keyUp处理函数。

相关文章