首页 > 代码库 > 单片机按键处理框架

单片机按键处理框架

写过一段时间单片机程序,也看了一些单片机程序,书上的,网上的,基本都是非常原始的读取按键,延时判断,这些按键相关代码穿插于整个程序,着实不够美观,最重要的是不能复用,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 _tagKeyInfo17 {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 _tagMessageInfo29 {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 loop40 41 void KeyScan(void);    // call it in timer service, 20ms42 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 _tagFifo11 {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         else21         {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     else45     {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 50010 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处理函数。