#include "driver/i2c.h" #include "driver/spi_master.h" #include "esp_err.h" #include "esp_log.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 "temp.h" #include "fatfs.h" #include "pages.h" #include "ble.h" #include "battery.h" #include "button.h" #include "sleep_mgr.h" #include "ui/ui.h" #include "ui/screens/ui_ScreenSet.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; // } // BOOT按键按下处理:唤醒屏幕 + 退出手电筒 + 返回ScreenHome void boot_btn_handler(int gpio_num, void *usr_data) { ESP_LOGI("BTN_HANDLER", "BOOT按键触发,返回ScreenHome"); // 检查当前是否在ScreenImg界面,如果是则先隐藏ContainerDle lv_obj_t *current_screen = lv_scr_act(); if (current_screen == ui_ScreenImg) { ui_ScreenImg_hide_delete_container(); ESP_LOGI("BTN_HANDLER", "从ScreenImg离开,已隐藏ContainerDle"); } // 检查屏幕是否关闭(低功耗模式) bool screen_was_off = sleep_mgr_is_screen_off(); if (screen_was_off) { // 屏幕关闭状态:先切换界面(背光仍为0,用户看不到),再恢复亮度 ESP_LOGI("BTN_HANDLER", "屏幕已关闭,先切换界面再唤醒"); // 退出手电筒 if (flashlight_is_active()) { flashlight_exit(); } // 切换到ScreenHome(此时背光为0,LCD已渲染但不可见) _ui_screen_change(&ui_ScreenHome, LV_SCR_LOAD_ANIM_NONE, 0, 0, &ui_ScreenHome_screen_init); // 等待 LVGL 完成界面切换和渲染(100ms足够LVGL完成2-3个tick) vTaskDelay(pdMS_TO_TICKS(100)); // 现在恢复亮度(此时ScreenHome已渲染完成,避免看到旧界面) sleep_mgr_notify_activity(); } else { // 屏幕正常显示状态:先通知活动,再切换界面 sleep_mgr_notify_activity(); if (flashlight_is_active()) { flashlight_exit(); } _ui_screen_change(&ui_ScreenHome, LV_SCR_LOAD_ANIM_NONE, 0, 0, &ui_ScreenHome_screen_init); } ESP_LOGI("BTN_HANDLER", "已切换到ScreenHome界面"); } // 初始化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已初始化 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按键回调:返回ScreenHome界面 extern void boot_btn_handler(int gpio_num, void *usr_data); button_on_boot_press(boot_btn_handler, NULL); ESP_LOGI("MAIN", "12.1 BOOT按键回调已注册"); // 初始化休眠管理器(依赖按键和UI,必须最后初始化) sleep_mgr_init(); ESP_LOGI("MAIN", "13. 休眠管理器已初始化"); 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();// 显示图片 // //===================================================================== }