From 2ab5a97ac309c7c4161884f98a4878e89d888532 Mon Sep 17 00:00:00 2001 From: OPTOC <9159397+optoc@user.noreply.gitee.com> Date: Thu, 28 Aug 2025 16:03:47 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8C=89=E9=94=AE=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/CMakeLists.txt | 3 + app/drivers/pin_io/pin_io.c | 102 +++++++++++++++++++++++ app/drivers/pin_io/pin_io.h | 23 +++++ app/drivers/sertrf/key.c | 162 ++++++++++++++++++++++++++++++++++++ app/drivers/sertrf/key.h | 48 +++++++++++ 5 files changed, 338 insertions(+) create mode 100644 app/drivers/pin_io/pin_io.c create mode 100644 app/drivers/pin_io/pin_io.h create mode 100644 app/drivers/sertrf/key.c create mode 100644 app/drivers/sertrf/key.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 7a0f5ef..e21efaf 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -29,10 +29,13 @@ list(APPEND srcs "utils/sb_aes.c") list(APPEND srcs "drivers/sertrf/sertrf.c") list(APPEND srcs "drivers/sertrf/device.c") +list(APPEND srcs "drivers/sertrf/key.c") list(APPEND srcs "drivers/led_strip/led_strip.c") list(APPEND srcs "drivers/led_strip/led_strip_encoder.c") +list(APPEND srcs "drivers/pin_io/pin_io.c") + if(CONFIG_BUILD_BLE) list(APPEND srcs "drivers/data_port/ble_spp/ble_spp_server.c") list(APPEND srcs "drivers/data_port/ble_spp/ble_spp_server_shell.c") diff --git a/app/drivers/pin_io/pin_io.c b/app/drivers/pin_io/pin_io.c new file mode 100644 index 0000000..e2592c9 --- /dev/null +++ b/app/drivers/pin_io/pin_io.c @@ -0,0 +1,102 @@ +#include "pin_io.h" + +/* 配置 */ +#include "config/board_config.h" +#include "config/app_config.h" +#include "config/app_log.h" + +#if defined(CONFIG_CAP_LED_STRIP) +#include "led_strip/config/led_strip_config.h" +#endif + +/* SDK */ +#include "driver/gpio.h" + +/* 通用模块 */ +#include "button/button.h" + +#include "os/os.h" + +#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_INF +#define SYS_LOG_DOMAIN "PIN" +#include "sys_log.h" + +/** + * @brief IO 基本操作:配置为通用输入 + * + * @param pin 0..n + */ +void pin_cfg_input(const cfg_board_pin_io_t *pin) +{ + if (GPIO_USED(pin->pin) == false) + { + SYS_LOG_WRN("pin %d not used", pin->pin); + return; + } + + gpio_config_t io_conf; + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pull_up_en = (pin->en_lev == 0 ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE); + io_conf.pull_down_en = (pin->en_lev ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE); + io_conf.pin_bit_mask = 1ULL << pin->pin; + io_conf.intr_type = GPIO_INTR_DISABLE; + gpio_config(&io_conf); +} + +/** + * @brief IO 基本操作:获取当前输入电平是否为有效的电平 + * + * @param pin 0..n + * @retval true 对应预设为有效的电平 + * @retval false 对应预设为非有效的电平 + */ +bool pin_get_valid(const cfg_board_pin_io_t *pin) +{ + if (GPIO_USED(pin->pin) == false) + { + SYS_LOG_WRN("pin %d not used", pin->pin); + return false; + } + + return gpio_get_level(pin->pin) ^ !pin->en_lev; +} + +/** + * @brief IO 基本操作:配置为通用输出 + * + * @param pin 0..n + */ +void pin_cfg_output(const cfg_board_pin_io_t *pin) +{ + if (GPIO_USED(pin->pin) == false) + { + SYS_LOG_WRN("pin %d not used", pin->pin); + return; + } + + gpio_config_t io_conf; + io_conf.mode = GPIO_MODE_INPUT_OUTPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE; + io_conf.pin_bit_mask = 1ULL << pin->pin; + io_conf.intr_type = GPIO_INTR_DISABLE; + gpio_config(&io_conf); +} + +/** + * @brief IO 基本操作:设置使输出是否为有效的电平 + * + * @param pin 0..n + * @param en false: 使输出为对应预设为非有效的电平; true: 使输出为对应预设为有效的电平 + */ +void pin_set_valid(const cfg_board_pin_io_t *pin, bool en) +{ + if (GPIO_USED(pin->pin) == false) + { + SYS_LOG_WRN("pin %d not used", pin->pin); + return; + } + + gpio_set_level((gpio_num_t)pin->pin, !pin->en_lev ^ !!en); +} + diff --git a/app/drivers/pin_io/pin_io.h b/app/drivers/pin_io/pin_io.h new file mode 100644 index 0000000..913a614 --- /dev/null +++ b/app/drivers/pin_io/pin_io.h @@ -0,0 +1,23 @@ +/** + * @file pin_io.h + * @author LokLiang + * @brief 1. GPIO 的基本驱动, 2. 控制板载电压的开关 + * @version 0.1 + * @date 2024-04-16 + * + * @copyright Copyright (c) 2024 + * + */ + +#pragma once + +#include "sys_types.h" +#include "config/board_config.h" + +void pin_cfg_input(const cfg_board_pin_io_t *pin); +bool pin_get_valid(const cfg_board_pin_io_t *pin); + +void pin_cfg_output(const cfg_board_pin_io_t *pin); +void pin_set_valid(const cfg_board_pin_io_t *pin, bool en); + + diff --git a/app/drivers/sertrf/key.c b/app/drivers/sertrf/key.c new file mode 100644 index 0000000..a39cac4 --- /dev/null +++ b/app/drivers/sertrf/key.c @@ -0,0 +1,162 @@ +#include "key.h" + +button_t btn; + +cfg_board_pin_io_t key_switch = { + .pin = 9, + .en_lev = 0,}; +// 新增事件类型 +// EVT_DOUBLE_CLICK: 双击 +// EVT_SINGLE_LONG_PRESS: 单击后长按 + +bool key_single_click = 0,key_press_down = 0,key_press_up = 0; + + +// 用户在此处理按键事件 +static void my_button_handler(button_event_t evt) { + switch (evt) { + case EVT_PRESS_DOWN: //按下 + // SYS_LOG_INF("[Event] PRESS_DOWN"); + key_press_down = true; + key_press_up = false; + break; + case EVT_PRESS_UP: //松开 + // SYS_LOG_INF("[Event] PRESS_UP"); + key_press_up = true; + key_press_down = false; + break; + case EVT_SINGLE_CLICK: //单击 + key_single_click = true; + // SYS_LOG_INF("[Event] SINGLE_CLICK"); + break; + case EVT_DOUBLE_CLICK: //双击 + // SYS_LOG_INF("[Event] DOUBLE_CLICK"); + break; + case EVT_LONG_PRESS: //长按 + // SYS_LOG_INF("[Event] LONG_PRESS"); + break; + case EVT_SINGLE_LONG_PRESS: //单击后长按 + wifi_mode_switch(NULL); + SYS_LOG_INF("[Event] SINGLE_LONG_PRESS"); + break; + default: break; + } +} + +// 初始化按键 +static void button_init(button_t *btn, bool (*read_pin)(void), button_cb_t cb) { + btn->read_pin = read_pin; + btn->callback = cb; + btn->stable_state = read_pin() ? 1 : 0; + btn->debounce_cnt = 0; + btn->tick_cnt = 0; + btn->state = 0; + btn->click_count = 0; // 新增计数 +} + +// 每次调用间隔 5ms (os_work_later 参数) +static void button_scan(button_t *btn) { + bool level = btn->read_pin(); + + // 防抖 + if (level != btn->stable_state) { + if (++btn->debounce_cnt >= DEBOUNCE_TICKS) { + btn->stable_state = level; + btn->debounce_cnt = 0; + } + } else { + btn->debounce_cnt = 0; + } + + switch (btn->state) { + case 0: // 空闲->按下 + if (btn->stable_state) { + btn->callback(EVT_PRESS_DOWN); + btn->tick_cnt = 0; + btn->state = 1; + } + break; + + case 1: // 按下计时 + btn->tick_cnt++; + if (!btn->stable_state) { + // 松开 + btn->callback(EVT_PRESS_UP); + if (btn->tick_cnt < LONG_PRESS_TICKS) { + // 短按,统计点击次数 + btn->click_count++; + btn->tick_cnt = 0; + btn->state = 2; // 等待双击 + } else { + // 长按释放 + btn->callback(EVT_LONG_PRESS); + btn->click_count = 0; + btn->state = 0; + } + } else if (btn->tick_cnt >= LONG_PRESS_TICKS) { + // 长按开始 + // 可加 EVT_LONG_PRESS_START 如需区分开始和持续 + } + break; + + case 2: // 等待双击或单击后长按 + btn->tick_cnt++; + if (btn->stable_state) { + // 再次按下 + if (btn->click_count == 1) { + btn->callback(EVT_PRESS_DOWN); + btn->state = 3; // 第二次按下 + btn->tick_cnt = 0; + } + } else if (btn->tick_cnt > DOUBLE_CLICK_WINDOW) { + // 超过双击时间窗口 + if (btn->click_count == 1) { + btn->callback(EVT_SINGLE_CLICK); + } + btn->click_count = 0; + btn->state = 0; + } + break; + + case 3: // 第二次按下状态 + btn->tick_cnt++; + if (!btn->stable_state) { + // 第二次松开 -> 双击 + btn->callback(EVT_PRESS_UP); + if (btn->tick_cnt < LONG_PRESS_TICKS) { + btn->callback(EVT_DOUBLE_CLICK); + } else { + // 单击后长按 + btn->callback(EVT_SINGLE_LONG_PRESS); + } + btn->click_count = 0; + btn->state = 0; + } + break; + + default: + btn->state = 0; + btn->click_count = 0; + break; + } +} + +static bool read_button_pin(void) { + // HAL_GPIO_ReadPin == GPIO_PIN_SET(1) 时,表示松开 + // return pin_get_valid(&g_cfg_board->key_switch_mode); + return pin_get_valid(&key_switch); +} + +//添加自定义初始化 +void _work_button(void *arg) { + button_scan(&btn); + os_work_later(10); +} + +void button_work_init() { + button_init(&btn, read_button_pin, my_button_handler); + + static os_work_t work_handler_button; + os_work_create(&work_handler_button, "work-button", _work_button, NULL, OS_PRIORITY_NORMAL); + os_work_submit(default_os_work_q_hdl, &work_handler_button, 10); +} diff --git a/app/drivers/sertrf/key.h b/app/drivers/sertrf/key.h new file mode 100644 index 0000000..572cb92 --- /dev/null +++ b/app/drivers/sertrf/key.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include // 如果在裸机下,用平台自带的延时函数替代 +#include "../pin_io/pin_io.h" +#include "../../config/board_config.h" +#include "../../config/app_config.h" +#include "sys_log.h" +#include "os/os.h" +#include "device.h" + +// 按键事件类型 +typedef enum { + EVT_NONE = 0, // 无事件 + EVT_PRESS_DOWN, // 按下 + EVT_PRESS_UP, // 松开 + EVT_SINGLE_CLICK, // 单击 + EVT_DOUBLE_CLICK, // 双击 + EVT_LONG_PRESS, // 长按释放 + EVT_SINGLE_LONG_PRESS // 单击后长按 +} button_event_t; + +// 回调函数原型 +typedef void (*button_cb_t)(button_event_t evt); + +// 配置参数 +#define DEBOUNCE_TICKS 3 // 连续3次读到新值才确认变化 +#define LONG_PRESS_TICKS 100 // 100*SCAN_INTERVAL_US >=1s 触发长按阈值 +#define DOUBLE_CLICK_WINDOW 30 // 30*SCAN_INTERVAL_US <=300ms 双击间隔窗口 +#define SCAN_INTERVAL_US 10000 // 10ms 扫描一次 + +// 按键处理结构体 +typedef struct { + bool (*read_pin)(void); // 读取 GPIO,按下返回 true + button_cb_t callback; // 事件回调 + + uint8_t stable_state; // 去抖后稳定状态 + uint8_t debounce_cnt; // 去抖计数 + uint16_t tick_cnt; // 持续按下或间隔计数 + uint8_t state; // 状态机状态 + uint8_t click_count; // 短按计数 +} button_t; + +extern bool key_single_click,key_press_down,key_press_up; +void _work_button(void *arg); +void button_work_init(); \ No newline at end of file