LVGL从SD卡读取图片并显示到MCU LCD屏详细笔记教程

1、前言

        在上一篇LVGL专题文章中已经讲解了如何将LVGL与FatFs链接起来,实现LVGL对SD卡中的数据进行读写操作。本文在上一文的基础上,将实现LVGL读取文件系统中的图片文件(BMP、PNG、JPG),并显示到MCU设备中的LCD屏中。

        LVGL配置FatFs文件系统,实现对STM32的SD卡数据读写-CSDN博客

        不得不吐槽一下,在MCU这类资源受限的设备上,需要刷一张图片,可谓是一波三折,属实头大。在试错,踩坑好几回后,总计归纳了这篇文章所呈现的笔记内容。如果本文讲解的方法有不合适的地方,欢迎在评论区或者私信交流探讨。

2、LVGL图片类型

(1)、解码器

        在LVGL中,支持如下4种格式的图片类型,分别是BMPPNGJPGGIF

        打开LVGL官网的文档,根据使用的LVGL选择了对应的文档版本后,点击3rd party libraries。可以看到官方对于使用这些第三方库资源内容的说明。

        BMP decoder — LVGL documentation

        除了使用本地图片解码器,LVGL官网也提供了在线图像转换器:Image Converter — LVGL

(2)、BMP

        BMP(Bitmap Image File)是一种图像文件格式,广泛应用于Windows操作系统中,用于存储数字图像。BMP图片是没有经过压缩的RGB图像数据。在使用的时候,不需要特定的解码器,直接读取文件的内容,简单处理后,就能进行显示。但因为其没有压缩,所以占用的内存空间较大。接下来所说的LVGL BMP解码器是指读取BMP文件处理像素的操作。

        而较多的MCU设备LCD显示屏仅支持16位RGB565格式的BMP图像显示。因此,对于目标设备LCD仅支持RGB565时,需要将24位BMP位图进行格式转换后,才能正常显示到LCD中。于是在这一篇文章中,将BMP的原理进行了深度的解析,同时也提供了位图格式转换的参考代码,要是有这个问题的困扰,可以参考一下。

        BMP位图原理深度解析及编程实现RGB565图片格式转换-CSDN博客

        在LVGL的BMP解码器中,像素是按需读取的(不是整个图像被加载),因此使用 BMP 图像需要很少的 RAM。

        在 lv_conf.h 中通过 LV_USE_BMP 可启用BMP解码器,并将 BMP 文件直接用作图像源。

(3)、PNG

        PNG(Portable Network Graphics)是一种广泛使用的图像文件格式,它采用无损压缩算法,旨在提供高质量的图像显示,同时保持文件大小相对较小。

        PNG图像解码时,其解码期间的RAM为: 图像宽度 x 图像高度 x 4字节

        在 lv_conf.h 中通过 LV_USE_PNG 可启用PNG解码器,并将 PNG 文件直接用作图像源。

(4)、JPG

        JPG文件,全称为JPEG(Joint Photographic Experts Group),是一种广泛使用的图像文件格式,它基于JPEG标准,该标准定义了一种有损压缩算法,用于减少图像文件的大小,同时尽可能保持图像质量。

        对于JPG图片的处理,LVGL提供的解码JPG库的实际上是SJPG,这是基于“普通”JPG 的自定义格式,专门用于LVGL。

        在LVGL中,解码普通 JPG 会消耗整个未压缩图像大小的 RAM,因此LVGL官方仅推荐用于具有更多 RAM 的设备。并且LVGL提供的JPG解码器,仅解码 JPG 和 SJPG 图像所需的部分,因此在使用过程中,无法对图片进行缩放或旋转。

        默认未修改的情况下,sjpg 图像占用的缓存空间为:图像宽度 * 2 * 16 字节

        在 lv_conf.h 中通过 LV_USE_SJPG 可启用JPG解码器,并将 JPG 文件直接用作图像源。

(5)、GIF

        GIF文件,全称Graphics Interchange Format,是一种无损压缩的图像文件格式,主要用于创建简单且颜色较少的图像,尤其是具有动画效果的图像。

        要解码和显示 GIF 动画,需要以下 RAM 量:

LV_COLOR_DEPTH 8: 3 x 图像宽度 x 图像高度

LV_COLOR_DEPTH 16:4 x 图像宽度 x 图像高度

