问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

基于ESP-IDF的ESP32-C3驱动TFT屏幕播放GIF图片方案

创作时间:
作者:
@小白创作中心

基于ESP-IDF的ESP32-C3驱动TFT屏幕播放GIF图片方案

引用
CSDN
1.
https://blog.csdn.net/qq_41126242/article/details/143907673

本文介绍了一种基于ESP-IDF框架的解决方案,展示了如何使用ESP32-C3驱动TFT屏幕播放GIF图片。该方案重点解决了内存限制问题,通过逐帧解码和部分屏幕更新实现了GIF的流畅播放。

方案实现思路

  1. 逐帧解码 GIF:使用流式读取方式逐帧解码 GIF 文件。
  2. 优化屏幕刷新:采用小区域更新,减少显示缓冲区的内存使用。
  3. SPIFFS 文件系统:将 GIF 文件存储在 SPIFFS 文件系统中。
  4. 内存优化:使用较小的解码缓冲区并分段更新显示。

完整代码

1. 设置项目配置

在 ESP-IDF 项目中,先配置 SPIFFS 文件系统和 TFT 屏幕:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "esp_system.h"
#include "esp_log.h"
#include "esp_spiffs.h"
#include "driver/spi_master.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "tftspi.h"
#include "tft.h"
#include "gifdec.h"
#define TAG "GIF_PLAYER"
// 屏幕分辨率
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 320
// SPIFFS 文件路径
#define GIF_FILE_PATH "/spiffs/sample.gif"

2. 初始化 SPIFFS 文件系统

SPIFFS 用于存储和读取 GIF 文件:

void init_spiffs() {
    esp_vfs_spiffs_conf_t conf = {
        .base_path = "/spiffs",
        .partition_label = NULL,
        .max_files = 5,
        .format_if_mount_failed = true
    };
    esp_err_t ret = esp_vfs_spiffs_register(&conf);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize SPIFFS");
        return;
    }
    size_t total = 0, used = 0;
    ret = esp_spiffs_info(NULL, &total, &used);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to get SPIFFS partition information");
    } else {
        ESP_LOGI(TAG, "SPIFFS total: %d, used: %d", total, used);
    }
}

3. 初始化 TFT 屏幕

使用 TFT_eSPI 或 TFT 自定义库初始化屏幕:

void init_tft() {
    tft_spi_init();
    TFT_init();
    TFT_fillScreen(TFT_BLACK);
    TFT_setRotation(LANDSCAPE);
    TFT_setFont(DEFAULT_FONT, NULL);
}

4. GIF 解码和显示逻辑

使用 gifdec 库解码 GIF 文件,每次仅加载一帧到内存:

static gd_GIF *gif;
void display_frame(gd_GIF *gif) {
    uint8_t *frame = heap_caps_malloc(gif->width * gif->height * 3, MALLOC_CAP_8BIT);
    if (!frame) {
        ESP_LOGE(TAG, "Failed to allocate memory for GIF frame");
        return;
    }
    if (gd_get_frame(gif, frame)) {
        for (int y = 0; y < gif->height; y++) {
            for (int x = 0; x < gif->width; x++) {
                int index = (y * gif->width + x) * 3;
                uint16_t color = TFT_Color565(frame[index], frame[index + 1], frame[index + 2]);
                TFT_drawPixel(gif->fx + x, gif->fy + y, color);
            }
        }
    }
    free(frame);
}

5. 播放 GIF 的任务

实现一个任务逐帧解码和显示 GIF:

void gif_player_task(void *pvParameter) {
    FILE *f = fopen(GIF_FILE_PATH, "r");
    if (!f) {
        ESP_LOGE(TAG, "Failed to open GIF file");
        vTaskDelete(NULL);
    }
    gif = gd_open_gif(f);
    if (!gif) {
        ESP_LOGE(TAG, "Failed to decode GIF");
        fclose(f);
        vTaskDelete(NULL);
    }
    while (1) {
        display_frame(gif);
        vTaskDelay(pdMS_TO_TICKS(gif->gce.delay * 10));  // 根据 GIF 帧延迟设置播放间隔
        if (!gd_next_frame(gif)) {
            gd_rewind(gif);  // 播放完毕重新开始
        }
    }
    gd_close_gif(gif);
    fclose(f);
    vTaskDelete(NULL);
}

6. 主程序入口

初始化系统并创建 GIF 播放任务:

void app_main(void) {
    ESP_LOGI(TAG, "Initializing SPIFFS...");
    init_spiffs();
    ESP_LOGI(TAG, "Initializing TFT...");
    init_tft();
    ESP_LOGI(TAG, "Starting GIF player...");
    xTaskCreate(gif_player_task, "gif_player_task", 8192, NULL, 5, NULL);
}

关键优化点

  1. 逐帧解码
  • 每次解码并显示一帧,释放上一帧的内存,避免一次性占用大量 RAM。
  1. 显示区域优化
  • 只更新变化的帧部分,减少显示缓冲区的大小。
  1. GIF 文件压缩
  • 尽量使用低分辨率、较少颜色的 GIF 文件。
  1. SPIFFS 文件系统
  • 确保 GIF 文件位于 SPIFFS 中,减少 I/O 操作开销。

测试与结果

运行此代码后,你的 ESP32-C3 应能流畅地在 TFT 屏幕上播放 GIF 动画,且不会占用过多内存。如果需要进一步优化或解决问题,可以分享更多详细场景和需求,我会协助调整代码!

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号