本按键扫描具备以下事件。
按下,释放,长按保持,长按释放,长长按保持,长长按释放,单击,双击,三击。
KEY_EVENT_NONE
KEY_EVENT_PRESS
KEY_EVENT_RELEASE
KEY_EVENT_LONG_HOLD
KEY_EVENT_LONG_RELEASE
KEY_EVENT_LONG_LONG_HOLD
KEY_EVENT_LONG_LONG_RELEASE
KEY_EVENT_CLICK
KEY_EVENT_DOUBLE_CLICK
KEY_EVENT_TRIPLE_CLICK
#include "bsp_gpio.h"
#include
#include "sys_cmsis.h"
#include "modules.h"
#include "errorno.h"
#include "string.h"
#include "log.h"
#include "key.h"
#define KEY_LOG_EN 0
#if KEY_LOG_EN
#define KEY_LOG_D(str, ...) LOG_D(str, ##__VA_ARGS__)
#define KEY_LOG_I(str, ...) LOG_I(str, ##__VA_ARGS__)
#define KEY_LOG_N(str, ...) LOG_N(str, ##__VA_ARGS__)
#define KEY_LOG_W(str, ...) LOG_W(str, ##__VA_ARGS__)
#define KEY_LOG_E(str, ...) LOG_E(str, ##__VA_ARGS__)
#define KEY_LOG_C(str, ...) LOG_C(str, ##__VA_ARGS__)
#else
#define KEY_LOG_D(str, ...)
#define KEY_LOG_I(str, ...)
#define KEY_LOG_N(str, ...)
#define KEY_LOG_W(str, ...)
#define KEY_LOG_E(str, ...)
#define KEY_LOG_C(str, ...)
#endif
#define KEY_LPRESS_TIME 2000
#define KEY_LLPRESS_TIME 8000
#define KEY_REPEAT_TIME 1000
#define KEY_DBLCLICK_TIME 200
#define KEY_TPLCLICK_TIME 180
typedef enum
{
KEY_STATUS_NONE = 0,
KEY_STATUS_DEBOUNCE = (1 << 0),
KEY_STATUS_FIRST_PRESS = (1 << 1),
KEY_STATUS_FIRST_RELEASE = (1 << 2),
KEY_STATUS_SECOND_PRESS = (1 << 3),
KEY_STATUS_SECOND_RELEASE = (1 << 4),
KEY_STATUS_THIRD_PRESS = (1 << 5),
KEY_STATUS_THIRD_RELEASE = (1 << 6),
} key_status_t;
typedef struct
{
uint8_t status;
uint32_t time;
uint32_t event;
uint32_t flag;
uint32_t long_press_time;
uint32_t long_long_press_time;
key_num_t key_num;
key_cfg_t *p_cfg;
key_evt_cb_t evt_cbk;
} key_hdl_t;
static key_hdl_t g_key_hdl[KEY_NUM];
static sys_timer_id_t g_key_judge_timer_id;
static void key_state_change_handler(void *arg)
{
key_num_t key = *(key_num_t*)arg;
if (g_key_hdl[key].p_cfg->trigger == KEY_TRIGGER_MODE_LEVEL)
{
if (g_key_hdl[key].time < (g_key_hdl[key].p_cfg->effective_interval / KEY_SAMPLE_INTERVAL_MS))
{
return;
}
if (g_key_hdl[key].p_cfg->active_level == bsp_gpio_read(g_key_hdl[key].p_cfg->gpio_num))
{
if (g_key_hdl[key].status == KEY_STATUS_NONE)
{
g_key_hdl[key].status = KEY_STATUS_DEBOUNCE;
g_key_hdl[key].time = 0;
g_key_hdl[key].long_press_time = 0;
g_key_hdl[key].long_long_press_time = 0;
}
}
}
else if (g_key_hdl[key].p_cfg->trigger == KEY_TRIGGER_MODE_PULSE)
{
if (g_key_hdl[key].time < g_key_hdl[key].p_cfg->effective_interval / KEY_SAMPLE_INTERVAL_MS)
{
return;
}
if (g_key_hdl[key].p_cfg->active_level == bsp_gpio_read(g_key_hdl[key].p_cfg->gpio_num))
{
g_key_hdl[key].event |= KEY_EVENT_PRESS;
if (g_key_hdl[key].evt_cbk != NULL)
{
(*g_key_hdl[key].evt_cbk)(key, KEY_EVENT_PRESS);
}
KEY_LOG_D("[key][%d][press]\r\n", key);
}
else if (g_key_hdl[key].p_cfg->active_level != bsp_gpio_read(g_key_hdl[key].p_cfg->gpio_num))
{
g_key_hdl[key].time = 0;
g_key_hdl[key].event |= KEY_EVENT_RELEASE;
if (g_key_hdl[key].evt_cbk != NULL)
{
(*g_key_hdl[key].evt_cbk)(key, KEY_EVENT_RELEASE);
}
KEY_LOG_D("[key][%d][release]\r\n", key);
}
}
}
void key_init(key_num_t key, key_cfg_t *cfg, key_evt_cb_t cbk)
{
memset(&g_key_hdl[key], 0, sizeof(key_hdl_t));
g_key_hdl[key].p_cfg = cfg;
g_key_hdl[key].key_num = key;
g_key_hdl[key].evt_cbk = cbk;
bsp_gpio_register_irq_callback(cfg->gpio_num, key_state_change_handler,
(void *)&g_key_hdl[key].key_num);
bsp_gpio_init(cfg->gpio_num, BSP_GPIO_EXTI_ENABLE);
}
static void key_normal_handle(key_num_t key)
{
if (g_key_hdl[key].p_cfg->active_level == bsp_gpio_read(g_key_hdl[key].p_cfg->gpio_num))
{
if (g_key_hdl[key].status == KEY_STATUS_NONE)
{
g_key_hdl[key].status = KEY_STATUS_DEBOUNCE;
g_key_hdl[key].time = 0;
g_key_hdl[key].long_press_time = 0;
g_key_hdl[key].long_long_press_time = 0;
KEY_LOG_D("[key][%d][normal_handle]\r\n", key);
}
}
}
static void key_debounce_handle(key_num_t key)
{
if (g_key_hdl[key].time >= g_key_hdl[key].p_cfg->debounce_time / KEY_SAMPLE_INTERVAL_MS)
{
g_key_hdl[key].time = 0;
g_key_hdl[key].long_press_time = 0;
g_key_hdl[key].long_long_press_time = 0;
g_key_hdl[key].flag = 0;
g_key_hdl[key].event = 0;
if (g_key_hdl[key].p_cfg->active_level == bsp_gpio_read(g_key_hdl[key].p_cfg->gpio_num))
{
g_key_hdl[key].event |= KEY_EVENT_PRESS;
if (g_key_hdl[key].evt_cbk != NULL)
{
(*g_key_hdl[key].evt_cbk)(key, KEY_EVENT_PRESS);
}
KEY_LOG_D("[key][%d][press]\r\n", key);
g_key_hdl[key].flag |= KEY_EVENT_PRESS;
g_key_hdl[key].status = KEY_STATUS_FIRST_PRESS;
}
else
{
g_key_hdl[key].status = KEY_STATUS_NONE;
}
}
}
static void key_first_press_handle(key_num_t key)
{
if (g_key_hdl[key].p_cfg->active_level == bsp_gpio_read(g_key_hdl[key].p_cfg->gpio_num))
{
if (g_key_hdl[key].long_press_time >= KEY_LPRESS_TIME / KEY_SAMPLE_INTERVAL_MS)
{
g_key_hdl[key].long_press_time = 0;
if ((g_key_hdl[key].event & KEY_EVENT_LONG_HOLD) == 0)
{
g_key_hdl[key].event |= KEY_EVENT_LONG_HOLD;
g_key_hdl[key].flag |= KEY_EVENT_LONG_HOLD;
if (g_key_hdl[key].evt_cbk != NULL)
{
(*g_key_hdl[key].evt_cbk)(key, KEY_EVENT_LONG_HOLD);
}
KEY_LOG_D("[key][%d][long_hold]\r\n", key);
}
}
if (g_key_hdl[key].long_long_press_time >= KEY_LLPRESS_TIME / KEY_SAMPLE_INTERVAL_MS)
{
g_key_hdl[key].long_long_press_time = 0;
if ((g_key_hdl[key].event & KEY_EVENT_LONG_LONG_HOLD) == 0)
{
g_key_hdl[key].event |= KEY_EVENT_LONG_LONG_HOLD;
g_key_hdl[key].flag |= KEY_EVENT_LONG_LONG_HOLD;
if (g_key_hdl[key].evt_cbk != NULL)
{
(*g_key_hdl[key].evt_cbk)(key, KEY_EVENT_LONG_LONG_HOLD);
}
KEY_LOG_D("[key][%d][long_long_hold]\r\n", key);
}
}
}
else
{
g_key_hdl[key].event |= KEY_EVENT_RELEASE;
if (g_key_hdl[key].evt_cbk != NULL)
{
(*g_key_hdl[key].evt_cbk)(key, KEY_EVENT_RELEASE);
}
KEY_LOG_D("[key][%d][release]\r\n", key);
if (g_key_hdl[key].flag & KEY_EVENT_LONG_LONG_HOLD)
{
g_key_hdl[key].flag &= (~KEY_EVENT_LONG_LONG_HOLD);
g_key_hdl[key].event |= KEY_EVENT_LONG_LONG_RELEASE;
if (g_key_hdl[key].evt_cbk != NULL)
{
(*g_key_hdl[key].evt_cbk)(key, KEY_EVENT_LONG_LONG_RELEASE);
}
KEY_LOG_D("[key][%d][long_long_release]\r\n", key);
}
else
{
if (g_key_hdl[key].flag & KEY_EVENT_LONG_HOLD)
{
g_key_hdl[key].flag &= (~KEY_EVENT_LONG_HOLD);
g_key_hdl[key].event |= KEY_EVENT_LONG_RELEASE;
if (g_key_hdl[key].evt_cbk != NULL)
{
(*g_key_hdl[key].evt_cbk)(key, KEY_EVENT_LONG_RELEASE);
}
KEY_LOG_D("[key][%d][long_release]\r\n", key);
}
}
if (g_key_hdl[key].time >= KEY_DBLCLICK_TIME / KEY_SAMPLE_INTERVAL_MS)
{
if (((g_key_hdl[key].event & KEY_EVENT_LONG_LONG_HOLD) == 0) &&
((g_key_hdl[key].event & KEY_EVENT_LONG_HOLD) == 0))
{
g_key_hdl[key].event |= KEY_EVENT_CLICK;
if (g_key_hdl[key].evt_cbk != NULL)
{
(*g_key_hdl[key].evt_cbk)(key, KEY_EVENT_CLICK);
}
KEY_LOG_D("[key][%d][click_1]\r\n", key);
}
g_key_hdl[key].status = KEY_STATUS_NONE;
}
else
{
g_key_hdl[key].time = 0;
g_key_hdl[key].status = KEY_STATUS_FIRST_RELEASE;
}
}
}
static void key_first_release_handle(key_num_t key)
{
if (g_key_hdl[key].time <= KEY_DBLCLICK_TIME / KEY_SAMPLE_INTERVAL_MS)
{
if (g_key_hdl[key].p_cfg->active_level == bsp_gpio_read(g_key_hdl[key].p_cfg->gpio_num))
{
g_key_hdl[key].time = 0;
g_key_hdl[key].status = KEY_STATUS_SECOND_PRESS;
}
}
else
{
if (g_key_hdl[key].p_cfg->active_level != bsp_gpio_read(g_key_hdl[key].p_cfg->gpio_num))
{
g_key_hdl[key].event |= KEY_EVENT_CLICK;
if (g_key_hdl[key].evt_cbk != NULL)
{
(*g_key_hdl[key].evt_cbk)(key, KEY_EVENT_CLICK);
}
KEY_LOG_D("[key][%d][click_2]\r\n", key);
g_key_hdl[key].status = KEY_STATUS_NONE;
}
}
}
static void key_second_press_handle(key_num_t key)
{
if (g_key_hdl[key].time <= KEY_DBLCLICK_TIME / KEY_SAMPLE_INTERVAL_MS)
{
if (g_key_hdl[key].p_cfg->active_level != bsp_gpio_read(g_key_hdl[key].p_cfg->gpio_num))
{
g_key_hdl[key].time = 0;
g_key_hdl[key].status = KEY_STATUS_SECOND_RELEASE;
}
}
else
{
g_key_hdl[key].event |= KEY_EVENT_CLICK;
if (g_key_hdl[key].evt_cbk != NULL)
{
(*g_key_hdl[key].evt_cbk)(key, KEY_EVENT_CLICK);
}
KEY_LOG_D("[key][%d][click_3]\r\n", key);
g_key_hdl[key].time = 0;
g_key_hdl[key].long_press_time = 0;
g_key_hdl[key].long_long_press_time = 0;
g_key_hdl[key].status = KEY_STATUS_FIRST_PRESS;
}
}
static void key_second_release_handle(key_num_t key)
{
if (g_key_hdl[key].time <= KEY_TPLCLICK_TIME / KEY_SAMPLE_INTERVAL_MS)
{
if (g_key_hdl[key].p_cfg->active_level == bsp_gpio_read(g_key_hdl[key].p_cfg->gpio_num))
{
g_key_hdl[key].time = 0;
g_key_hdl[key].status = KEY_STATUS_THIRD_PRESS;
}
}
else
{
g_key_hdl[key].event |= KEY_EVENT_DOUBLE_CLICK;
if (g_key_hdl[key].evt_cbk != NULL)
{
(*g_key_hdl[key].evt_cbk)(key, KEY_EVENT_DOUBLE_CLICK);
}
KEY_LOG_D("[key][%d][double_click_1]\r\n", key);
g_key_hdl[key].status = KEY_STATUS_NONE;
}
}
static void key_third_press_handle(key_num_t key)
{
if (g_key_hdl[key].time <= KEY_TPLCLICK_TIME / KEY_SAMPLE_INTERVAL_MS)
{
if (g_key_hdl[key].p_cfg->active_level != bsp_gpio_read(g_key_hdl[key].p_cfg->gpio_num))
{
g_key_hdl[key].time = 0;
g_key_hdl[key].event |= KEY_EVENT_TRIPLE_CLICK;
if (g_key_hdl[key].evt_cbk != NULL)
{
(*g_key_hdl[key].evt_cbk)(key, KEY_EVENT_TRIPLE_CLICK);
}
KEY_LOG_D("[key][%d][triple_click]\r\n", key);
g_key_hdl[key].status = KEY_STATUS_NONE;
}
}
else
{
g_key_hdl[key].event |= KEY_EVENT_DOUBLE_CLICK;
if (g_key_hdl[key].evt_cbk != NULL)
{
(*g_key_hdl[key].evt_cbk)(key, KEY_EVENT_DOUBLE_CLICK);
}
KEY_LOG_D("[key][%d][double_click_2]\r\n", key);
g_key_hdl[key].time = 0;
g_key_hdl[key].long_press_time = 0;
g_key_hdl[key].long_long_press_time = 0;
g_key_hdl[key].status = KEY_STATUS_FIRST_PRESS;
}
}
static void key_judge_timer_handle(void const *arg)
{
uint8_t i;
for (i = 0; i < KEY_NUM; i++)
{
g_key_hdl[i].time ++;
g_key_hdl[i].long_press_time ++;
g_key_hdl[i].long_long_press_time ++;
}
for (i = 0; i < KEY_NUM; i++)
{
if (g_key_hdl[i].p_cfg->trigger == KEY_TRIGGER_MODE_PULSE)
{
continue;
}
switch (g_key_hdl[i].status)
{
case KEY_STATUS_NONE:
{
key_normal_handle(i);
}
break;
case KEY_STATUS_DEBOUNCE:
{
key_debounce_handle(i);
}
break;
case KEY_STATUS_FIRST_PRESS:
{
key_first_press_handle(i);
}
break;
case KEY_STATUS_FIRST_RELEASE:
{
key_first_release_handle(i);
}
break;
case KEY_STATUS_SECOND_PRESS:
{
key_second_press_handle(i);
}
break;
case KEY_STATUS_SECOND_RELEASE:
{
key_second_release_handle(i);
}
break;
case KEY_STATUS_THIRD_PRESS:
{
key_third_press_handle(i);
}
break;
case KEY_STATUS_THIRD_RELEASE:
{
;
}
break;
default:
break;
}
}
}
SYS_TIMER_DEF(key_judge_timer, key_judge_timer_handle);
static void key_module_init(void)
{
sys_status status;
g_key_judge_timer_id = sys_timer_create(SYS_TIMER(key_judge_timer), SYS_TIMER_PERIODIC, NULL);
if (g_key_judge_timer_id)
{
status = sys_timer_start(g_key_judge_timer_id, KEY_SAMPLE_INTERVAL_MS);
if (status != RETVAL(E_OK))
{
KEY_LOG_E("[key][key_module_init] failed %d\r\n", status);
}
}
}
APP_INITCALL("key_module", key_module_init);
#ifndef __KEY_H__
#define __KEY_H__
#include "typedefs.h"
typedef enum
{
KEY0_POWER,
KEY1_HALL,
KEY2_USB,
KEY_NUM,
} key_num_t;
#define KEY_SAMPLE_INTERVAL_MS 10
typedef enum
{
KEY_EVENT_NONE = 0,
KEY_EVENT_PRESS = (1 << 0),
KEY_EVENT_RELEASE = (1 << 1),
KEY_EVENT_LONG_HOLD = (1 << 2),
KEY_EVENT_LONG_RELEASE = (1 << 3),
KEY_EVENT_LONG_LONG_HOLD = (1 << 4),
KEY_EVENT_LONG_LONG_RELEASE = (1 << 5),
KEY_EVENT_CLICK = (1 << 6),
KEY_EVENT_DOUBLE_CLICK = (1 << 7),
KEY_EVENT_TRIPLE_CLICK = (1 << 8),
} key_event_t;
typedef enum
{
KEY_ACTIVE_LEVEL_LOW = 0,
KEY_ACTIVE_LEVEL_HIGH,
} key_active_level_t;
typedef enum
{
KEY_TRIGGER_MODE_PULSE,
KEY_TRIGGER_MODE_LEVEL,
} key_trigger_t;
typedef struct
{
uint8_t gpio_num;
uint8_t debounce_time;
uint16_t effective_interval;
key_trigger_t trigger;
key_active_level_t active_level;
} key_cfg_t;
typedef void (*key_evt_cb_t)(key_num_t key, uint32_t event);
void key_init(key_num_t key, key_cfg_t *cfg, key_evt_cb_t cbk);
#endif //__KEY_H__
最新代码请去gitee获取:跳转