用状态机方式生成单个按键扫描函数,返回键值,可以识别长按键,短按键,双击,三连击
时间: 2024-03-09 13:49:51 浏览: 11
好的,下面是一个简单的状态机方式生成单个按键扫描函数的示例代码,可以实现你的要求:
```
#define KEY_IDLE 0
#define KEY_DOWN 1
#define KEY_UP 2
#define KEY_DOUBLE 3
#define KEY_TRIPLE 4
#define KEY_SHORT_PRESS_TIME 200 // 短按时间,单位 ms
#define KEY_LONG_PRESS_TIME 1000 // 长按时间,单位 ms
#define KEY_DOUBLE_PRESS_TIME 300 // 双击时间间隔,单位 ms
#define KEY_TRIPLE_PRESS_TIME 300 // 三连击时间间隔,单位 ms
static uint8_t key_state = KEY_IDLE;
static uint32_t key_timestamp = 0;
static uint32_t key_press_time = 0;
static uint8_t key_press_count = 0;
/**
* @brief 单个按键扫描函数
* @retval 按键值,0 表示没有按键按下
*/
uint8_t key_scan(void)
{
uint8_t key_value = 0;
switch (key_state)
{
case KEY_IDLE:
if (KEY_IS_DOWN()) // 检测到按键按下
{
key_state = KEY_DOWN;
key_timestamp = HAL_GetTick();
}
break;
case KEY_DOWN:
if (KEY_IS_UP()) // 检测到按键释放
{
key_state = KEY_UP;
key_press_time = HAL_GetTick() - key_timestamp;
key_press_count++;
if (key_press_count == 1) // 第一次按下
{
if (key_press_time < KEY_SHORT_PRESS_TIME)
{
key_value = KEY_SHORT_PRESS;
}
}
else if (key_press_count == 2) // 第二次按下
{
if (key_press_time < KEY_SHORT_PRESS_TIME)
{
key_value = KEY_DOUBLE_PRESS;
key_state = KEY_DOUBLE;
key_timestamp = HAL_GetTick();
}
}
else if (key_press_count == 3) // 第三次按下
{
if (key_press_time < KEY_SHORT_PRESS_TIME)
{
key_value = KEY_TRIPLE_PRESS;
key_state = KEY_TRIPLE;
key_timestamp = HAL_GetTick();
}
}
if (key_press_time > KEY_LONG_PRESS_TIME) // 长按
{
key_value = KEY_LONG_PRESS;
}
key_press_time = 0;
}
else if (HAL_GetTick() - key_timestamp > KEY_LONG_PRESS_TIME) // 长按
{
key_state = KEY_UP;
key_value = KEY_LONG_PRESS;
}
break;
case KEY_UP:
if (KEY_IS_DOWN()) // 检测到按键按下
{
key_state = KEY_DOWN;
key_timestamp = HAL_GetTick();
}
else if (HAL_GetTick() - key_timestamp > KEY_DOUBLE_PRESS_TIME) // 双击超时
{
key_state = KEY_IDLE;
key_press_count = 0;
}
break;
case KEY_DOUBLE:
if (KEY_IS_DOWN() && HAL_GetTick() - key_timestamp > KEY_DOUBLE_PRESS_TIME) // 检测到按键按下,且时间间隔大于双击时间
{
key_state = KEY_DOWN;
key_press_count = 1;
}
else if (HAL_GetTick() - key_timestamp > KEY_TRIPLE_PRESS_TIME) // 三连击超时
{
key_state = KEY_IDLE;
key_press_count = 0;
}
break;
case KEY_TRIPLE:
if (KEY_IS_DOWN() && HAL_GetTick() - key_timestamp > KEY_TRIPLE_PRESS_TIME) // 检测到按键按下,且时间间隔大于三连击时间
{
key_state = KEY_DOWN;
key_press_count = 1;
}
else if (HAL_GetTick() - key_timestamp > KEY_DOUBLE_PRESS_TIME) // 双击超时
{
key_state = KEY_IDLE;
key_press_count = 0;
}
break;
default:
break;
}
return key_value;
}
```
注意,上面的代码中使用了一些宏来代表按键的状态和时间,需要根据实际情况进行修改。另外,`KEY_IS_DOWN()` 和 `KEY_IS_UP()` 是自定义的宏,用于检测按键是否按下和释放,也需要根据实际情况进行修改。