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

news2024/9/20 22:48:11

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显示效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2079368.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

转行软件测试必需要知道的知识

1前言 随着现在互联网行业的迅猛发展,越来越多的人想涌入进来,因为大家都觉得IT行业工资高,做测试门槛又低,是的,入门门槛确实比较低,但是要做好的话,还是有点难的,毕竟术业有专攻嘛…

网约车资格证考试攻略(必备宝典)

考试分数详情及攻略如下: 一、理论部分:(电脑操作,鼠标勾选) 1、全国试题,满分50分,40分过关,每位学员要练习到45分才行; 2、地方试题,满分25分&#xff0c…

Vue3源码调试-第三篇

前言 上两篇已经调试完packages/runtime-dom/src/index.ts下的createApp函数的第一行了,接下来我们看下一行 injectNativeTagCheck 首先说下这个__DEV__估计也是定义在dev.js下,又或者是哪里的,这里控制台输出是true,那我估计是…

Nginx: 代理场景下Nginx接收用户请求包体的处理

Nginx 反向代理图 当用户发过来一个request body的时候,Nginx 是如何处理这样一个body这个body 它对应的就是我们客户请求的一些具体内容 1 )proxy_request_bufering 指令 接收包体的两种方式 接收完全部包体再发送一边接收包体一边发送 接收包体的两种…

前端项目部署到服务器上(nginx)

我这个之前已经部署过项目,所以要进行这个操作 docker imagedocker rm -f nginx //用于强制删除名为“nginx”的容器docker ps //用于列出当前正在运行的Docker容器docker volume -fdocker volume prune //用于删除所有未使用的Docker数据卷,‌释放存…

day11JS-面向对象和js中的设计模式

1. 面向对象 1.1 什么是面向对象 面向对象是一种编程思想,JS就是基于这个思想构建出来的一门编程语言,所以JS中存在对象、类、实例的概念。 对象:万物皆对象。 构造函数(类):把具有某一特征的内容可以划分…

穿梭虚实之间:3DGS与NeRF如何辅助机器人遥控操作?

导读: 本研究介绍了一种用于机器人遥控操作的新型辐射场可视化技术,研究者提出了一种在线训练辐射场的方法,能够实时从多个摄像头获取数据,支持多种辐射方法,包括NeRF和3DGS。该系统与现有的ROS遥控操作系统集成&#…

惠海H6501 DCDC降压恒压ic 60V72V80V100V转24V36V48V实地架构低功耗 仪表仪器供电 兼容XX9487

H6501是一款高压降压型开关稳压器,可输出高达1A的持续电流至负载。它集成了一个 高压高端MOSFET,提供2.5A的典型峰值电流限。其4.5V至48V的宽输入电压范围可适用于各种降压应用,是汽车、工业和照明应用的理想之选。采用滞环电压控制模式&…

行为识别实战第二天——Yolov5+SlowFast+deepsort: Action Detection(PytorchVideo)

Yolov5SlowFastdeepsort 一、简介 YoloV5SlowFastDeepSort 是一个结合了目标检测、动作识别和目标跟踪技术的视频处理框架。这一集成系统利用了各自领域中的先进技术,为视频监控、体育分析、人机交互等应用提供了一种强大的解决方案。 1. 组件说明: Y…

golang笔记——Go堆内存管理

前言 本文主要记录个人学习Golang堆内存管理,涉及到的相关内容,算是对个人所学知识点的梳理与总结。从非常宏观的角度看,Go的堆内存管理就是下图这个样子 学习内存管理,肯定首先需要了解内存管理的基本知识,我会按照 内…

C++笔记10•容器适配器:stackqueue priority_queue•

从C中看stack&queue&priority_queue 1.stack的介绍 官方stack实现: 本质是一个数组 1. stack 是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。 2. stack 是作为容器适…

【C/C++】typedef用法

typedef用法讲解&#xff0c;时隔半年&#xff0c;再看typedef。 &#x1f381;typedef可以简化结构体关键字 #include<iostream> using namespace std;struct Person {char name[64];int age; };void test01() {struct Person p { "张三",18 };//不用type…

【设计模式-代理】

定义 代理模式是一种结构型设计模式&#xff0c;它提供了对象的替代者或占位符&#xff0c;用来控制对这个对象的访问。通过代理模式&#xff0c;一个类可以代表另一个类来执行某些操作。这种模式常用于增强对象的功能或控制对对象的访问。 特点 控制访问&#xff1a;代理模…

day01 1.c++对c的扩充

#include <iostream>using namespace std;int main() {string s1;cout << "请输入一个字符串&#xff1a;";getline(cin,s1);int count10,count20,count30,count40;int len s1.length();for(int i0;i<len;i){if((s1[i]>a&&s1[i]<z) ||…

BeanPostProcessor和Ordered

1. 概述 BeanPostProcessor 和 Ordered 接口用于在Spring容器初始化Bean的过程中进行自定义处理&#xff0c;并控制处理顺序 2. BeanPostProcessor BeanPostProcessor 接口允许你在Spring容器初始化Bean的前后对Bean进行自定义处理。它有两个方法&#xff1a; postProcessB…

zabbix对接Grafana

1.grafana安装 Download Grafana | Grafana Labs sudo yum install -y https://dl.grafana.com/oss/release/grafana-11.1.4-1.x86_64.rpm 2.zabbix插件安装 Grafana 默认并没有 zabbix 数据源的支持&#xff0c;只有安装了zabbix插件&#xff0c;才可以在grafana中添加zabbi…

峟思固定测斜仪的工作原理与应用

固定测斜仪作为一种精密的测量仪器&#xff0c;在地质工程、土木工程、矿山安全等领域中发挥着至关重要的作用。它通过测量土体或岩体内部的水平位移&#xff0c;为工程安全监测提供了可靠的数据支持。本文将详细介绍固定测斜仪的工作原理、结构组成以及其在实际应用中的表现。…

一文读懂 DDD领域驱动设计

DDD&#xff08;Domain-Driven Design&#xff0c;领域驱动设计&#xff09;是一种软件开发方法&#xff0c;它强调软件系统设计应该以问题领域为中心&#xff0c;而不是技术实现为主导。DDD通过一系列手段如统一语言、业务抽象、领域划分和领域建模等来控制软件复杂度&#xf…

快手小店自动回复机器人脚本

快手小店自动回复机器人是一种利用人工智能AI技术&#xff0c;能够根据用户的会话咨询内容自动回复的工具。这种机器人可以帮助快手小店主快速、高效地回复客户消息&#xff0c;提升店铺的客户服务质量和销售效率。 甜羊浏览器是一款基于Chromium内核开发的国产浏览器&#xff…

OpenAI API: How to count tokens before API request

题意&#xff1a;“OpenAI API&#xff1a;如何在 API 请求之前计算令牌数量” 问题背景&#xff1a; I would like to count the tokens of my OpenAI API request in R before sending it (version gpt-3.5-turbo). Since the OpenAI API has rate limits, this seems impor…