1.按键.h文件
#include <stdint.h>
#include <string.h>
#define BTN_NAME_MAX 10
/* 按键循环20ms */
#define BTN_DEBOUNCE_TIME 1 // 消抖周期
#define BTN_DOUBLE_TIME 15 // 双击间隔周期
#define BTN_LONG_TIME 50 // 长按检测周期
typedef void (*BTN_CALLBACK)(void *);
//初始化按键电平
typedef enum
{
BTN_LEVEL_LOW = 0, // 低电平
BTN_LEVEL_HIGH, // 高电平
} BTN_LEVEL;
//按键状态
typedef enum
{
BTN_DOWM = 0, // 按下
BTN_UP, // 松开
BTN_NONE, // 无事件
} BTN_STATE;
//按键事件
typedef enum
{
BTN_EV_CLICK_RISE = 0, // 单击弹起
BTN_EV_CLICK_DROP, // 单机按下
BTN_EV_DOUBLE_CLICK, // 双击弹起
BTN_EV_LONG_CLICK_RISE, // 长按弹起
BTN_EV_LONG_CLICK_DROP, // 长按按下
BTN_EV_CNT, // 辅助用于统计事件个数
BTN_EV_NULL, // 无事件发生
} BTN_EVENT;
typedef struct __BTN_HandleTypedef
{
uint8_t (*read_btn_level)(void); /* 读取按键电平函数 */
char name[BTN_NAME_MAX]; /* 按键名称 */
uint8_t button_state : 2; /* 按键状态 */
uint8_t button_last_state : 2; /* 上一次的按键状态,判断双击 */
uint8_t button_trigger_level : 2; /* 按键触发电平 */
uint8_t button_last_level : 2; /* 上一次按键电平 */
BTN_EVENT event; /* 按键触发事件,单击,双击,长按 */
BTN_EVENT last_event;
BTN_CALLBACK callback[BTN_EV_CNT]; /* 按键函数指针 */
uint8_t button_trigger_cnt; /* 双击检测周期内按键触发次数 */
uint16_t timer_count; /* 计数值 */
uint16_t debounce_count; /* 消抖计数值 */
struct __BTN_HandleTypedef *next; /* 链表指针 */
} BTN_HandleTypedef;
2.按键.c文件
static struct __BTN_HandleTypedef *button_head = NULL;
/*********************************************************************
* @fn Driver_Button_List_Process
*
* @brief 按键链表进程.
*
* @param none
*
* @return none
*/
void Driver_Button_List_Process(void)
{
struct __BTN_HandleTypedef *pass_btn;
for(pass_btn = button_head; pass_btn != NULL; pass_btn = pass_btn->next)
{
Driver_Button_List_Cycle_Process(pass_btn);
}
}
/*********************************************************************
* @fn Driver_Button_List_Delete
*
* @brief 按键初链表删除.
*
* @param btn:按键句柄
*
* @return none
*/
void Driver_Button_List_Delete(BTN_HandleTypedef *btn)
{
struct __BTN_HandleTypedef **curr;
struct __BTN_HandleTypedef *entry;
if(btn == NULL)
return;
curr = &button_head;
while(*curr != NULL)
{
entry = *curr;
if (entry == btn)
*curr = entry->next;
else
curr = &entry->next;
}
}
/*********************************************************************
* @fn Driver_Button_List_Add
*
* @brief 按键链表添加.
*
* @param none
*
* @return none
*/
static void Driver_Button_List_Add(BTN_HandleTypedef *btn)
{
btn->next = button_head;
button_head = btn;
}
/*********************************************************************
* @fn Driver_Button_List_Create
*
* @brief 按键初链表创建.
*
* @param name:按键名称
*
* @param btn:按键句柄
*
* @param read_btn_level:读取按键电平
*
* @param btn_trigger_level:电平初始化状态
*
* @return none
*/
static void Driver_Button_List_Create(const char *name, BTN_HandleTypedef *btn, uint8_t (*read_btn_level)(void), uint8_t btn_trigger_level)
{
if(btn == NULL)
{
return;
}
memset(btn, 0, sizeof(struct __BTN_HandleTypedef));
strncpy(btn->name, name, BTN_NAME_MAX);
btn->button_state = BTN_NONE;
btn->button_last_state = BTN_NONE;
btn->event = BTN_EV_NULL;
btn->last_event = BTN_EV_NULL;
btn->read_btn_level = read_btn_level;
btn->button_trigger_level = btn_trigger_level;
btn->button_last_level = btn->read_btn_level();
btn->debounce_count = 0;
btn->timer_count = 0;
btn->button_trigger_cnt = 0;
Driver_Button_List_Add(btn);
}
/*********************************************************************
* @fn Driver_Button_List_Create_Callback
*
* @brief 按键链表创建事件回调函数.
*
* @param btn:按键句柄
*
* @param btn_event:按键事件名称
*
* @param btn_callback:按键回调函数
*
* @return none
*/
static void Driver_Button_List_Create_Callback(BTN_HandleTypedef *btn, BTN_EVENT btn_event, BTN_CALLBACK btn_callback)
{
if(btn == NULL)
{
return;
}
btn->callback[btn_event] = btn_callback;
}
/*********************************************************************
* @fn Driver_Button_List_Process
*
* @brief 按键链表进程.
*
* @param btn:按键句柄
*
* @return none
*/
static void Driver_Button_List_Cycle_Process(BTN_HandleTypedef *btn)
{
uint8_t current_level = (uint8_t)btn->read_btn_level();
if((current_level != btn->button_last_level) && (++btn->debounce_count >= BTN_DEBOUNCE_TIME))
{
btn->button_last_level = current_level;
btn->debounce_count = 0;
if(btn->button_trigger_level == current_level)
{
btn->button_state = BTN_DOWM;
btn->event = BTN_EV_CLICK_DROP;
btn->timer_count = 0;
}
else
{
btn->button_state = BTN_UP;
}
}
btn->timer_count++;
switch(btn->button_state)
{
case BTN_DOWM:
if(btn->timer_count > BTN_LONG_TIME && btn->button_last_level == current_level)
{
if(btn->timer_count % 4 == 0)
{
btn->event = BTN_EV_LONG_CLICK_DROP;
btn->last_event = BTN_EV_LONG_CLICK_DROP;
btn->button_state = BTN_NONE;
goto button_even;
}
}
if(btn->event == BTN_EV_CLICK_DROP)
{
goto button_even;
}
break;
case BTN_UP:
if(btn->last_event == BTN_EV_LONG_CLICK_DROP)
{
btn->last_event = BTN_EV_NULL;
btn->event = BTN_EV_LONG_CLICK_RISE;
goto button_even;
}
if(btn->timer_count < BTN_DOUBLE_TIME)
{
if(btn->button_last_state == BTN_DOWM)
{
btn->button_trigger_cnt++;
btn->timer_count = 0;
}
}
if(btn->timer_count > BTN_DOUBLE_TIME)
{
btn->timer_count = 0;
if (btn->button_trigger_cnt == 1)
{
btn->event = BTN_EV_CLICK_RISE;
}
else if (btn->button_trigger_cnt > 1)
{
btn->event = BTN_EV_DOUBLE_CLICK;
}
btn->button_trigger_cnt = 0;
btn->timer_count = 0;
}
break;
case BTN_NONE:
break;
default:
break;
}
button_even:
btn->button_last_state = btn->button_state;
if(btn->event < BTN_EV_CNT && btn->callback[btn->event] != NULL)
{
btn->callback[btn->event](btn);
btn->event = BTN_EV_NULL;
}
}
3.例程
重写读按键口函数
static uint8_t read_ok_key(void)
{
return HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_7);
}
创建按键事件回调函数(每个事件可以单独创建回调函数,这里省事就公用一个了)
static void key_ok_callback(void *btn)
{
BTN_HandleTypedef *button = (BTN_HandleTypedef *)btn;
switch(button->event)
{
case BTN_EV_CLICK_RISE:
if(strncmp(button->name, "ok_key", BTN_NAME_MAX) == 0)
{
//Debug("click rise");
}
break;
case BTN_EV_CLICK_DROP:
if(strncmp(button->name, "ok_key", BTN_NAME_MAX) == 0)
{
//Debug("click drop");
}
break;
case BTN_EV_DOUBLE_CLICK:
if(strncmp(button->name, "ok_key", BTN_NAME_MAX) == 0)
{
//Debug("click double");
}
break;
case BTN_EV_LONG_CLICK_RISE:
if(strncmp(button->name, "ok_key", BTN_NAME_MAX) == 0)
{
//Debug("click long rise");
}
break;
case BTN_EV_LONG_CLICK_DROP:
if(strncmp(button->name, "ok_key", BTN_NAME_MAX) == 0)
{
//Debug("click long drop");
}
break;
default:
//Debug("click error");
break;
}
}
初始化按键
void Driver_Button_List_Init(void)
{
static BTN_HandleTypedef OK_key;
Driver_Button_List_Create("ok_key", &OK_key, read_ok_key, BTN_LEVEL_HIGH);
Driver_Button_List_Create_Callback(&OK_key, BTN_EV_CLICK_RISE, key_ok_callback);
Driver_Button_List_Create_Callback(&OK_key, BTN_EV_CLICK_DROP, key_ok_callback);
Driver_Button_List_Create_Callback(&OK_key, BTN_EV_DOUBLE_CLICK, key_ok_callback);
Driver_Button_List_Create_Callback(&OK_key, BTN_EV_LONG_CLICK_RISE, key_ok_callback);
Driver_Button_List_Create_Callback(&OK_key, BTN_EV_LONG_CLICK_DROP, key_ok_callback);
}