Rdzleo 5eddd2aa72 feat: 新增按键驱动、休眠管理和电池监控功能,修复内存损坏和开机闪烁问题
 新增功能
- 按键驱动模块:GPIO中断+软件去抖,支持BOOT和KEY2按键事件回调
- 休眠管理器:10秒无操作自动休眠,触摸/按键唤醒,UI集成开关
- 电池电量监控:GPIO3 ADC实时检测,ScreenSet界面圆弧显示

🐛 Bug修复
- 修复FreeRTOS任务栈溢出导致内存损坏(battery任务栈2048→4096)
- 修复图片文件名损坏问题(改用静态缓冲区替代动态分配)
- 修复触摸中断引脚配置错误(GPIO4→GPIO5,匹配V1.0硬件)
- 修复开机闪烁问题(调整背光初始化时序,UI渲染后再点亮)

🎨 界面优化
- ScreenSet恢复为标准Screen切换方式(移除浮动面板架构)
- 亮度调节支持0%(完全关闭)和10-100%范围
- ScreenHome界面电量显示独立(不关联实时电量)
- 手势导航优化:下拉显示设置,上滑返回主界面

 性能优化
- 启动时间优化:从650ms缩短至170ms
- 内存管理优化:图片列表使用静态数组(10×32字节)
- 任务栈配置调优:battery 4096, button 3072, sleep_mgr 3072

📝 其他改进
- CMakeLists.txt添加新模块编译配置
- 添加硬件版本兼容性注释(GPIO引脚说明)
- 完善函数注释和错误日志输出
- sdkconfig配置更新

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-11 10:28:25 +08:00

