首页 > 代码库 > 单片机按键处理框架
单片机按键处理框架
写过一段时间单片机程序,也看了一些单片机程序,书上的,网上的,基本都是非常原始的读取按键,延时判断,这些按键相关代码穿插于整个程序,着实不够美观,最重要的是不能复用,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
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 }
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
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 }
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
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中,提供了一个示例,分别设置了3个按键key_1,key_2,key_3的keydown处理函数,同时设置了key_3的keyUp处理函数。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。