软件SPI可以驱动屏幕

This commit is contained in:
2026-07-14 14:44:07 +08:00
parent 3577003fb6
commit 0a5c478a42
53 changed files with 9354 additions and 87 deletions

View File

@@ -0,0 +1,334 @@
/*
* Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
* 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;
}
}