目录
一、按键状态机的作用
一般的按键状态机一般都具有以下功能:
- 能够判断哪个按键按下
- 能够判断按键是长按或者短按
- 能够记录对应按键按下对应的次数
实现思想:
- 首先,通过定时器或者查询方式等周期性查询按键状态机的状态
- 接着在按键状态机中,需要获取得到对应按下的按键,然后通过对按键的前后状态进行对比,如果没有改变,则增加按键时间。如果按键松开,则对按键结构体进行修改,将对应信息赋值给按键结构体。
使用方法:
- 通过不断检测按键状态机,当按键状态机改变后。通过对按键结构体的检索,可以得知按下按键的按键编号、按键时间长短、按键按下次数。
- 然后执行对应按键的功能
二、按键状态机的实现
1、按键状态机的宏定义
/* 按键key的编号 */
#define KEY_DEFAULT_NUM 0x00
#define KEY_0_NUM 0x01
#define KEY_1_NUM 0x02
#define KEY_2_NUM 0x04
#define KEY_UP_NUM 0x08
#define KEY_ALL_NUM 0xFF
/* 按键时长状态定义 */
#define KEY_PRESS_SHORT 10U
2、按键状态机的枚举与相关结构体
/* 按键状态对比 */
typedef enum
{
No_Change = 0,
Pressed_State,
Release_State,
}exKeyCompareStateEnum;
/* 按键按下时间长短 */
typedef enum
{
Key_State_Default = 0,
Key_State_Short,
Key_State_Long,
}exKeyStateEnum;
/* 按键结构体 */
typedef struct
{
uint8_t ucKeyNum; /* 按键编号 */
uint8_t ucKeyState; /* 按键时长状态 */
uint8_t ucKeyCount; /* 按键次数 */
}exKeyTypeDef;
3、按键状态机的函数实现
/**
* 按键状态机
* @para ucKeyNum: 需要检测的按键编号
* @retval 0: 状态未改变 1: 状态改变
*/
uint8_t ucKeyMachine(uint8_t ucKeyNum)
{
static uint8_t ucNewKeyNum = 0, ucOldKeyNum = 0;
static uint8_t ucKeyPressedTime = 0;
static uint8_t ucEndFlag = 0;
uint8_t ucKeyState = No_Change;
/* 对应按键编号的按键状态 */
ucNewKeyNum = ucKeyScan(ucKeyNum);
/* 新按键状态 判断与处理 */
ucKeyState = ucKeyStateCompare(ucNewKeyNum, ucOldKeyNum);
switch(ucKeyState)
{
case No_Change: ucKeyPressedTime++; break; /* 按键状态改变,则增加按键时间 */
case Pressed_State: ucOldKeyNum = ucNewKeyNum; ucKeyPressedTime = 0; break; /* 按键按下,则更改按键缓存,并且将按键时间置0 */
case Release_State: ucEndFlag = 1; break; /* 按键松开,则进入按键结束 */
}
/* 按键结束 */
if(ucEndFlag == 1)
{
/* 更新按键次数 */
if(ex_KeyHandle.ucKeyNum == ucOldKeyNum)
ex_KeyHandle.ucKeyCount++;
else
{
ex_KeyHandle.ucKeyNum = ucOldKeyNum;
ex_KeyHandle.ucKeyCount = 0;
}
/* 更新按键状态时长 */
if(ucKeyPressedTime >= KEY_PRESS_SHORT)
ex_KeyHandle.ucKeyState = Key_State_Long;
else
ex_KeyHandle.ucKeyState = Key_State_Short;
/* 参数初始化 */
ucEndFlag = 0;
ucOldKeyNum = 0;
ucKeyPressedTime = 0;
return 1;
}
return 0;
}
/**
* 按键扫描
* @para ucKeyNum: 按键编号
* @retval ucPressedKeyNum: 返回对应按下按键的编号, 未按下则返回 0
*/
uint8_t ucKeyScan(uint8_t ucKeyNum)
{
uint8_t ucPressedKeyNum = 0;
if(ucKeyNum & KEY_0_NUM)
{
if(HAL_GPIO_ReadPin(KEY_PORT, KEY_0_PIN) == GPIO_PIN_RESET)
ucPressedKeyNum |= KEY_0_NUM;
}
if(ucKeyNum & KEY_1_NUM)
{
if(HAL_GPIO_ReadPin(KEY_PORT, KEY_1_PIN) == GPIO_PIN_RESET)
ucPressedKeyNum |= KEY_1_NUM;
}
if(ucKeyNum & KEY_2_NUM)
{
if(HAL_GPIO_ReadPin(KEY_PORT, KEY_2_PIN) == GPIO_PIN_RESET)
ucPressedKeyNum |= KEY_2_NUM;
}
if(ucKeyNum & KEY_UP_NUM)
{
if(HAL_GPIO_ReadPin(KEY_UP_PORT, KEY_UP_PIN) == GPIO_PIN_SET)
ucPressedKeyNum |= KEY_UP_NUM;
}
return ucPressedKeyNum;
}
/**
* 按键状态前后对比函数
* @para ucNewKeyNum: 新键值状态
* @para ucOldKeyNum: 旧键值状态
* @retval 返回对应键值改变的状态
*/
uint8_t ucKeyStateCompare(uint8_t ucNewKeyNum, uint8_t ucOldKeyNum)
{
if(ucNewKeyNum == ucOldKeyNum)
return No_Change;
else if((ucNewKeyNum & ucOldKeyNum) == ucOldKeyNum)
return Pressed_State;
else
return Release_State;
}