多功能按键
本示例主要实现多功能按键:短按(按下与释放),长按(长按按下、连续、释放),短按多次连击功能;
H文件
#ifndef _KEY_H_
#define _KEY_H_
#include "stdio.h"
#include "stdint.h"
#define MULTI_CLICK 1
#define LONG_CONTINUE 1
typedef enum
{
eKeyLow,
eKeyHigh,
}eKey;
typedef enum
{
eKeyNull,
eKeyPress,
eKeyRelease,
eKeyLongPress,
#if LONG_CONTINUE
eKeyLongContinnue,
#endif
eKeyLongRelease,
}eKeyStatus;
typedef int (*pKeyCallBackFunction)(void* parm);
typedef struct _Key_CB_t
{
pKeyCallBackFunction pKeyPressCB;
pKeyCallBackFunction pKeyReleaseCB;
pKeyCallBackFunction pKeyLongPressCB;
#if LONG_CONTINUE
pKeyCallBackFunction pKeyLongContinueCB;
#endif
pKeyCallBackFunction pKeyLongReleaseCB;
}KeyCB_t;
typedef struct _Key_t
{
eKeyStatus ekey;
uint16_t usId;
uint16_t usDebounce;
uint16_t usShortPressDebounce;
uint16_t usLongPressDebounce;
#if MULTI_CLICK
uint8_t ucShortKeyTimes;
uint16_t usReleaseDebounce;
uint16_t usShortKeyReleaseDeobunce;
#endif
#if LONG_CONTINUE
uint16_t usLongContinueDebounce;
#endif
KeyCB_t* pKeyCB;
}KeyInfo_t;
#define KEY_CNT 1
#define KEY_BUF_CNT ((KEY_CNT>>4) + ((KEY_CNT&0x0F)?1:0)) //16bit Algin
void KeyInit(void);
void KeyScan(void);
void KeyProcess(void);
#endif
C文件
#include "Key.h"
#include "main.h"
uint16_t KeyScanBuf[KEY_BUF_CNT];
KeyInfo_t KeyInfo[KEY_CNT];
int KeyShortPress(void * parm)
{
printf("%s\r\n",__FUNCTION__);
return 0;
}
int KeyShortRelease(void * parm)
{
#if MULTI_CLICK
printf("%s,t=%d\r\n",__FUNCTION__,((KeyInfo_t*)parm)->ucShortKeyTimes);
#else
printf("%s\r\n",__FUNCTION__);
#endif
return 0;
}
int KeyLongPress(void * parm)
{
printf("%s\r\n",__FUNCTION__);
return 0;
}
int KeyLongContinue(void * parm)
{
printf("%s\r\n",__FUNCTION__);
return 0;
}
int KeyLongRelease(void * parm)
{
printf("%s\r\n",__FUNCTION__);
return 0;
}
KeyCB_t KeyCbBuf=
{
KeyShortPress,
KeyShortRelease,
KeyLongPress,
#if LONG_CONTINUE
KeyLongContinue,
#endif
KeyLongRelease,
};
void KeyInit(void)
{
for(int i=0;i<KEY_CNT;i++)
{
KeyInfo[i].ekey = eKeyNull;
KeyInfo[i].usId = i;
KeyInfo[i].usDebounce = 0;
KeyInfo[i].usShortPressDebounce = 4;
KeyInfo[i].usLongPressDebounce = 24;//240ms
#if MULTI_CLICK
KeyInfo[i].ucShortKeyTimes = 0;
KeyInfo[i].usReleaseDebounce = 0;
KeyInfo[i].usShortKeyReleaseDeobunce = 40;//400ms
#endif
#if LONG_CONTINUE
KeyInfo[i].usLongContinueDebounce = 0;
#endif
KeyInfo[i].pKeyCB = &KeyCbBuf;
}
}
void KeyScan(void)
{
KeyScanBuf[0] = HAL_GPIO_ReadPin(KEY_UP_GPIO_Port,KEY_UP_Pin);
}
void KeyDetect(uint8_t * pKey,KeyInfo_t* pKeyInfo,uint16_t KeyCnt)
{
for(int i=0;i<KeyCnt;i++)
{
if ((pKey[i>>3]&(0x01<<(i&0x07))) == eKeyLow)
{
pKeyInfo->usDebounce++;
if (pKeyInfo->ekey == eKeyLongPress)
{
#if LONG_CONTINUE
pKeyInfo->ekey = eKeyLongContinnue;
pKeyInfo->usLongContinueDebounce = pKeyInfo->usDebounce + pKeyInfo->usLongPressDebounce;
#endif
}
#if LONG_CONTINUE
else if ((pKeyInfo->ekey == eKeyLongContinnue) && (pKeyInfo->usLongContinueDebounce == pKeyInfo->usDebounce))
{
if (pKeyInfo->pKeyCB->pKeyLongContinueCB != NULL)
{
pKeyInfo->pKeyCB->pKeyLongContinueCB(pKeyInfo);
}
pKeyInfo->usLongContinueDebounce = pKeyInfo->usDebounce + pKeyInfo->usLongPressDebounce;
}
#endif
else if ((pKeyInfo->ekey != eKeyLongPress)&&(pKeyInfo->usDebounce == pKeyInfo->usLongPressDebounce))
{
pKeyInfo->ekey = eKeyLongPress;
if (pKeyInfo->pKeyCB->pKeyLongPressCB != NULL)
{
pKeyInfo->pKeyCB->pKeyLongPressCB(pKeyInfo);
}
}
else if (pKeyInfo->usDebounce == pKeyInfo->usShortPressDebounce)
{
pKeyInfo->ekey = eKeyPress;
if (pKeyInfo->pKeyCB->pKeyPressCB != NULL)
{
pKeyInfo->pKeyCB->pKeyPressCB(pKeyInfo);
}
#if MULTI_CLICK
pKeyInfo->ucShortKeyTimes++;
pKeyInfo->usReleaseDebounce = 0;
#endif
}
}
else
{
if (pKeyInfo->ekey == eKeyPress)
{
#if MULTI_CLICK
pKeyInfo->usReleaseDebounce++;
if (pKeyInfo->usReleaseDebounce > pKeyInfo->usShortKeyReleaseDeobunce)
{
//short key release
if (pKeyInfo->pKeyCB->pKeyReleaseCB != NULL)
{
pKeyInfo->pKeyCB->pKeyReleaseCB(pKeyInfo);
pKeyInfo->ucShortKeyTimes = 0;
pKeyInfo->usReleaseDebounce = 0;
pKeyInfo->ekey = eKeyNull;
}
}
#else
if (pKeyInfo->pKeyCB->pKeyReleaseCB != NULL)
{
pKeyInfo->pKeyCB->pKeyReleaseCB(pKeyInfo);
pKeyInfo->ekey = eKeyNull;
}
#endif
}
#if LONG_CONTINUE
else if ((pKeyInfo->ekey == eKeyLongContinnue)||(pKeyInfo->ekey == eKeyLongPress))
{
if (pKeyInfo->pKeyCB->pKeyLongReleaseCB != NULL)
{
pKeyInfo->pKeyCB->pKeyLongReleaseCB(pKeyInfo);
#if MULTI_CLICK
pKeyInfo->ucShortKeyTimes = 0;
pKeyInfo->usReleaseDebounce = 0;
#endif
pKeyInfo->ekey = eKeyNull;
}
}
#else
else if (pKeyInfo->ekey == eKeyLongPress)
{
if (pKeyInfo->pKeyCB->pKeyLongReleaseCB != NULL)
{
pKeyInfo->pKeyCB->pKeyLongReleaseCB(pKeyInfo);
#if MULTI_CLICK
pKeyInfo->ucShortKeyTimes = 0;
pKeyInfo->usReleaseDebounce = 0;
#endif
pKeyInfo->ekey = eKeyNull;
}
}
#endif
pKeyInfo->usDebounce = 0;
}
pKeyInfo++;
}
}
void KeyProcess(void)
{
KeyScan();
KeyDetect((uint8_t*)KeyScanBuf,KeyInfo,KEY_CNT);
}
使用说明
#define MULTI_CLICK 1 //设置是否使能连击功能
#define LONG_CONTINUE 1//设置是否使能长按连续功能
typedef int (pKeyCallBackFunction)(void parm);
typedef struct _Key_CB_t
{
pKeyCallBackFunction pKeyPressCB;
pKeyCallBackFunction pKeyReleaseCB;
pKeyCallBackFunction pKeyLongPressCB;
#if LONG_CONTINUE
pKeyCallBackFunction pKeyLongContinueCB;
#endif
pKeyCallBackFunction pKeyLongReleaseCB;
}KeyCB_t;
以上为按键回调函数结构体。
typedef struct _Key_t
{
eKeyStatus ekey;
uint16_t usId;
uint16_t usDebounce;
uint16_t usShortPressDebounce;
uint16_t usLongPressDebounce;
#if MULTI_CLICK
uint8_t ucShortKeyTimes;
uint16_t usReleaseDebounce;
uint16_t usShortKeyReleaseDeobunce;
#endif
#if LONG_CONTINUE
uint16_t usLongContinueDebounce;
#endif
KeyCB_t* pKeyCB;
}KeyInfo_t;
以上为单个按键结构体。
#define KEY_CNT 1//定义按键个数
按键初始化
在KeyInit里面初始化按键,设置每个按键的相关信息,特别是其回调函数。
按键扫描
请在KeyScan里面实现每个按键的扫描,每个按键状态占用1个bit,保存在KeyScanBuf里面。
按键处理
请周期性调用KeyProcess,其实现按键扫描和处理整个过程。
如果有连击功能,连接次数结果请在KeyShortRelease里面调用((KeyInfo_t*)parm)->ucShortKeyTimes获取。