820 lines
30 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 "lvgl.h"
#include "fatfs.h"
#include "driver/ledc.h"
#include "gpio.h"
#include "wifi.h"
#include "temp.h"
#include "jpeg_decoder.h"
#include "../ui/screens/ui_ScreenImg.h"
#include <inttypes.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <strings.h>
#include <stdbool.h>
char img_path[40];
char *img_filename;
lv_obj_t *app_img;
lv_obj_t *act_mainscreen;
uint8_t *app_img_data = 0;
esp_jpeg_image_output_t outdata;
lv_img_dsc_t image;
#define MAX_IMAGE_FILES 10
#define MAX_FILENAME_LEN 32
static char spiffs_image_files[MAX_IMAGE_FILES][MAX_FILENAME_LEN];
static int spiffs_image_count = 0;
static int current_image_index = 0;
static bool image_list_initialized = false;
// 当前亮度值(用于休眠恢复)
static uint8_t current_brightness = 50;
// 获取当前亮度值
uint8_t pwm_get_brightness(void) {
return current_brightness;
}
// 设置屏幕亮度percent范围0-100
// 0=完全关闭背光10~100为正常亮度范围
// 显示10%~100%映射到实际亮度20%~100%,背光低电平有效需反转占空比
void pwm_set_brightness(uint8_t percent) {
if (percent == 0) {
// 完全关闭背光低电平有效占空比100%=全高=关闭)
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 8191);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
return;
}
if (percent < 10) percent = 10;
if (percent > 100) percent = 100;
current_brightness = percent;
uint32_t actual = 20 + (uint32_t)(percent - 10) * 80 / 90;
uint32_t duty = 8191 - (8191 * actual) / 100;
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
}
// 初始化PWM
void pwm_init(){
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.timer_num = LEDC_TIMER_0,
.duty_resolution = LEDC_TIMER_13_BIT,
.freq_hz = 5000,
.clk_cfg = LEDC_AUTO_CLK
};
ledc_timer_config(&ledc_timer);// 配置PWM定时器
ledc_channel_config_t ledc_channel = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = LEDC_CHANNEL_0,
.timer_sel = LEDC_TIMER_0,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = PIN_LCD_EN,
.duty = 0,
.hpoint = 0
};
ledc_channel_config(&ledc_channel);// 配置PWM通道
pwm_set_brightness(50);// 初始亮度50%
// ledc_timer_config_t motor_timer = {
// .speed_mode = LEDC_LOW_SPEED_MODE,
// .timer_num = LEDC_TIMER_1,
// .duty_resolution = LEDC_TIMER_13_BIT,
// .freq_hz = 5000,
// .clk_cfg = LEDC_AUTO_CLK
// };
// ledc_timer_config(&motor_timer);
// ledc_channel_config_t motor_channel = {
// .speed_mode = LEDC_LOW_SPEED_MODE,
// .channel = LEDC_CHANNEL_1,
// .timer_sel = LEDC_TIMER_0,
// .intr_type = LEDC_INTR_DISABLE,
// .gpio_num = PIN_MOTOR_EN,
// .duty = 4095,
// .hpoint = 0
// };
// ledc_channel_config(&motor_channel);
// ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0);
// ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1);
}
// 测试扫描WiFi列表
void wifi_scan_list_test(){
wifi_ap_record_t* wifi_list = NULL;// 定义WiFi列表指针
uint16_t num = 0;// 定义WiFi数量变量
esp_err_t err = wifi_scan_list(&num,&wifi_list);// 扫描WiFi列表
if(err == ESP_OK){
ESP_LOGI("WIFI","列表获取成功,数量:%d",num);// 打印WiFi数量
for (int i = 0; i < num; i++) {
ESP_LOGI("WIFI", "AP %d - SSID: %s, RSSI: %d", i + 1, wifi_list[i].ssid, wifi_list[i].rssi);// 打印每个WiFi的SSID和RSSI
}
}
}
// 测试连接WiFi
void wifi_connect_test(){
wifi_config_t wifi_config = {
.sta = {
.password = "12345678",
.ssid = "LDL的iPhone"
}
};
esp_wifi_set_config(ESP_IF_WIFI_STA,&wifi_config);// 设置WiFi配置
esp_err_t err = esp_wifi_connect();// 连接WiFi
if(err == ESP_OK){
ESP_LOGI("WIFI","WIFI连接成功");
}
}
// 测试断开WiFi连接
void wifi_disconnect_test(){
esp_err_t err = esp_wifi_disconnect();// 断开WiFi连接
if(err == ESP_OK){
ESP_LOGI("WIFI","已断开WiFi连接");
}
}
// 测试开始扫描WiFi
void wifi_scan_start_test(){
wifi_scan_start();// 开始扫描WiFi
}
// 测试获取可用堆内存
void free_heap_test(){
ESP_LOGI("HEAP","可用堆内存:%d",(int)heap_caps_get_total_size(MALLOC_CAP_SPIRAM));
}
lv_obj_t *act_wifiscreen;// 当前WiFi屏幕对象
lv_obj_t *act_testscreen;// 当前测试屏幕对象
lv_obj_t *act_mainscreen;// 当前主屏幕对象
void app_wifi_display(){
}
// 测试获取温度和湿度
void temp_test(){
float temp,humi;// 定义温度和湿度变量
get_temp(&temp);// 获取温度
get_humi(&humi);// 获取湿度
ESP_LOGI("TEMP","temp:%.2f humi:%.2f",temp,humi);// 打印温度和湿度
}
// 从NVS中读取图片路径
esp_err_t nvs_read_img(void) {
nvs_handle_t nvs_handle; // NVS 句柄
esp_err_t err; // NVS 错误码
err = nvs_open("config", NVS_READONLY, &nvs_handle);// 打开 NVS 句柄
if (err != ESP_OK) return err; // 如果打开失败,返回错误码
size_t imgname_len;
err = nvs_get_str(nvs_handle, "img_filename", NULL, &imgname_len);// 获取图片路径长度
if (err == ESP_OK) {
img_filename = malloc(imgname_len);// 分配内存
err = nvs_get_str(nvs_handle, "img_filename", img_filename, &imgname_len);// 获取图片路径
if (err != ESP_OK) {
nvs_close(nvs_handle);// 关闭 NVS 句柄
return err; // 如果获取失败,返回错误码
}
ESP_LOGI("NVS", "img_filename: %s", img_filename);// 打印图片路径
}
nvs_close(nvs_handle);// 关闭 NVS 句柄
return err;
}
// 测试改变NVS中的图片路径
esp_err_t nvs_change_img(char *imgname) {
nvs_handle_t nvs_handle;// NVS 句柄
esp_err_t err;
err = nvs_open("config", NVS_READWRITE, &nvs_handle);// 打开 NVS 句柄
if (err != ESP_OK) goto close_handle;
err = nvs_set_str(nvs_handle, "img_filename", imgname);// 设置图片路径
if (err != ESP_OK) goto close_handle;
err = nvs_commit(nvs_handle);// 提交更改
if (err != ESP_OK) goto close_handle;// 如果提交失败,关闭句柄并返回错误码
close_handle:
nvs_close(nvs_handle); // 关闭 NVS 句柄
return err;
}
// 仅更新现有图片,显示其他图片
// img_name: 图片文件名为NULL时从NVS读取
void app_img_change(const char *img_name){
// 释放之前的图片数据
if(app_img_data){
free(app_img_data);
app_img_data = NULL;
ESP_LOGI("IMG", "释放之前显示的图片数据缓存");
}
const char *current_img_name = img_name;
// 如果没有指定图片名从NVS读取
if(!current_img_name) {
esp_err_t ret_nvs = nvs_read_img();// 从NVS中读取图片路径
if(ret_nvs != ESP_OK){
ESP_LOGE("NVS","图片路径获取失败2");
return;
}
current_img_name = img_filename;
}
// 构建图片路径
snprintf(img_path, sizeof(img_path), "/spiflash/%s", current_img_name);// 格式化图片路径
ESP_LOGI("IMG", "准备显示图片: %s, 路径: %s", current_img_name, img_path);
// 检查文件是否存在
struct stat file_stat;
if(stat(img_path, &file_stat) != 0) {
ESP_LOGE("IMG", "文件不存在: %s", img_path);
return;
}
ESP_LOGI("IMG", "文件大小: %ld 字节", file_stat.st_size);
// 解码图片
esp_err_t ret = DecodeImg(img_path,&app_img_data,&outdata);// 解码图片
if(ret == ESP_OK){
ESP_LOGI("IMG", "图片解码成功,数据地址: %p, 宽度: %d, 高度: %d",
app_img_data, outdata.width, outdata.height);
// 检查解码后的数据
if(app_img_data == NULL) {
ESP_LOGE("IMG", "解码数据为空");
return;
}
// 配置图片数据
image.header.cf = LV_IMG_CF_TRUE_COLOR;
image.header.always_zero = 0;
image.header.reserved = 0;
image.header.w = outdata.width;
image.header.h = outdata.height;
image.data_size = outdata.output_len;
image.data = app_img_data;
// 获取屏幕对象
act_mainscreen = lv_scr_act();
if(act_mainscreen == NULL) {
ESP_LOGE("IMG", "获取屏幕对象失败");
return;
}
// 如果图片对象不存在,创建它
if(app_img == NULL) {
app_img = lv_img_create(act_mainscreen);
if(app_img == NULL) {
ESP_LOGE("IMG", "创建图片对象失败");
return;
}
lv_obj_center(app_img);
ESP_LOGI("IMG", "创建图片对象成功");
}
// 更新图片显示
lvgl_port_lock(0);// 锁定LVGL端口
lv_img_set_src(app_img, &image);// 设置图片源
lv_scr_load(act_mainscreen);// 加载主屏幕
lvgl_port_unlock();// 解锁LVGL端口
ESP_LOGI("IMG", "图片显示成功: %s", current_img_name);
} else {
ESP_LOGE("IMG", "图片解码失败,错误码: %d", ret);
}
}
// 完整的图片显示初始化
void app_img_display(){
ESP_LOGI("IMG", "开始显示图片");
esp_err_t ret_nvs = nvs_read_img();// 从NVS中读取图片路径
if(ret_nvs != ESP_OK){
ESP_LOGE("NVS","图片路径获取失败1");
return;
}
ESP_LOGI("IMG", "图片路径: %s", img_filename);
snprintf(img_path, sizeof(img_path), "/spiflash/%s",img_filename);// 格式化图片路径
ESP_LOGI("IMG", "完整路径: %s", img_path);
// 检查文件是否存在
struct stat file_stat;
if(stat(img_path, &file_stat) != 0){
ESP_LOGE("IMG", "文件不存在");
return;
}
ESP_LOGI("IMG", "文件大小: %ld 字节", file_stat.st_size);
esp_err_t ret = DecodeImg(img_path,&app_img_data,&outdata);// 解码图片
if(ret == ESP_OK){
ESP_LOGI("IMG", "图片解码成功,数据地址: %p", app_img_data);
// 检查解码后的数据
if(app_img_data == NULL){
ESP_LOGE("IMG", "解码数据为空");
return;
}
image.header.cf = LV_IMG_CF_TRUE_COLOR;
image.header.always_zero = 0;
image.header.reserved = 0;
image.header.w = outdata.width;
image.header.h = outdata.height;
image.data_size = outdata.output_len;
image.data = app_img_data;
ESP_LOGI("IMG", "LV_IMG_CF_RGB565 值: %d", LV_IMG_CF_RGB565);
ESP_LOGI("IMG", "设置图片数据: 宽度=%lu, 高度=%lu, 数据大小=%lu", (unsigned long)image.header.w, (unsigned long)image.header.h, (unsigned long)image.data_size);
act_mainscreen = lv_scr_act();// 获取当前主屏幕对象
if(act_mainscreen == NULL){
ESP_LOGE("IMG", "获取屏幕对象失败");
return;
}
ESP_LOGI("IMG", "获取屏幕对象成功");
app_img = lv_img_create(act_mainscreen);// 创建图片对象
if(app_img == NULL){
ESP_LOGE("IMG", "创建图片对象失败");
return;
}
ESP_LOGI("IMG", "创建图片对象成功");
lvgl_port_lock(0);// 锁定LVGL端口
ESP_LOGI("IMG", "设置图片源前");
lv_img_set_src(app_img, &image);// 设置图片源
ESP_LOGI("IMG", "设置图片源后");
lv_obj_center(app_img);// 居中显示图片
ESP_LOGI("IMG", "居中显示图片后");
lv_scr_load(act_mainscreen);// 加载主屏幕
ESP_LOGI("IMG", "加载主屏幕后");
lvgl_port_unlock();// 解锁LVGL端口
vTaskDelay(50);// 延时50ms
pwm_init();// 初始化PWM
ESP_LOGI("IMG", "图片显示完成");
} else {
ESP_LOGE("IMG", "图片解码失败,错误码: %d", ret);
}
}
// // 图片切换任务
// void img_switch_task(void *pvParameters) {
// char *image_files[] = {"default.jpg", "02.jpg"};
// int file_count = 2;
// int current_index = 0;
// while(1) {
// // 释放之前的图片数据
// if(app_img_data) {
// free(app_img_data);
// app_img_data = NULL;
// }
// // 获取当前要显示的图片文件名
// const char *current_image = image_files[current_index];
// ESP_LOGI("IMG_SWITCH", "切换到图片: %s", current_image);
// // 构建图片路径
// snprintf(img_path, sizeof(img_path), "/spiflash/%s", current_image);
// ESP_LOGI("IMG_SWITCH", "图片路径: %s", img_path);
// // 检查文件是否存在
// struct stat file_stat;
// if(stat(img_path, &file_stat) != 0) {
// ESP_LOGE("IMG_SWITCH", "文件不存在");
// vTaskDelay(pdMS_TO_TICKS(2000));
// continue;
// }
// ESP_LOGI("IMG_SWITCH", "文件大小: %ld 字节", file_stat.st_size);
// // 解码图片
// esp_err_t ret = DecodeImg(img_path, &app_img_data, &outdata);
// if(ret == ESP_OK) {
// ESP_LOGI("IMG_SWITCH", "图片解码成功,数据地址: %p", app_img_data);
// // 检查解码后的数据
// if(app_img_data == NULL) {
// ESP_LOGE("IMG_SWITCH", "解码数据为空");
// vTaskDelay(pdMS_TO_TICKS(2000));
// continue;
// }
// // 配置图片数据
// image.header.cf = LV_IMG_CF_TRUE_COLOR;
// image.header.always_zero = 0;
// image.header.reserved = 0;
// image.header.w = outdata.width;
// image.header.h = outdata.height;
// image.data_size = outdata.output_len;
// image.data = app_img_data;
// // 获取屏幕对象
// act_mainscreen = lv_scr_act();
// if(act_mainscreen == NULL) {
// ESP_LOGE("IMG_SWITCH", "获取屏幕对象失败");
// vTaskDelay(pdMS_TO_TICKS(2000));
// continue;
// }
// // 如果图片对象不存在,创建它
// if(app_img == NULL) {
// app_img = lv_img_create(act_mainscreen);
// if(app_img == NULL) {
// ESP_LOGE("IMG_SWITCH", "创建图片对象失败");
// vTaskDelay(pdMS_TO_TICKS(2000));
// continue;
// }
// lv_obj_center(app_img);
// }
// // 更新图片显示
// lvgl_port_lock(0);
// lv_img_set_src(app_img, &image);
// lv_scr_load(act_mainscreen);
// lvgl_port_unlock();
// ESP_LOGI("IMG_SWITCH", "图片显示成功");
// } else {
// ESP_LOGE("IMG_SWITCH", "图片解码失败,错误码: %d", ret);
// }
// // 切换到下一张图片
// current_index = (current_index + 1) % file_count;
// // 等待2秒
// vTaskDelay(pdMS_TO_TICKS(2000));
// }
// }
// 新的显示测试屏幕函数
void app_test_display(){
lvgl_port_lock(0);// 锁定LVGL端口
// 获取或创建屏幕对象
lv_obj_t *screen = lv_scr_act();
if(screen == NULL) {
screen = lv_obj_create(NULL);// 创建屏幕对象
if(screen == NULL) {
ESP_LOGE("TEST", "Failed to create screen object");// 创建屏幕对象失败
lvgl_port_unlock();// 解锁LVGL端口
return;
}
}
// 清空屏幕
lv_obj_clean(screen);
// 创建标签
lv_obj_t *label = lv_label_create(screen);
if(label) {
lv_label_set_text(label, "Test Screen\nLCD is working!");// 设置标签文本
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
// 创建基本样式
static lv_style_t style;// 基本样式
lv_style_init(&style);// 初始化基本样式
lv_style_set_text_font(&style, &lv_font_montserrat_14);// 设置字体
lv_style_set_text_color(&style, lv_color_hex(0xf9076a));// 设置文本颜色
lv_style_set_bg_color(&style, lv_color_hex(0x000000));// 设置背景颜色
lv_obj_add_style(label, &style, 0);// 添加样式到标签
}
lv_scr_load(screen);// 加载屏幕
lvgl_port_unlock();// 解锁LVGL端口
}
// 图片循环显示任务 - 显示spiffs中的所有图片
void img_loop_task(void *pvParameters) {
// 存储SPIFFS中的图片文件名
char *image_files[10]; // 最多支持10张图片
int file_count = 0;
int current_index = 0;
static bool backlight_initialized = false;
// 初始化背光(只执行一次)
if(!backlight_initialized) {
pwm_init();
backlight_initialized = true;// 初始化背光
ESP_LOGI("IMG_LOOP", "背光初始化完成");
}
while(1) {
// 重新扫描SPIFFS中的图片文件
ESP_LOGI("IMG_LOOP", "开始扫描SPIFFS中的图片文件");
// 打开SPIFFS目录
DIR *dir = opendir("/spiflash");
if(!dir) {
ESP_LOGE("IMG_LOOP", "无法打开SPIFFS目录");
vTaskDelay(pdMS_TO_TICKS(3000));
continue;
}
// 重置文件计数
file_count = 0;
// 遍历目录
struct dirent *entry;
while((entry = readdir(dir)) != NULL && file_count < 10) {
// 检查是否是图片文件(.jpg, .jpeg, .png等
const char *name = entry->d_name;
int len = strlen(name);
if(len > 4) {
const char *ext = name + len - 4;
if(strcasecmp(ext, ".jpg") == 0 || strcasecmp(ext, ".jpeg") == 0 ||
strcasecmp(ext, ".png") == 0 || strcasecmp(ext, ".bmp") == 0) {
// 存储图片文件名
image_files[file_count] = strdup(name);
ESP_LOGI("IMG_LOOP", "发现图片文件: %s", name);
file_count++;
}
}
}
closedir(dir);
// 检查是否找到图片
if(file_count == 0) {
ESP_LOGE("IMG_LOOP", "未找到图片文件");
vTaskDelay(pdMS_TO_TICKS(3000));
continue;
}
ESP_LOGI("IMG_LOOP", "共发现 %d 张图片,开始循环显示", file_count);
// 循环显示所有图片
for(current_index = 0; current_index < file_count; current_index++) {
const char *current_image = image_files[current_index];
ESP_LOGI("IMG_LOOP", "显示图片 %d/%d: %s", current_index + 1, file_count, current_image);
// 使用修改后的app_img_change函数显示图片
app_img_change(current_image);
// 等待3秒
vTaskDelay(pdMS_TO_TICKS(3000));
}
// 释放文件名内存
for(int i = 0; i < file_count; i++) {
free(image_files[i]);
}
// 再次扫描前短暂延时
vTaskDelay(pdMS_TO_TICKS(500));
}
}
// 图片切换任务 - 显示指定的两张图片
void img_switch_task(void *pvParameters) {
char *image_files[] = {"default.jpg", "02.jpg"};
int file_count = 2;
int current_index = 0;
while(1) {
// 使用修改后的app_img_change函数显示图片
const char *current_image = image_files[current_index];
ESP_LOGI("IMG_SWITCH", "切换到图片: %s", current_image);
app_img_change(current_image);
// 切换到下一张图片
current_index = (current_index + 1) % file_count;
// 等待2秒
vTaskDelay(pdMS_TO_TICKS(2000));
}
}
// 初始化SPIFFS图片列表
void init_spiffs_image_list(void) {
if(image_list_initialized) {
ESP_LOGI("IMG_LIST", "图片列表已初始化,跳过");
return;
}
ESP_LOGI("IMG_LIST", "开始扫描SPIFFS中的图片文件");
// 打开SPIFFS目录
DIR *dir = opendir("/spiflash");
if(!dir) {
ESP_LOGE("IMG_LIST", "无法打开SPIFFS目录");
return;
}
// 重置文件计数
spiffs_image_count = 0;
// 遍历目录
struct dirent *entry;
while((entry = readdir(dir)) != NULL && spiffs_image_count < MAX_IMAGE_FILES) {
// 检查是否是图片文件(.jpg, .jpeg, .png等
const char *name = entry->d_name;
int len = strlen(name);
if(len > 4 && len < MAX_FILENAME_LEN) {
const char *ext = name + len - 4;
if(strcasecmp(ext, ".jpg") == 0 || strcasecmp(ext, ".jpeg") == 0 ||
strcasecmp(ext, ".png") == 0 || strcasecmp(ext, ".bmp") == 0) {
// 存储图片文件名到静态缓冲区
strncpy(spiffs_image_files[spiffs_image_count], name, MAX_FILENAME_LEN - 1);
spiffs_image_files[spiffs_image_count][MAX_FILENAME_LEN - 1] = '\0';
ESP_LOGI("IMG_LIST", "发现图片文件: %s", name);
spiffs_image_count++;
}
}
}
closedir(dir);
// 检查是否找到图片
if(spiffs_image_count == 0) {
ESP_LOGE("IMG_LIST", "未找到图片文件");
return;
}
image_list_initialized = true;
ESP_LOGI("IMG_LIST", "图片列表初始化完成,共发现 %d 张图片", spiffs_image_count);
// 查找default.jpg并设置为当前索引
for(int i = 0; i < spiffs_image_count; i++) {
if(strcmp(spiffs_image_files[i], "default.jpg") == 0) {
current_image_index = i;
ESP_LOGI("IMG_LIST", "设置默认图片索引: %d", current_image_index);
break;
}
}
}
// 获取下一张图片
const char* get_next_image(void) {
if(!image_list_initialized || spiffs_image_count == 0) {
ESP_LOGE("IMG_LIST", "图片列表未初始化或为空");
return NULL;
}
current_image_index = (current_image_index + 1) % spiffs_image_count;
ESP_LOGI("IMG_LIST", "切换到下一张图片,索引: %d/%d", current_image_index + 1, spiffs_image_count);
return spiffs_image_files[current_image_index];
}
// 获取上一张图片
const char* get_prev_image(void) {
if(!image_list_initialized || spiffs_image_count == 0) {
ESP_LOGE("IMG_LIST", "图片列表未初始化或为空");
return NULL;
}
current_image_index = (current_image_index - 1 + spiffs_image_count) % spiffs_image_count;
ESP_LOGI("IMG_LIST", "切换到上一张图片,索引: %d/%d", current_image_index + 1, spiffs_image_count);
return spiffs_image_files[current_image_index];
}
// 重置图片列表
void free_spiffs_image_list(void) {
if(!image_list_initialized) {
return;
}
spiffs_image_count = 0;
current_image_index = 0;
image_list_initialized = false;
ESP_LOGI("IMG_LIST", "图片列表已重置");
}
// 更新ui_ImgBle控件的图片
void update_ui_ImgBle(const char *img_name) {
if(!img_name) {
ESP_LOGE("IMG_UI", "图片名为空");
return;
}
if(!ui_ImgBle) {
ESP_LOGE("IMG_UI", "ui_ImgBle控件不存在");
return;
}
static uint8_t *ui_img_data = NULL;
static lv_img_dsc_t ui_image;
// 释放之前的图片数据
if(ui_img_data) {
free(ui_img_data);
ui_img_data = NULL;
ESP_LOGI("IMG_UI", "释放之前的图片数据");
}
// 构建图片路径
snprintf(img_path, sizeof(img_path), "/spiflash/%s", img_name);
ESP_LOGI("IMG_UI", "准备显示图片: %s, 路径: %s", img_name, img_path);
// 检查文件是否存在
struct stat file_stat;
if(stat(img_path, &file_stat) != 0) {
ESP_LOGE("IMG_UI", "文件不存在: %s", img_path);
return;
}
ESP_LOGI("IMG_UI", "文件大小: %ld 字节", file_stat.st_size);
// 解码图片
esp_jpeg_image_output_t ui_outdata;
esp_err_t ret = DecodeImg(img_path, &ui_img_data, &ui_outdata);
if(ret == ESP_OK) {
ESP_LOGI("IMG_UI", "图片解码成功,宽度: %d, 高度: %d", ui_outdata.width, ui_outdata.height);
// 检查解码后的数据
if(ui_img_data == NULL) {
ESP_LOGE("IMG_UI", "解码数据为空");
return;
}
// 配置图片数据
ui_image.header.cf = LV_IMG_CF_TRUE_COLOR;
ui_image.header.always_zero = 0;
ui_image.header.reserved = 0;
ui_image.header.w = ui_outdata.width;
ui_image.header.h = ui_outdata.height;
ui_image.data_size = ui_outdata.output_len;
ui_image.data = ui_img_data;
// 更新ui_ImgBle控件的图片
lvgl_port_lock(0);
lv_img_set_src(ui_ImgBle, &ui_image);
lvgl_port_unlock();
ESP_LOGI("IMG_UI", "ui_ImgBle图片更新成功: %s", img_name);
} else {
ESP_LOGE("IMG_UI", "图片解码失败,错误码: %d", ret);
}
}
// // 原本显示测试屏幕 代码
// void app_test_display(){
// lvgl_port_lock(0);// 锁定LVGL端口
// act_testscreen = lv_scr_act();// 获取当前测试屏幕对象
// // 创建列表样式
// static lv_style_t list_style;
// lv_style_init(&list_style);
// lv_style_set_bg_color(&list_style, lv_color_hex(0x1E1E1E));
// lv_style_set_border_width(&list_style, 0);
// lv_style_set_radius(&list_style, 0);
// lv_style_set_text_align(&list_style, LV_TEXT_ALIGN_CENTER);
// // 创建列表项样式
// static lv_style_t list_item_style;
// lv_style_init(&list_item_style);
// lv_style_set_bg_color(&list_item_style, lv_color_hex(0x2E2E2E));
// lv_style_set_bg_opa(&list_item_style, LV_OPA_100);
// lv_style_set_text_color(&list_item_style, lv_color_hex(0xFFFFFF));
// lv_style_set_pad_all(&list_item_style, 10);
// lv_style_set_min_height(&list_item_style, 80); // 设置最小高度为60px
// // 创建选中项样式
// static lv_style_t list_item_selected_style;
// lv_style_init(&list_item_selected_style);
// lv_style_set_bg_color(&list_item_selected_style, lv_color_hex(0x4A90E2));
// lv_style_set_text_color(&list_item_selected_style, lv_color_hex(0xFFFFFF));
// lv_obj_t* list = lv_list_create(act_testscreen);
// lv_obj_add_style(list, &list_style, 0);
// lv_obj_set_size(list, lv_pct(100), lv_pct(100));
// lv_obj_t* list_item1 = lv_list_add_btn(list, LV_SYMBOL_FILE, "FLASH TEST");
// lv_obj_t* list_item2 = lv_list_add_btn(list, LV_SYMBOL_FILE, "WIFI SCAN START TEST");
// lv_obj_t* list_item3 = lv_list_add_btn(list, LV_SYMBOL_FILE, "WIFI SCAN LIST TEST");
// lv_obj_t* list_item5 = lv_list_add_btn(list, LV_SYMBOL_FILE, "WIFI CONNECT TEST");
// lv_obj_t* list_item6 = lv_list_add_btn(list, LV_SYMBOL_FILE, "WIFI DISCONNECT TEST");
// lv_obj_t* list_item4 = lv_list_add_btn(list, LV_SYMBOL_FILE, "FREE HEAP");
// lv_obj_t* list_item7 = lv_list_add_btn(list, LV_SYMBOL_FILE, "TEMP TEST");
// lv_obj_add_event_cb(list_item1, fs_test, LV_EVENT_CLICKED, NULL);
// lv_obj_add_event_cb(list_item2, wifi_scan_start_test, LV_EVENT_CLICKED, NULL);
// lv_obj_add_event_cb(list_item3, wifi_scan_list_test, LV_EVENT_CLICKED, NULL);
// lv_obj_add_event_cb(list_item4, free_heap_test, LV_EVENT_CLICKED, NULL);
// lv_obj_add_event_cb(list_item5, wifi_connect_test, LV_EVENT_CLICKED, NULL);
// lv_obj_add_event_cb(list_item6, wifi_disconnect_test, LV_EVENT_CLICKED, NULL);
// lv_obj_add_event_cb(list_item7, temp_test, LV_EVENT_CLICKED, NULL);
// lv_obj_t *parent = lv_obj_create(act_mainscreen);
// lv_obj_set_size(parent, 150, 150);
// lv_obj_center(parent); // 居中显示
// static lv_style_t style_bg_black;
// lv_style_init(&style_bg_black);
// lv_style_set_bg_color(&style_bg_black, lv_color_hex(0x000000));
// lv_obj_add_style(act_mainscreen, &style_bg_black, 0);
// static lv_style_t style_img;
// lv_style_init(&style_img);
// lv_style_set_radius(&style_img,75);
// lv_style_set_clip_corner(&style_img, true);
// lv_style_set_border_width(&style_img,75);
// lv_obj_add_style(parent,&style_img,0);
// // lv_obj_t *img = lv_img_create(act_mainscreen);
// // lv_img_set_src(img,"C:spiflash/face_1759919044875.jpg");
// lv_scr_load(act_testscreen);
// lvgl_port_unlock();
// vTaskDelay(50);
// pwm_init();
// }