LV_COLOR_DEPTH 32:5 x 图像宽度 x 图像高度

        在 lv_conf.h 中通过 LV_USE_GIF 中启用GIF解码器,并且可将GIF文件直接作为图像源。

3、LVGL显示图片

(1)、图片显示方案

        在LVGL中,将图片显示到LCD设备中,主要如下3种方法:

1、将图片转码成源代码,编译时,一起编译到程序代码中

2、将图片转码成二进制bin文件,将图片拷贝到SD卡中,程序运行时进行读取显示

3、将图片直接拷贝到SD卡中,通过LVGL的解码库解析显示图片

        在本文中,讲解的是,如何配置MCU工程及LVGL,实现利用LVGL的解码库,将各类图片解析出来,显示到LCD屏幕中。

        提醒:在显示BMP图片时,如果是直接将BMP原图片拷贝到SD卡中去显示时。需要对图片进行转码操作,否则BMP图片颜色深度位数不一致会无法显示

[Warn]    (0.484, +484)     decoder_open: LV_COLOR_DEPTH == 16 but bpp is 24 (should be 16)     (in lv_bmp.c line #160)
[Warn]    (0.495, +11)     _lv_img_cache_open: Image draw cannot open the image resource     (in lv_img_cache.c line #125)
[Warn]    (0.506, +11)     lv_draw_img: Image draw error     (in lv_draw_img.c line #84)
[Warn]    (0.515, +9)     decoder_open: LV_COLOR_DEPTH == 16 but bpp is 24 (should be 16)     (in lv_bmp.c line #160)
[Warn]    (0.525, +10)     _lv_img_cache_open: Image draw cannot open the image resource     (in lv_img_cache.c line #125)
[Warn]    (0.536, +11)     lv_draw_img: Image draw error     (in lv_draw_img.c line #84)

        BMP位图原理深度解析及编程实现RGB565图片格式转换-CSDN博客

(2)、MCU工程配置

①、修改内存大小

        根据自己所用开发的芯片,找到其启动文件,修改其堆、栈空间。如果堆栈空间不足,运行LVGL程序时,会出现各种莫名其妙的问题,因此,在能芯片容量范围内的情况下,能多大就多大。

        打开lv_conf.h文件,需要为LVGL分配多一些的内存空间,找到LV_MEM_SIZE这个宏,将其值设置的大一些。

        如下所示为在程序代码调试过程中,堆栈空间值过小,打开图片失败时,产生的错误提示,将启动文件的堆栈空间和LV_MEM_SIZE设置到合适值时,如下所示的错误消失,图片正常显示。

[Warn]    (0.693, +693)     _lv_img_cache_open: Image draw cannot open the image resource     (in lv_img_cache.c line #125)
[Warn]    (0.704, +11)     lv_draw_img: Image draw error     (in lv_draw_img.c line #84)
[Warn]    (0.715, +11)     _lv_img_cache_open: Image draw cannot open the image resource     (in lv_img_cache.c line #125)
[Warn]    (0.726, +11)     lv_draw_img: Image draw error     (in lv_draw_img.c line #84)
[Warn]    (0.737, +11)     _lv_img_cache_open: Image draw cannot open the image resource     (in lv_img_cache.c line #125)
[Warn]    (0.748, +11)     lv_draw_img: Image draw error     (in lv_draw_img.c line #84)

        如果MCU设备的内存空间告急严重,可以尝试使用微库,这也能节省一定的内存空间。如下所示是开启微库前后,编译出来的程序内存变化情况。

②、修改LVGL配置文件

        在LVGL中,如果需要读取SD卡中的原始图片文件,并显示到LCD中,需要开启宏定义配置。

        打开lv_conf.h文件,找到文件系统部分的配置,检查LV_USE_FS_FATFS是否开启,如果还未配置LVGL的文件系统,请查看本文开始部分的内容,进行文件系统的适配。

        找到如下图所示的LV_USE_PNG、LV_USE_BMP、LV_USE_SJPG、LV_USE_GIF,根据实际的使用需要,对这些宏定义开关进行配置。

(3)、参考程序源码

#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
#include "lv_conf.h"

#include "diskio.h"
#include "ff.h"
#include "ffconf.h"

void FatFs_Init(void)
{
    FATFS fs;                        
    FRESULT res_sd;
    
    while(SD_Init())
    {
        LED_RED_ON;
        delay_ms(500);
        LED_RED_OFF;
        delay_ms(500);
    }
    

    res_sd = f_mount(&fs,"0:", 1);
    if (res_sd!=FR_OK)
    {
        printf("SD Mount FatFs Failed! %d\r\n",res_sd);
        while (1);
    } else {
        printf("SD Mount FatFs Success!\r\n");
    }
}

void LVGL_Show_Images(void)
{
    FatFs_Init();//初始化文件系统,并且将SD卡挂载
    
    lv_init(); 
    lv_port_disp_init();
    lv_port_indev_init();
            
    lv_obj_t *label_1 = lv_label_create(lv_scr_act());
    lv_obj_t *label_2 = lv_label_create(lv_scr_act());
    lv_obj_t *label_3 = lv_label_create(lv_scr_act());
    const lv_font_t *font_txt;
    font_txt = &lv_font_montserrat_14;
    
    lv_obj_set_style_text_font(label_1, font_txt, LV_PART_MAIN);
    lv_obj_set_style_text_font(label_2, font_txt, LV_PART_MAIN);
    lv_obj_set_style_text_font(label_3, font_txt, LV_PART_MAIN);
    
    lv_label_set_text(label_1, "PNG");
    lv_label_set_text(label_2, "BMP");
    lv_label_set_text(label_3, "JPG");
        
    lv_obj_t *img1 = lv_img_create(lv_scr_act());
    lv_img_set_src(img1, "0:/images/1.png");//jpg 11.2K以内,png 11.2K以内
    lv_obj_center(img1);
    lv_obj_align_to(label_1 ,img1, LV_ALIGN_OUT_LEFT_MID, -10, 0);
        
    
    lv_obj_t *img2 = lv_img_create(lv_scr_act());
    lv_img_set_src(img2, "0:/images/2.bmp");
    lv_obj_align_to(img2, img1, LV_ALIGN_OUT_TOP_MID, 0, -40);
    lv_obj_align_to(label_2 ,img2, LV_ALIGN_OUT_LEFT_MID, -10, 0);
    
    lv_obj_t *img3 = lv_img_create(lv_scr_act());
    lv_img_set_src(img3, "0:/images/3.jpg");
    lv_obj_align_to(img3, img1, LV_ALIGN_OUT_BOTTOM_MID, 0, 40);
    lv_obj_align_to(label_3 ,img3, LV_ALIGN_OUT_LEFT_MID, -10, 0);
}

(4)、LCD显示效果

### LVGL框架中显示图片顿的原因 LVGL框架中的图片显示顿时,主要原因是内存管理不当以及资源分配不足。具体来说: - 图片在绘制之前才会被解码,这一过程涉及动态内存的频繁申请与释放(即“申请内存—读取图片—绘制图片—删除内存”)。这种策略可能导致大量内存碎片化,从而影响系统的稳定性引发顿现象[^1]。 - 此外,在某些情况下,如果未合理配置线程栈大小,则可能会发生栈溢出的情况,进而导致程序运行异常甚至崩溃[^2]。 ### 解决方案 为了有效缓解或彻底消除上述原因造成的顿问题,可以采取如下措施: #### 优化内存管理 通过调整图像缓存机制来减少不必要的内存操作次数。例如采用双缓冲技术或者直接映射显存的方式能够显著降低数据传输开销,且避免了传统方法中反复拷贝带来的额外负担[^3]。 另外还可以考虑增加可用堆空间容量以适应更大规模的数据处理需求;同时也要注意监控剩余可利用存储量以防万一出现极端状况下的资源耗尽风险。 #### 调整任务优先级与调度参数 对于多任务环境下的应用而言,适当调节各子模块之间的执行顺序及其占用CPU时间的比例有助于平衡整体性能表现 。比如提高图形渲染相关进程的重要性等级使其获得更多的计算机会 ,这样就可以加快画面更新速度从而改善用户体验感 。 #### 修改默认设置 针对特定硬件平台移植版本可能存在的一些局限性也可以通过对源代码做出相应改动来进行弥补 。像ESP32这样的微控制器系列就有专门适配好的驱动库可供选用 ,里面包含了经过验证的最佳实践做法可以帮助开发者快速构建稳定可靠的应用场景 [^4]. ```c // 示例:初始化显示接口函数定义部分可能需要根据实际情况定制修改 void disp_init(void){ // 初始化SPI总线或者其他通信协议链路... } ``` 以上就是关于如何解决LVGL框架下展示静态素材过程中遇到延迟障碍的一些建议总结。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值