#include "dzbj_button.h" #include "driver/gpio.h" #include "esp_log.h" #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" static const char *TAG = "DZBJ_BTN"; // 去抖间隔(微秒) #define DEBOUNCE_US 200000 // 按键事件队列 static QueueHandle_t btn_evt_queue = NULL; // 回调存储 typedef struct { btn_event_cb_t cb; void *usr_data; } btn_cb_t; static btn_cb_t boot_cb = {0}; static btn_cb_t key2_cb = {0}; // 去抖时间戳 static int64_t last_boot_us = 0; static int64_t last_key2_us = 0; // GPIO中断服务函数(ISR中不做耗时操作,仅发送事件到队列) static void IRAM_ATTR gpio_isr_handler(void *arg) { int gpio_num = (int)arg; xQueueSendFromISR(btn_evt_queue, &gpio_num, NULL); } // 按键事件处理任务 static void btn_task(void *pvParameters) { int gpio_num; while (1) { if (xQueueReceive(btn_evt_queue, &gpio_num, portMAX_DELAY)) { int64_t now = esp_timer_get_time(); // BOOT(GPIO0) 由 iot_button 处理,这里仅处理 KEY2 if (gpio_num == PIN_BTN_KEY2) { if (now - last_key2_us > DEBOUNCE_US) { last_key2_us = now; ESP_LOGI(TAG, "KEY2按键按下 (GPIO%d)", gpio_num); if (key2_cb.cb) { key2_cb.cb(gpio_num, key2_cb.usr_data); } } } } } } esp_err_t dzbj_button_init(void) { btn_evt_queue = xQueueCreate(10, sizeof(int)); // 仅配置 KEY2(GPIO4),BOOT(GPIO0) 由 iot_button 统一处理 gpio_config_t io_conf = { .pin_bit_mask = (1ULL << PIN_BTN_KEY2), .mode = GPIO_MODE_INPUT, .pull_up_en = GPIO_PULLUP_ENABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_NEGEDGE, }; gpio_config(&io_conf); // 安装GPIO中断服务(如果已安装则跳过) esp_err_t ret = gpio_install_isr_service(0); if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { ESP_LOGE(TAG, "GPIO ISR服务安装失败"); return ret; } gpio_isr_handler_add(PIN_BTN_KEY2, gpio_isr_handler, (void *)PIN_BTN_KEY2); // 按键处理任务 xTaskCreate(btn_task, "btn_task", 3072, NULL, 5, NULL); ESP_LOGI(TAG, "按键初始化完成 (KEY2=GPIO%d,BOOT由iot_button处理)", PIN_BTN_KEY2); return ESP_OK; } void dzbj_button_on_boot_press(btn_event_cb_t cb, void *usr_data) { boot_cb.cb = cb; boot_cb.usr_data = usr_data; } void dzbj_button_on_key2_press(btn_event_cb_t cb, void *usr_data) { key2_cb.cb = cb; key2_cb.usr_data = usr_data; } // === 吧唧模式 BOOT 单击处理(从 dzbj main.c boot_btn_handler 移植) === #include "lvgl.h" #include "sleep_mgr/include/sleep_mgr.h" // UI 函数前向声明 extern lv_obj_t *ui_ScreenHome; extern lv_obj_t *ui_ScreenImg; extern void ui_ScreenHome_screen_init(void); extern void ui_ScreenImg_hide_delete_container(void); extern void _ui_screen_change(lv_obj_t **target, lv_scr_load_anim_t fademode, int spd, int delay, void (*target_init)(void)); extern bool flashlight_is_active(void); extern uint8_t flashlight_get_saved_brightness(void); extern void flashlight_exit(void); extern void pwm_set_brightness(uint8_t percent); void dzbj_boot_click_handler(void) { bool screen_was_off = sleep_mgr_is_screen_off(); if (screen_was_off) { // 低功耗模式:只唤醒屏幕 ESP_LOGI(TAG, "吧唧模式 BOOT:低功耗模式,仅唤醒屏幕"); sleep_mgr_notify_activity(); } else { // 正常模式:退出手电筒 + 返回ScreenHome ESP_LOGI(TAG, "吧唧模式 BOOT:返回ScreenHome"); // 如果在ScreenImg界面,先隐藏删除容器 lv_obj_t *current_screen = lv_scr_act(); if (current_screen == ui_ScreenImg) { ui_ScreenImg_hide_delete_container(); } sleep_mgr_notify_activity(); // 退出手电筒 bool was_flashlight = flashlight_is_active(); uint8_t saved_brightness = 0; if (was_flashlight) { saved_brightness = flashlight_get_saved_brightness(); flashlight_exit(); vTaskDelay(pdMS_TO_TICKS(80)); } // 切换到Home界面 _ui_screen_change(&ui_ScreenHome, LV_SCR_LOAD_ANIM_NONE, 0, 0, &ui_ScreenHome_screen_init); // 手电筒退出后恢复亮度 if (was_flashlight) { vTaskDelay(pdMS_TO_TICKS(150)); pwm_set_brightness(saved_brightness); ESP_LOGI(TAG, "亮度已恢复到%d%%", saved_brightness); } } }