Rdzleo 75586b3744 ESP32-S3按键版电子吧唧功能完整实现
1、按键驱动重构:从GPIO中断改为iot_button组件,支持BOOT/KEY2的单击/双击/长按6种事件;
2、新增按键导航管理器(key_nav):9种上下文状态机,统一分发按键事件到对应界面业务逻辑;
3、BLE模块改造:广播默认关闭由按键触发,新增设备间图片传输(GATT Client),支持扫描配对→MTU协商→分包发送;
4、新增6个UI界面:配对(Peiwang)、更新(Update)、发送等待(ImageShar)、接收等待(ImageReception)、发送中(Sharing)、接收中(Receiving);
5、新增电池指示器组件(battery_ui):支持多界面真实电量显示,3秒渐隐效果;
6、Home界面重构:移除手势事件,改为airhub背景图+电池指示器;
7、Img界面重构:移除触摸事件,新增删除二次确认边框机制;
8、禁用ScreenSet/ScreenChar界面(保留文件),禁用触摸初始化(保留代码可恢复);
9、sleep_mgr简化:移除ScreenSet亮度UI依赖,按键唤醒由key_nav统一处理;
10、新增9张图片资源(airhub背景、配对、传输状态、电池图标等);

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 17:35:05 +08:00

255 lines
9.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "driver/i2c.h"
#include "driver/spi_master.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_pm.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_flash.h"
#include "esp_check.h"
#include "nvs_flash.h"
#include "lv_demos.h"
#include "string.h"
#include "gpio.h"
#include "wifi.h"
#include "lcd.h"
#include "fatfs.h"
#include "pages.h"
#include "ble.h"
#include "battery.h"
#include "button.h"
#include "sleep_mgr.h"
#include "key_nav.h"
#include "ui/ui.h"
#include "ui/screens/ui_ScreenImg.h"
// #include "axis.h"
// #include "esp_bt.h"
// #include "esp_mac.h"
// #include "esp_gap_ble_api.h"
// #include "esp_gattc_api.h"
// #include "esp_gatt_defs.h"
// #include "esp_bt_main.h"
// #include "esp_log.h"
// #include "esp_system.h"
// #include "esp_bt_defs.h"
// #include "freertos/FreeRTOS.h"
// esp_err_t spi_init(void){
// spi_bus_config_t spi_conf = {
// .sclk_io_num = PIN_LCD_CLK,
// .data0_io_num = PIN_LCD_D0,
// .data1_io_num = PIN_LCD_D1,
// .data2_io_num = PIN_LCD_D2,
// .data3_io_num = PIN_LCD_D3,
// .max_transfer_sz = 4096,
// .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_QUAD,
// };
// esp_err_t err = spi_bus_initialize(SPI_LCD_HOST,&spi_conf, SPI_DMA_CH_AUTO);
// spi_device_interface_config_t devcfg = {
// .command_bits = 8,
// .address_bits = 24,
// .mode = 0,
// .clock_speed_hz = 10000000,
// .spics_io_num = PIN_LCD_CS,
// .queue_size = 1,
// .cs_ena_posttrans = 0,
// .flags = SPI_DEVICE_HALFDUPLEX,
// };
// err = spi_bus_add_device(SPI_LCD_HOST, &devcfg, &spi_lcd_handle);
// return err;
// }
// 初始化I2C
esp_err_t i2c_init(void){
i2c_config_t i2c_conf = {
.scl_io_num = PIN_NUM_SCL,
.sda_io_num = PIN_NUM_SDA,
.mode = I2C_MODE_MASTER,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
};
i2c_param_config(I2C_MASTER_NUM,&i2c_conf);
return i2c_driver_install(I2C_MASTER_NUM, i2c_conf.mode,0,0, 0);
}
// esp_err_t i2c_master_write_slave(uint8_t slave_addr, uint8_t *data_w, size_t size_w) {
// i2c_cmd_handle_t cmd = i2c_cmd_link_create();
// i2c_master_start(cmd);
// i2c_master_write_byte(cmd, (slave_addr << 1) | I2C_MASTER_WRITE, true);
// i2c_master_write(cmd, data_w, size_w, true);
// i2c_master_stop(cmd);
// esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 100);
// i2c_cmd_link_delete(cmd);
// return ret;
// }
// esp_err_t i2c_master_read_slave(uint8_t slave_addr,uint8_t order, uint8_t *data_r, size_t size_r) {
// i2c_cmd_handle_t cmd = i2c_cmd_link_create();
// i2c_master_start(cmd);
// i2c_master_write_byte(cmd, (slave_addr << 1) | I2C_MASTER_WRITE, true);
// i2c_master_write_byte(cmd,order,true);
// i2c_master_start(cmd);
// i2c_master_write_byte(cmd, (slave_addr << 1) | I2C_MASTER_READ, true);
// i2c_master_read(cmd, data_r, size_r, true);
// i2c_master_stop(cmd);
// esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 100);
// i2c_cmd_link_delete(cmd);
// return ret;
// }
// 初始化NVS
void nvs_init(){
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());// 擦除NVS分区
ret = nvs_flash_init();// 初始化NVS
}
ESP_ERROR_CHECK(ret);// 检查NVS初始化是否成功
// 添加默认图片路径设置
// ============================================================================
nvs_handle_t nvs_handle;
esp_err_t err = nvs_open("config", NVS_READWRITE, &nvs_handle);// 打开NVS配置文件
if (err == ESP_OK) {
size_t imgname_len;// 图片路径长度
err = nvs_get_str(nvs_handle, "img_filename", NULL, &imgname_len);// 获取当前图片路径长度
if (err != ESP_OK) {
// 设置默认图片路径(与放入 spiffs_image 的文件名一致)
const char* default_img = "default.jpg";// 默认图片文件名
err = nvs_set_str(nvs_handle, "img_filename", default_img);// 设置默认图片路径
if (err == ESP_OK) {
nvs_commit(nvs_handle);
ESP_LOGI("NVS", "Set default image: %s", default_img);// 设置默认图片路径
}
}
nvs_close(nvs_handle);// 关闭NVS配置文件
}
// ============================================================================
// nvs_handle_t nvs_handle;
// esp_err_t err;
// err = nvs_open("config", NVS_READWRITE, &nvs_handle);
// if (err != ESP_OK) printf("创建config失败\n");
// int32_t brightness = 80;
// const char* wifi_ssid = "MyWiFi";
// const char* img_filename = "face_1762059331906.jpg";
// err = nvs_set_i32(nvs_handle, "brightness", brightness);
// if (err != ESP_OK) goto close_handle;
// err = nvs_set_str(nvs_handle, "wifi_ssid", wifi_ssid);
// if (err != ESP_OK) goto close_handle;
// err = nvs_set_str(nvs_handle, "img_filename", img_filename);
// if (err != ESP_OK) goto close_handle;
// err = nvs_commit(nvs_handle);
// close_handle:
// nvs_close(nvs_handle);
}
void app_main(void)
{
i2c_init();
ESP_LOGI("MAIN", "1. I2C已初始化");// I2C已初始化
nvs_init();
ESP_LOGI("MAIN", "2. NVS已初始化");// NVS已初始化
// 配置 Power Management低功耗管理
esp_pm_config_t pm_config = {
.max_freq_mhz = 240, // 最大频率 240MHzGIF解码需要高算力
.min_freq_mhz = 40, // 最小频率 40MHz保证LVGL正常刷新
.light_sleep_enable = true // 启用自动 Light Sleep
};
esp_err_t pm_err = esp_pm_configure(&pm_config);
if (pm_err == ESP_OK) {
ESP_LOGI("MAIN", "2.1 Power Management已启用40-240MHz动态频率 + 自动Light Sleep");
} else {
ESP_LOGW("MAIN", "2.1 Power Management启用失败%s", esp_err_to_name(pm_err));
}
lcd_init();
ESP_LOGI("MAIN", "3. LCD已初始化");// LCD已初始化
// touch_init(); // 按键版不使用触摸,跳过初始化节省资源(恢复触摸时取消注释)
ESP_LOGI("MAIN", "4. 触摸已跳过(按键版)");
lvgl_lcd_init();
ESP_LOGI("MAIN", "5. LVGL已初始化");// LVGL已初始化
// LVGL任务创建后下一个tick即运行利用这段时间初始化文件系统
fatfs_init();
ESP_LOGI("MAIN", "6. FATFS文件系统已初始化");// FATFS已初始化
fatfs_remove_nullData("/spiflash");// 移除空数据
fatfs_list_all_filenames("/spiflash",false);// 列出所有文件名
ESP_LOGI("MAIN", "7. SPIFFS处理完成");// SPIFFS处理完成
// =====================================================================
// 显示SquareLine Studio生成的UI界面
ui_init(); // 初始化UI含JPEG解码
ESP_LOGI("MAIN", "8. SquareLine UI已初始化");// SquareLine UI已初始化
// 等待LVGL完成屏幕切换和首帧渲染彻底避免开机闪烁
// ui_init()会创建所有屏幕并加载ScreenHome包括
// 1. JPEG解码约210ms
// 2. 屏幕对象创建和切换
// 3. QSPI传输首帧到LCD约100ms
// 增加到150ms确保所有渲染完成后再点亮背光
vTaskDelay(pdMS_TO_TICKS(150));
// UI渲染完成后再点亮背光避免开机闪烁旧画面
pwm_init();
ESP_LOGI("MAIN", "9. PWM背光已初始化");// PWM背光已初始化
// 初始化电池ADC检测并启动监控任务
ESP_ERROR_CHECK(battery_init());
ESP_LOGI("MAIN", "10. 电池ADC已初始化");
battery_monitor_start();
ESP_LOGI("MAIN", "11. 电池监控任务已启动");
// 初始化按键驱动
ESP_ERROR_CHECK(button_init());
ESP_LOGI("MAIN", "12. 按键已初始化");
// 初始化按键导航注册BOOT/KEY2所有事件回调
key_nav_init();
ESP_LOGI("MAIN", "12.1 按键导航已初始化");
// 初始化BLE蓝牙仅初始化不开始广播由KEY2按键触发
ble_init();
ESP_LOGI("MAIN", "13. BLE蓝牙已初始化默认关闭广播");
// 初始化设备间蓝牙传图模块GATT Client
extern void ble_transfer_init(void);
ble_transfer_init();
ESP_LOGI("MAIN", "13.1 设备间传图模块已初始化");
// 初始化休眠管理器依赖按键和UI必须最后初始化
sleep_mgr_init();
ESP_LOGI("MAIN", "14. 休眠管理器已初始化");
ESP_LOGI("MAIN", "系统初始化完成!");// 系统初始化完成
// =====================================================================
// // 优先显示测试屏幕
// app_test_display();
// ESP_LOGI("MAIN", "Test screen displayed");
// //=====================================================================
// // // 启动图片循环显示任务
// xTaskCreate(img_loop_task, "img_loop_task", 8192, NULL, 5, NULL);
// ESP_LOGI("MAIN", "图片循环显示任务已启动");
// ESP_LOGI("MAIN", "任务将每3秒循环显示SPIFFS中的所有图片");
// //=====================================================================
// 注释掉静态图片显示,使用任务自动切换
// app_img_display();// 显示图片
// //=====================================================================
}