/* * Copyright (c) 2016 Zibin Zheng * All rights reserved. */ #include "multi_button.h" /* 回调执行宏,包含空值检查,传递user_data */ #define EVENT_CB(ev) do { if (handle->cb[ev]) handle->cb[ev](handle, handle->user_data); } while(0) /* 按键句柄链表头 */ static Button* head_handle = NULL; /* 前向声明 */ static void button_handler(Button* handle); static inline uint8_t button_read_level(Button* handle); /* * 函数功能:初始化按键结构体句柄 * 入口参数:handle - 按键句柄结构体指针 * pin_level - 读取按键GPIO电平的函数指针 * active_level - 按下时的有效电平 * button_id - 按键标识符 * 返回值:无 * 函数说明:初始化按键状态机和所有参数 */ void button_init(Button* handle, uint8_t(*pin_level)(uint8_t), uint8_t active_level, uint8_t button_id) { if (!handle || !pin_level) { return; } memset(handle, 0, sizeof(Button)); handle->event = (uint8_t)BTN_NONE_PRESS; handle->hal_button_level = pin_level; handle->button_level = !active_level; handle->active_level = active_level; handle->button_id = button_id; handle->state = BTN_STATE_IDLE; } /* * 函数功能:绑定按键事件回调函数 * 入口参数:handle - 按键句柄结构体指针 * event - 触发事件类型 * cb - 回调函数 * user_data - 传递给回调的用户上下文指针 * 返回值:无 * 函数说明:为指定事件注册回调函数 */ void button_attach(Button* handle, ButtonEvent event, BtnCallback cb, void* user_data) { if (!handle || event >= BTN_EVENT_COUNT) { return; } handle->cb[event] = cb; handle->user_data = user_data; } /* * 函数功能:解绑按键事件回调函数 * 入口参数:handle - 按键句柄结构体指针 * event - 触发事件类型 * 返回值:无 * 函数说明:移除指定事件的回调函数 */ void button_detach(Button* handle, ButtonEvent event) { if (!handle || event >= BTN_EVENT_COUNT) { return; } handle->cb[event] = NULL; } /* * 函数功能:获取按键事件 * 入口参数:handle - 按键句柄结构体指针 * 返回值:按键事件 * 函数说明:返回当前发生的按键事件 */ ButtonEvent button_get_event(Button* handle) { if (!handle) { return BTN_NONE_PRESS; } return (ButtonEvent)(handle->event); } /* * 函数功能:获取按键重复按下次数 * 入口参数:handle - 按键句柄结构体指针 * 返回值:重复按下次数 * 函数说明:返回连击次数 */ uint8_t button_get_repeat_count(Button* handle) { if (!handle) { return 0; } return handle->repeat; } /* * 函数功能:重置按键状态到空闲 * 入口参数:handle - 按键句柄结构体指针 * 返回值:无 * 函数说明:将按键状态机重置为初始状态 */ void button_reset(Button* handle) { if (!handle) { return; } handle->state = BTN_STATE_IDLE; handle->ticks = 0; handle->repeat = 0; handle->event = (uint8_t)BTN_NONE_PRESS; handle->debounce_cnt = 0; } /* * 函数功能:检查按键是否按下 * 入口参数:handle - 按键句柄结构体指针 * 返回值:1 - 按下,0 - 未按下,-1 - 错误 * 函数说明:检查当前按键是否处于按下状态 */ int button_is_pressed(Button* handle) { if (!handle) { return -1; } return (handle->button_level == handle->active_level) ? 1 : 0; } /* * 函数功能:读取按键电平 * 入口参数:handle - 按键句柄结构体指针 * 返回值:按键电平 * 函数说明:通过HAL函数读取GPIO电平 */ static inline uint8_t button_read_level(Button* handle) { return handle->hal_button_level(handle->button_id); } /* * 函数功能:按键驱动核心函数,驱动状态机 * 入口参数:handle - 按键句柄结构体指针 * 返回值:无 * 函数说明:实现按键消抖和事件检测的状态机 */ static void button_handler(Button* handle) { uint8_t read_gpio_level = button_read_level(handle); /* 非空闲状态下增加tick计数器(饱和处理) */ if (handle->state > BTN_STATE_IDLE) { if (handle->ticks < UINT16_MAX) { handle->ticks++; } } /* 按键消抖处理 */ if (read_gpio_level != handle->button_level) { if (++(handle->debounce_cnt) >= DEBOUNCE_TICKS) { handle->button_level = read_gpio_level; handle->debounce_cnt = 0; } } else { handle->debounce_cnt = 0; } /* 状态机 */ switch (handle->state) { case BTN_STATE_IDLE: if (handle->button_level == handle->active_level) { /* 检测到按键按下 */ handle->event = (uint8_t)BTN_PRESS_DOWN; EVENT_CB(BTN_PRESS_DOWN); handle->ticks = 0; handle->repeat = 1; handle->state = BTN_STATE_PRESS; } else { handle->event = (uint8_t)BTN_NONE_PRESS; } break; case BTN_STATE_PRESS: if (handle->button_level != handle->active_level) { /* 按键释放 */ handle->event = (uint8_t)BTN_PRESS_UP; EVENT_CB(BTN_PRESS_UP); handle->ticks = 0; handle->state = BTN_STATE_RELEASE; } else if (handle->ticks > LONG_TICKS) { /* 检测到长按 */ handle->event = (uint8_t)BTN_LONG_PRESS_START; EVENT_CB(BTN_LONG_PRESS_START); handle->state = BTN_STATE_LONG_HOLD; } break; case BTN_STATE_RELEASE: if (handle->button_level == handle->active_level) { /* 按键再次按下 */ handle->event = (uint8_t)BTN_PRESS_DOWN; EVENT_CB(BTN_PRESS_DOWN); if (handle->repeat < PRESS_REPEAT_MAX_NUM) { handle->repeat++; } handle->event = (uint8_t)BTN_PRESS_REPEAT; EVENT_CB(BTN_PRESS_REPEAT); handle->ticks = 0; handle->state = BTN_STATE_REPEAT; } else if (handle->ticks > SHORT_TICKS) { /* 超时,判断点击类型 */ if (handle->repeat == 1) { handle->event = (uint8_t)BTN_SINGLE_CLICK; EVENT_CB(BTN_SINGLE_CLICK); } else if (handle->repeat == 2) { handle->event = (uint8_t)BTN_DOUBLE_CLICK; EVENT_CB(BTN_DOUBLE_CLICK); } handle->state = BTN_STATE_IDLE; } break; case BTN_STATE_REPEAT: if (handle->button_level != handle->active_level) { /* 按键释放 */ handle->event = (uint8_t)BTN_PRESS_UP; EVENT_CB(BTN_PRESS_UP); if (handle->ticks < SHORT_TICKS) { handle->ticks = 0; handle->state = BTN_STATE_RELEASE; } else { handle->state = BTN_STATE_IDLE; } } else if (handle->ticks > SHORT_TICKS) { /* 按住时间过长,视为普通按下 */ handle->ticks = 0; handle->repeat = 0; handle->state = BTN_STATE_PRESS; } break; case BTN_STATE_LONG_HOLD: if (handle->button_level == handle->active_level) { /* 继续保持按下 */ handle->event = (uint8_t)BTN_LONG_PRESS_HOLD; EVENT_CB(BTN_LONG_PRESS_HOLD); } else { /* 从长按中释放 */ handle->event = (uint8_t)BTN_PRESS_UP; EVENT_CB(BTN_PRESS_UP); handle->state = BTN_STATE_IDLE; } break; default: /* 无效状态,重置为空闲 */ handle->state = BTN_STATE_IDLE; break; } } /* * 函数功能:启动按键工作,将句柄添加到工作链表 * 入口参数:handle - 目标句柄结构体指针 * 返回值:0 - 成功,-1 - 已存在,-2 - 无效参数 * 函数说明:将按键添加到轮询链表中 */ int button_start(Button* handle) { if (!handle) { return -2; } Button* target = head_handle; while (target) { if (target == handle) { return -1; } target = target->next; } handle->next = head_handle; head_handle = handle; return 0; } /* * 函数功能:停止按键工作,从工作链表移除句柄 * 入口参数:handle - 目标句柄结构体指针 * 返回值:无 * 函数说明:将按键从轮询链表中移除 */ void button_stop(Button* handle) { if (!handle) { return; } Button** curr; for (curr = &head_handle; *curr; ) { Button* entry = *curr; if (entry == handle) { *curr = entry->next; entry->next = NULL; return; } else { curr = &entry->next; } } } /* * 函数功能:后台tick处理,定时器重复调用,间隔5ms * 入口参数:无 * 返回值:无 * 函数说明:遍历链表调用每个按键的状态机处理函数 */ void button_ticks(void) { Button* target; Button* next; target = head_handle; while (target) { next = target->next; button_handler(target); target = next; } }