/*
* @Author: John Luo
* @Date: 2021-08-25 10:54:28
* @LastEditTime: 2021-08-25 13:01:24
* @LastEditors: John Luo
* @Description: 1. 自定义IsKeyDown()函数
* 2. gp_InitKeyVar()赋值函数指针
* 3. 连按功能需要打开长按功能
* @FilePath: \61F14x_UART\gp_key.c
*/
#include "gp_key.h"
#include "SYSCFG.h"
static KEY_T s_tBtn[KEY_COUNT];
static KEY_FIFO_T s_tKey;
/* 需要自己定义 *****************************************/
static uint8_t IsKeyDown0(void)
{
if (KEY0 == 0)
return 1;
else
return 0;
}
static uint8_t IsKeyDown1(void)
{
if (KEY1 == 0)
return 1;
else
return 0;
}
static uint8_t IsKeyDown2(void)
{
if (KEY2 == 0)
return 1;
else
return 0;
}
static uint8_t IsKeyDown3(void)
{
if (KEY3 == 0)
return 1;
else
return 0;
}
/********************************************************/
/**
* @description:
* @param {KEY_ID_E} _ucKeyID
* @param {uint16_t} _LongTime
* @param {uint8_t} _RepeatSpeed
* @return {*}
*/
static void gp_SetKeyParam(KEY_ID_E _ucKeyID, uint16_t _LongTime, uint8_t _RepeatSpeed)
{
s_tBtn[_ucKeyID].LongTime = _LongTime; /* 长按时间 0 表示不检测长按键事件 */
s_tBtn[_ucKeyID].RepeatSpeed = _RepeatSpeed; /* 按键连发的速度,0表示不支持连发 */
s_tBtn[_ucKeyID].RepeatCount = 0; /* 连发计数器 */
}
/**
* @description: 初始化按键结构体
* @param {*}
* @return {*}
*/
void gp_InitKeyVar(void)
{
uint8_t i;
/* 对按键FIFO读写指针清零 */
s_tKey.Read = 0;
s_tKey.Write = 0;
/* 给每个按键结构体成员变量赋一组缺省值 */
for (i = 0; i < KEY_COUNT; i++)
{
s_tBtn[i].LongTime = KEY_LONG_TIME; /* 长按时间 0 表示不检测长按键事件 */
s_tBtn[i].Count = KEY_FILTER_TIME / 2; /* 计数器设置为滤波时间的一半 */
s_tBtn[i].State = 0; /* 按键缺省状态,0为未按下 */
s_tBtn[i].RepeatSpeed = 0; /* 按键连发的速度,0表示不支持连发 */
s_tBtn[i].RepeatCount = 0; /* 连发计数器 */
}
/* 这里赋值按键按键函数指针 */
s_tBtn[KID_K0].IsKeyDownFunc = IsKeyDown0;
s_tBtn[KID_K1].IsKeyDownFunc = IsKeyDown1;
s_tBtn[KID_K2].IsKeyDownFunc = IsKeyDown2;
s_tBtn[KID_K3].IsKeyDownFunc = IsKeyDown3;
/* 如果需要单独更改某个按键的参数,可以在此单独重新赋值 */
gp_SetKeyParam(KID_K0, 150, 50);
}
/**
* @description: 10ms调用一次函数
* @param {uint8_t} i 按键id
* @return {*}
*/
void gp_DetectKey(uint8_t i)
{
KEY_T *pBtn;
/*
如果没有初始化按键函数,则报错
if (s_tBtn[i].IsKeyDownFunc == 0)
{
printf("Fault : DetectButton(), s_tBtn[i].IsKeyDownFunc undefine");
}
*/
pBtn = &s_tBtn[i];
if (pBtn->IsKeyDownFunc())
{
if (pBtn->Count < KEY_FILTER_TIME)
{
pBtn->Count = KEY_FILTER_TIME;
}
else if (pBtn->Count < 2 * KEY_FILTER_TIME)
{
pBtn->Count++;
}
else
{
if (pBtn->State == 0)
{
pBtn->State = 1;
/* 发送按钮按下的消息 */
gp_PutKeyFifo((uint8_t)(3 * i + 1));
}
if (pBtn->LongTime > 0)
{
if (pBtn->LongCount < pBtn->LongTime)
{
/* 发送按钮持续按下的消息 */
if (++pBtn->LongCount == pBtn->LongTime)
{
/* 键值放入按键FIFO */
gp_PutKeyFifo((uint8_t)(3 * i + 3));
}
}
else
{
if (pBtn->RepeatSpeed > 0)
{
if (++pBtn->RepeatCount >= pBtn->RepeatSpeed)
{
pBtn->RepeatCount = 0;
/* 常按键后,每隔10ms发送1个按键 */
gp_PutKeyFifo((uint8_t)(3 * i + 1));
}
}
}
}
}
}
else
{
if (pBtn->Count > KEY_FILTER_TIME)
{
pBtn->Count = KEY_FILTER_TIME;
}
else if (pBtn->Count != 0)
{
pBtn->Count--;
}
else
{
if (pBtn->State == 1)
{
pBtn->State = 0;
/* 发送按钮弹起的消息 */
gp_PutKeyFifo((uint8_t)(3 * i + 2));
}
}
pBtn->LongCount = 0;
pBtn->RepeatCount = 0;
}
}
/**
* @description: 按键动作压入队列
* @param {uint8_t} _KeyCode
* @return {*}
*/
void gp_PutKeyFifo(uint8_t _KeyCode)
{
s_tKey.Buf[s_tKey.Write] = _KeyCode;
if (++s_tKey.Write >= KEY_FIFO_SIZE)
{
s_tKey.Write = 0;
}
}
/**
* @description: 从队列中读取按键动作
* @param {*}
* @return {*}
*/
uint8_t gp_GetKeyFifo(void)
{
uint8_t ret;
if (s_tKey.Read == s_tKey.Write)
{
return KEY_NONE;
}
else
{
ret = s_tKey.Buf[s_tKey.Read];
if (++s_tKey.Read >= KEY_FIFO_SIZE)
{
s_tKey.Read = 0;
}
return ret;
}
}
/*
* @Author: John Luo
* @Date: 2021-08-25 10:54:37
* @LastEditTime: 2021-08-25 12:00:02
* @LastEditors: John Luo
* @Description:
* @FilePath: \61F14x_UART\gp_key.h
*/
#define uint8_t unsigned char
#define uint16_t unsigned int
/* 需要自己定义 *****************************************/
#define KEY0 RB4
#define KEY1 RB3
#define KEY2 RB2
#define KEY3 RB1
#define KEY_FILTER_TIME 5 /* 短按滤波和连按时间 */
#define KEY_LONG_TIME 100 /* 单位10ms, 持续1秒,认为长按事件 */
#define KEY_FIFO_SIZE 10 /* 按键动作队列大小 */
#define KEY_COUNT 4 /* 按键个数, 4个独立建 */
typedef enum /* 按键ID 从0开始增加 */
{
KID_K0 = 0,
KID_K1,
KID_K2,
KID_K3
} KEY_ID_E;
typedef enum /* 记录按键动作值 */
{
KEY_NONE = 0, /* 0 表示按键事件 */
KEY_0_DOWN, /* 0键按下 */
KEY_0_UP, /* 0键弹起 */
KEY_0_LONG, /* 0键长按 */
KEY_1_DOWN, /* 1键按下 */
KEY_1_UP, /* 1键弹起 */
KEY_1_LONG, /* 1键长按 */
KEY_2_DOWN, /* 2键按下 */
KEY_2_UP, /* 2键弹起 */
KEY_2_LONG, /* 2键长按 */
KEY_3_DOWN, /* 3键按下 */
KEY_3_UP, /* 3键弹起 */
KEY_3_LONG, /* 3键长按 */
} KEY_ENUM;
/* *****************************************************/
typedef struct
{
/* 下面是一个函数指针,指向判断按键手否按下的函数 */
uint8_t (*IsKeyDownFunc)(void); /* 按键按下的判断函数,1表示按下 */
uint8_t Count; /* 滤波器计数器 */
uint16_t LongCount; /* 长按计数器 */
uint16_t LongTime; /* 按键按下持续时间, 0表示不检测长按 */
uint8_t State; /* 按键当前状态(按下还是弹起) */
uint8_t RepeatSpeed; /* 连续按键周期 */
uint8_t RepeatCount; /* 连续按键计数器 */
} KEY_T;
typedef struct
{
uint8_t Buf[KEY_FIFO_SIZE]; /* 键值缓冲区 */
uint8_t Read; /* 缓冲区读指针 */
uint8_t Write; /* 缓冲区写指针 */
} KEY_FIFO_T;
/* 自定义按键函数 */
static uint8_t IsKeyDown0(void);
static uint8_t IsKeyDown1(void);
static uint8_t IsKeyDown2(void);
static uint8_t IsKeyDown3(void);
static void gp_SetKeyParam(KEY_ID_E _ucKeyID, uint16_t _LongTime, uint8_t _RepeatSpeed);
uint8_t gp_GetKeyFifo(void);
void gp_PutKeyFifo(uint8_t _KeyCode);
void gp_InitKeyVar(void);
void gp_DetectKey(uint8_t i);