#ifndef __MULTI_BUTTON_H_
#define __MULTI_BUTTON_H_
#include <REGX52.H>
#include "string.h"
//According to your need to modify the constants.
#define TICKS_INTERVAL 5 //ms
#define DEBOUNCE_TICKS 3 //MAX 8
#define SHORT_TICKS (300 / TICKS_INTERVAL)
#define LONG_TICKS (1000 / TICKS_INTERVAL)
#define LONG_HOLD_CYC (500 / TICKS_INTERVAL)
#define ACTIVE_LEVEL 0
#define BTN0 P0_0
#define BTN1 P1_3
#define BTN2 P2_4
#define BTN3 P3_6
#define BTN4 P3_0
#define BTN5 P2_3
#define BTN6 P1_4
#define BTN7 P3_5
typedef struct
{
unsigned char lastPinValue; /* 按键编号 */
unsigned char PinValue; /* 按键状态 */
unsigned short Count; /* 滤波器计数器 */
unsigned short LongCount; /* 长按计数器 */
unsigned short LongTime; /* 按键按下持续时间, 0表示不检测长按 */
unsigned char State; /* 按键当前状态(按下还是弹起) */
unsigned char RepeatSpeed; /* 连续按键周期 */
unsigned short RepeatCount; /* 连续按键计数器 */
unsigned short DelayCount; /* 延迟计数器,用于双击检测 */
unsigned char ClickCount; /* 单击次数 */
int LastTime; /* 上次按键时刻 */
} KEY_T;
#define KEY_FILTER_TIME 10
#define KEY_LONG_TIME 200 /* 单位10ms, 持续1秒,认为长按事件 */
#define KEY_DB_CLICK_TIME 25 /* 双击检测时长,单位ms */
#define KEY_MSG_STEP 6 /* 按键消息代码步长(每个键有几个事件代码,顺序排列) */
typedef enum
{
KEY_NONE = 0, /* 0 表示按键事件 */
KEY_1_DOWN, /* 1键按下 */
KEY_1_UP, /* 1键弹起单击 */
KEY_1_LONG_DOWN, /* 1键长按 */
KEY_1_LONG_UP, /* 1键长按后的弹起 */
KEY_1_AUTO_UP, /* 1键长按后自动发码 */
KEY_1_DB_UP, /* 1键双击 */
KEY_2_DOWN, /* 2键按下 */
KEY_2_UP, /* 2键弹起 */
KEY_2_LONG_DOWN, /* 2键长按 */
KEY_2_LONG_UP, /* 2键长按后的弹起 */
KEY_2_AUTO_UP, /* 2键长按后自动发码 */
KEY_2_DB_UP, /* 2键双击 */
KEY_3_DOWN, /* 3键按下 */
KEY_3_UP, /* 3键弹起 */
KEY_3_LONG_DOWN, /* 3键长按 */
KEY_3_LONG_UP, /* 3键长按后的弹起 */
KEY_3_AUTO_UP, /* 3键长按后自动发码 */
KEY_3_DB_UP, /* 3键双击 */
KEY_4_DOWN, /* 4键按下 */
KEY_4_UP, /* 4键弹起 */
KEY_4_LONG_DOWN, /* 4键长按 */
KEY_4_LONG_UP, /* 4键长按后的弹起 */
KEY_4_AUTO_UP, /* 4键长按后自动发码 */
KEY_4_DB_UP, /* 4键双击 */
KEY_5_DOWN, /* 5键按下 */
KEY_5_UP, /* 5键弹起 */
KEY_5_LONG_DOWN, /* 5键长按 */
KEY_5_LONG_UP, /* 5键长按后的弹起 */
KEY_5_AUTO_UP, /* 5键长按后自动发码 */
KEY_5_DB_UP, /* 5键双击 */
KEY_6_DOWN, /* 5键按下 */
KEY_6_UP, /* 5键弹起 */
KEY_6_LONG_DOWN, /* 5键长按 */
KEY_6_LONG_UP, /* 5键长按后的弹起 */
KEY_6_AUTO_UP, /* 5键长按后自动发码 */
KEY_6_DB_UP, /* 5键双击 */
KEY_7_DOWN, /* 5键按下 */
KEY_7_UP, /* 5键弹起 */
KEY_7_LONG_DOWN, /* 5键长按 */
KEY_7_LONG_UP, /* 5键长按后的弹起 */
KEY_7_AUTO_UP, /* 5键长按后自动发码 */
KEY_7_DB_UP, /* 5键双击 */
KEY_8_DOWN, /* 5键按下 */
KEY_8_UP, /* 5键弹起 */
KEY_8_LONG_DOWN, /* 5键长按 */
KEY_8_LONG_UP, /* 5键长按后的弹起 */
KEY_8_AUTO_UP, /* 5键长按后自动发码 */
KEY_8_DB_UP, /* 5键双击 */
} KEY_ENUM;
/* 按键FIFO用到变量 */
#define KEY_FIFO_SIZE 10
typedef struct
{
unsigned char Buf[KEY_FIFO_SIZE]; /* 键值缓冲区 */
unsigned char Read; /* 缓冲区读指针1 */
unsigned char Write; /* 缓冲区写指针 */
} KEY_FIFO_T;
#ifdef __cplusplus
extern "C" {
#endif
void button_init(void);
void button_ticks(void);
unsigned char bsp_GetKey(void);
#ifdef __cplusplus
}
#endif
#endif
#include "q_button.h"
KEY_T s_tBtn;
KEY_FIFO_T s_tKey; /* 按键FIFO变量,结构体 */
void bsp_PutKey(unsigned char _KeyCode)
{
s_tKey.Buf[s_tKey.Write] = _KeyCode;
if (++s_tKey.Write >= KEY_FIFO_SIZE)
{
s_tKey.Write = 0;
}
}
/*
*********************************************************************************************************
* 函 数 名: bsp_GetKey
* 功能说明: 从按键FIFO缓冲区读取一个键值。
* 形 参: 无
* 返 回 值: 按键代码
*********************************************************************************************************
*/
unsigned char bsp_GetKey(void)
{
unsigned char 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;
}
}
/**
* @brief 初始化按钮结构体。
* @param pin_level: 读取连接按钮电平的函数指针。
* @param active_level: 按钮按下的电平。
* @retval None
*/
void button_init(void)
{
memset(&s_tBtn, 0, sizeof(KEY_T));
//global_button.button_level = pin_level();
s_tBtn.LongTime = KEY_LONG_TIME; /* 长按时间 0 表示不检测长按键事件 */
s_tBtn.Count = KEY_FILTER_TIME / 2; /* 计数器设置为滤波时间的一半 */
}
// 读取GPIO口状态并映射到内存变量中的bit位
void read_gpio_status(unsigned char *status)
{
// 读取所有8个GPIO口的状态,并将结果存储到内存变量中
*status = 0;
// 读取GPIO口状态的代码示例,需要根据实际情况进行修改
if (P3_0 == ACTIVE_LEVEL)
{
// *status |= (1 << 0);
*status = 1;
}
if (P3_1 == ACTIVE_LEVEL)
{
// *status |= (1 << 1);
*status = 2;
}
if (P3_2 == ACTIVE_LEVEL)
{
// *status |= (1 << 2);
*status = 3;
}
if (P3_3 == ACTIVE_LEVEL)
{
// *status |= (1 << 3);
*status = 4;
}
if (P3_4 == ACTIVE_LEVEL)
{
// *status |= (1 << 4);
*status = 5;
}
if (P3_5 == ACTIVE_LEVEL)
{
// *status |= (1 << 5);
*status = 6;
}
if (P3_6 == ACTIVE_LEVEL)
{
// *status |= (1 << 6);
*status = 7;
}
if (P3_7 == ACTIVE_LEVEL)
{
// *status |= (1 << 7);
*status = 8;
}
}
/**
* @brief 按钮驱动核心函数,驱动状态机。
* @retval None
*/
void button_ticks(void)
{
if (bHalGetSysTick() % 10 == 0) /* 需要最小时间不要小于5ms,因为有print */
{
return;
}
read_gpio_status(&s_tBtn.PinValue);
if (s_tBtn.PinValue)
{
if (s_tBtn.Count < KEY_FILTER_TIME)
{
s_tBtn.Count = KEY_FILTER_TIME;
}
else if (s_tBtn.Count < 2 * KEY_FILTER_TIME)
{
s_tBtn.Count++;
}
else
{
s_tBtn.lastPinValue = s_tBtn.PinValue - 1;
if (s_tBtn.State == 0)
{
s_tBtn.State = 1;
/* 发送按钮按下的消息 */
bsp_PutKey((unsigned char)(KEY_MSG_STEP * s_tBtn.lastPinValue + KEY_1_DOWN));
}
if (s_tBtn.LongTime > 0)
{
if (s_tBtn.LongCount < s_tBtn.LongTime)
{
/* 发送长按消息 */
if (++s_tBtn.LongCount == s_tBtn.LongTime)
{
s_tBtn.State = 2;
/* 键值放入按键FIFO */
bsp_PutKey((unsigned char)(KEY_MSG_STEP * s_tBtn.lastPinValue + KEY_1_LONG_DOWN));
}
}
else
{
if (s_tBtn.RepeatSpeed > 0)
{
if (++s_tBtn.RepeatCount >= s_tBtn.RepeatSpeed)
{
s_tBtn.RepeatCount = 0;
/* 常按键后,每隔10ms发送1个按键弹起事件 */
bsp_PutKey((unsigned char)(KEY_MSG_STEP * s_tBtn.lastPinValue + KEY_1_AUTO_UP));
}
}
}
}
}
}
else
{
if (s_tBtn.Count > KEY_FILTER_TIME)
{
s_tBtn.Count = KEY_FILTER_TIME;
}
else if (s_tBtn.Count != 0)
{
s_tBtn.Count--;
}
else
{
if (s_tBtn.State != 0)
{
/* 2019-12-05 增加,第4个事件, 长按后的弹起 */
if (s_tBtn.LongTime == 0)
{
/* 发送短按弹起的消息 */
bsp_PutKey((unsigned char)(KEY_MSG_STEP * s_tBtn.lastPinValue + KEY_1_UP));
}
else
{
if (s_tBtn.State == 2)
{
/* 发送长按弹起的消息 */
bsp_PutKey((unsigned char)(KEY_MSG_STEP * s_tBtn.lastPinValue + KEY_1_LONG_UP));
}
else
{
bsp_PutKey((unsigned char)(KEY_MSG_STEP * s_tBtn.lastPinValue + KEY_1_UP)); /* 单击弹起事件 */
}
}
s_tBtn.State = 0;
}
}
s_tBtn.LongCount = 0;
s_tBtn.RepeatCount = 0;
}
}