• 在Windows模拟器中使用LVGL8.3


    引言

    LVGL是一个跨平台、轻量级、易于移植的图形库。也因其支持大量特性和其易于裁剪,配置开关众多,且版本升级较快,不同版本之间存在一定的差异性,相关的使用教程有一定的滞后性,由于缺少最新版本的中文教程,加上大量的教程中未注明对应的版本,初始接触的开发者往往容易中招,花费大量时间爬坑,本文特对自己的使用经验进行记录和总结,以期对初始接触LVGL的开发者有所帮助。

     

    简介

    什么是Lvgl?LVGL(轻巧而多功能的图形库)是一个免费的开放源代码图形库,它提供创建具有易于使用的图形元素,精美的视觉效果和低内存占用的嵌入式GUI所需的一切。

    主要特性

    l  功能强大的构建块,例如按钮,图表,列表,滑块,图像等。

    l  带有动画,抗锯齿,不透明,平滑滚动的高级图形

    l  各种输入设备,例如触摸板,鼠标,键盘,编码器等

    l  支持UTF-8编码的多语言

    l  多显示器支持,如TFT,单色显示器

    l  完全可定制的图形元素

    l  独立于任何微控制器或显示器使用的硬件

    l  可扩展以使用很少的内存(64 kB闪存,16 kB RAM)进行操作

    l  操作系统,支持外部存储器和GPU,但不是必需的

    l  单帧缓冲区操作,即使具有高级图形效果

    l  用C语言编写,以实现最大的兼容性(与C ++兼容)

    l  模拟器可在没有嵌入式硬件的PC上进行嵌入式GUI设计

    l  可移植到MicroPython

    l  可快速上手的教程、示例、主题

    l  丰富的文档教程

    l  在MIT许可下免费和开源

     

    LVGL硬件要求

    • 16、32或64位微控制器或处理器
    • 最低 16 MHz 时钟频率
    • Flash/ROM::对于非常重要的组件要求 >64 kB(建议 > 180 kB)
    • RAM
      • 静态 RAM 使用量:~2 kB,取决于所使用的功能和对象类型
      • 堆栈: > 2kB(建议 > 8 kB)
      • 动态数据(堆):> 2 KB(如果使用多个对象,则建议 > 16 kB)。由 lv_conf.h 中的 LV_MEM_SIZE 宏进行设置。
      • 显示缓冲区:> “水平分辨率”像素(建议 > 10× “水平分辨率” )
      • MCU 或外部显示控制器中的一帧缓冲区
    • C99或更高版本的编译器
    • 具备基本的C(或C ++)知识:指针,结构,回调...

    请注意,内存使用情况可能会因具体的体系结构、编译器和构建选项而异。  

     

    官方网址

    LVGL - Light and Versatile Embedded Graphics Library

    源码地址    https://github.com/lvgl/lvgl

     

    部分中文资料网址

    LVGL教程|极客笔记 (deepinout.com)

    欢迎阅读百问网LVGL中文开发手册! — 百问网LVGL中文教程文档 文档 (100ask.net)

     

    环境搭建

    本文主要针对在windows10下,使用visual stdio开发环境编译运行模块器对LVGL8.3开发测试的一些配置使用进行介绍。

    VS2019或VS022均可,Visual Stdio和Git工具的安装使用,在此不做介绍。

    Visual Studio simulator模拟器为开源项目,源码地址如下:

    https://github.com/lvgl/lv_port_win_visual_studio

     

    模拟器源码项目下载

    模拟器项目源码内部包含了引用特定版本代码库模块,通过文件下载方式下载,会存在引用模块为空的问题。

    Github站点的英文说明文档中介绍了推荐的下载方式,采用git下载,但与我们通常下载单个源码库有所不同。

    此存储库包含其他必要的 LVGL 软件存储库作为 git 子模块。这些子模块不会使用正常的 git clone 命令拉入,它们将被需要。有几种技术可以拉入子模块。

    此命令将在单个步骤中克隆lv_sim_visual_studio存储库和所有子模块。

    git clone --recurse-submodules https://github.com/lvgl/

    lv_sim_visual_studio.git

     

    众所周知,国内的网络环境,访问github比较抽风,这种方式,通常会失败。

    因此,推荐使用下面的方式下载

    git clone https://github.com/lvgl/lv_sim_visual_studio.git

    cd lv_sim_visual_studio

    git submodule update --init –recursive

     

    先单独下载模拟器主项目,再切换到模拟器项目目录,使用模块拉取命令下载,这样,即使用失败了,可以通过反复尝试,可以将模块代码拉取回来。

     

    模拟器使用

    模块器项目代码成功拉取后,使用VS2019或VS2022成功打开即可运行。

     

    模拟器项目中,lvgl的配置文件中,大部分可用宏已默认开启,这个与MCU项目下配置模板中的有所不同,毕竟电脑上模拟器可以有充足的硬件资源可供分配。

    lv_conf.h 中的LV_MEM_SIZE宏应为 128KB 或更大,因为在使用 64 位模拟器时可能会遇到内存不足问题。 注意:在此项目中,大小设置为 1024KB。 用户需要检查在Visual Studio中选择的目标,因为模拟器项目支持ARM64,Visual Studio会因为字母顺序在第一时间选择ARM64。

     

    自带例程使用

    LVGL.Simulator.cpp文件中,main函数内,默认使用的lv_demo_widgets()演示例程,其后有各类其他演示例程,只需注释掉lv_demo_widgets()演示例程调用,分别启用其他例程即可。

     

    文件系统使用

    LVGL8.3版本的fsdrv目录中,已自带lv_fs_win32的文件系统调用接口,在模拟器中使用无需另外移植lv_fs_port文件,但需要在相关的配置文件中进行相关宏定义开启和相关配置。

    Lv_conf.h配置文件中,文件系统宏默认已开启

    #define LV_USE_FS_WIN32 '/'

    //#define LV_FS_WIN32_PATH "C:\\Users\\john\\"

    文件系统的访问路径配置为注释状态,可启用该宏定义并指向所需访问的磁盘文件目录,否则,文件系统默认访问项目的当前路径。

    修改配置如下

    #define LV_USE_FS_WIN32 '/'

    #define LV_FS_WIN32_PATH "D:\\SD"//此处可使用你自己的目录

    然后,开启main函数中的如下代码

    复制代码
        lv_fs_dir_t d;
        if (lv_fs_dir_open(&d, "/") == LV_FS_RES_OK)
        {
            char b[MAX_PATH];
            memset(b, 0, MAX_PATH);
            while (lv_fs_dir_read(&d, b) == LV_FS_RES_OK)
            {
                printf("%s\n", b);
            }
            lv_fs_dir_close(&d);
    } 
    复制代码

    运行程序,查看控制台窗口,是不是应该出现指定目录下的所有目录和文件呢?

    然而,并没有。

    这一步也是LVGL默认模拟器项目比较坑的地方,没有默认给出需要的配置项,这一处也折腾我跟踪代码,分析了好久,说起来都是泪啊。

     

    到底应该怎么办呢?

    运行并跟踪代码,在lv_init()中会调用lv_fs_win32_init(),在这个函数中,对文件驱动器进行了初始化

        static lv_fs_drv_t fs_drv; /*A driver descriptor*/
        lv_fs_drv_init(&fs_drv);
        /*Set up fields...*/
        fs_drv.letter = LV_FS_WIN32_LETTER;
        fs_drv.cache_size = LV_FS_WIN32_CACHE_SIZE;

     

    定位查看LV_FS_WIN32_LETTER宏,发现在lv_conf_internal.h中,

    如果外部未定义,会被定义为'\0',其后注释说明,需设置为设置驱动器可访问的大写字母。

    如此处不进行定义,当lv_fs_dir_open函数中调用lv_fs_get_drv(letter)方法时,其内部的判断 (*drv)->letter == letter会无法匹配而导致无法返回可用的驱动器对象。

    我们可以修改lv_conf_internal.h文件中(2035行)处的LV_FS_WIN32_LETTER宏定义,或者在lv_conf.h文件中,在宏 LV_USE_FS_WIN32 的下面,增加一行如下定义即可

    #define LV_FS_WIN32_LETTER '/'

    再次运行模拟器,bingo,指定目标下的目录和文件,在控制台中被打印输出出来了

     

    使用矢量字体

    模拟器项目中,默认已提供了矢量字体示例,打开注释开关启用,同时注释掉后面的演示Demo调用即可。

    复制代码
        // ----------------------------------
        // my freetype application
        // ----------------------------------
    
        ///*Init freetype library
    
        // *Cache max 64 faces and 1 size*/
        lv_freetype_init(64, 1, 0);
        ///*Create a font*/
        static lv_ft_info_t info;
        info.name = "./lvgl/src/extra/libs/freetype/arial.ttf";
        info.weight = 36;
        info.style = FT_FONT_STYLE_NORMAL;
        lv_ft_font_init(&info);
    
        /*Create style with the new font*/
        static lv_style_t style;
        lv_style_init(&style);
        lv_style_set_text_font(&style, info.font);
        /*Create a label with the new style*/
    
        lv_obj_t* label = lv_label_create(lv_scr_act());
        lv_obj_add_style(label, &style, 0);
        lv_label_set_text(label, "FreeType Arial Test");
    复制代码

    默认矢量字体例程是英文字体,我们要使用中文矢量字体怎么处理呢?

    在我们之前建立的文件系统目录中,放置对应的中文字体

       //info.name = "./lvgl/src/extra/libs/freetype/arial.ttf";
       info.name = "D:/SD/TTF/simhei.ttf";

    此处须使用完整路径或相对路径

    lv_label_set_text(label, "This is 思源黑体!");

    测试,中文显示成功。

     

    使用点阵字体

    矢量字体使用方便,但在资源紧张的MCU中使用,需要消耗一定的内存开销和存储开销,至少需要增加200KB左右的Flash和16KB左右的内存开销。

    为了节约内存资源 ,在无需多种字号的情况下,我们通常选择点阵字体。点阵字体可以通过专门的转换工具软件从矢量字库提取。

    我们使用里飞网阿里兄提供的免费转换软件实现点阵字体库的转换。

     

    字体转换工具和用法,大家在里飞网论坛自行查阅即可,如不需发贴,无需注册。

     

    生成点阵字库文件的同时,会生成一个C文件,将文件添加到项目,将修改以下方法,增加在Windows系统下的文字字阵数据获取方法实现。

     

    复制代码
    static uint8_t __g_font_buf[512];//如bin文件存在SPI FLASH可使用此buff
    
    static uint8_t* __user_font_getdata(int offset, int size) {
        //如字模保存在SPI FLASH, SPIFLASH_Read(__g_font_buf,offset,size);
        //如字模已加载到SDRAM,直接返回偏移地址即可如:return (uint8_t*)(sdram_fontddr+offset);
    
        lv_fs_file_t file;
        lv_fs_res_t result;
        static uint32_t icount = 0;
        result = lv_fs_open(&file, "/Font/Bin/SourceHanSans_16.bin", LV_FS_MODE_RD);
        printf("lv_fs_open res:%d,count:%d\r\n", result, ++icount);
        if (result != LV_FS_RES_OK)
            return NULL;
    
        lv_fs_seek(&file, offset, LV_FS_SEEK_CUR);
        uint32_t len;
        lv_fs_read(&file, __g_font_buf, size, &len);
        lv_fs_close(&file);
    
        return __g_font_buf;
    }
    复制代码

     

    注:此方法仅适用于windows系统中测试使用,如果MCU中使用,速度一定会十分感人^_^,因为lvgl获取点阵字体的每一个字节,都会调用一次这个函数。

    大家可对此方法进行优化,如增加读取缓存处理,减少文件访问。如有好的实现,也请告诉我呵。

    增加点阵字体测试代码:

    复制代码
    void lv_showFont(void)
    {
        LV_FONT_DECLARE(SourceHanSans_16);//引入字库
        lv_obj_t* zh_label = lv_label_create(lv_scr_act());//获取默认屏幕
        lv_obj_set_style_text_font(zh_label, &SourceHanSans_16, LV_STATE_DEFAULT);// 设置风格的字体
        lv_label_set_text(zh_label, "你好,这是思源黑体!");//显示文字
        lv_obj_align(zh_label, LV_ALIGN_TOP_MID, 0, 0);
    
        lv_obj_t* label = lv_label_create(lv_scr_act());//获取默认屏幕
        lv_obj_set_style_text_font(label, &SourceHanSans_16, LV_STATE_DEFAULT);// 设置风格的字体
        lv_label_set_text(label, "山不在高,有仙则名,水不在深,有龙则灵。");//显示文字
        lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
    
        //lv_obj_t* style_txt = lv_label_create(lv_scr_act());//获取默认屏幕
        //lv_obj_set_style_text_font(style_txt, &SourceHanSans_16, LV_STATE_DEFAULT);// 设置风格的字体
        //lv_label_set_text(style_txt, "\uF00C确定");//显示文字
        //lv_obj_align(style_txt, LV_ALIGN_BOTTOM_MID, 0, 0);
    }
    复制代码

     

    运行测试代码,效果如下。

     

      

    使用图片文件

    我们通常希望能够直接使用存储在文件系统中的图片,最好是图片无需预先经过专门的处理,这样的话,图片比较通用,也无需专门的软件工具处理。

    LVGL8.3已经准备好了常用的BMP、PNG、JPG格式图像解码器。

    考虑解码的性能和速度,我们直接使用BMP位图。

    为了降低内存开销和存储开销,我打算使用256色位图,这样的话,一张普通图片,使用windows自带的画图程序,可以直接转存为256色位图。

    添加加载图形对象代码,如下

    复制代码
    void lv_showBmp(void)
    {
        lv_obj_t* bmp = lv_img_create(lv_scr_act());
        if (bmp == NULL)
        {
            printf("[%s:%d] create bmp failed\n", __FUNCTION__, __LINE__);
            return;
        }
    
        char* bmp_path;
    #if LV_USE_FS_WIN32
        bmp_path = "/Images/Lena_320_256.bmp";
    #else
        bmp_path = "C:/Images/Lena_320_256.bmp";
    #endif
    
        lv_img_set_src(bmp, bmp_path); // 设置图片
        //lv_img_set_zoom(bmp, 128);
        lv_obj_align(bmp, LV_ALIGN_CENTER, 0, 0);
        lv_obj_set_size(bmp, 160, 160); // 设置大小
    }
    复制代码

     

    此处加载图片的路径应设置成相对路径,且需以’/’开头,文件系统处理函数中,会定位到配置的文件目录里面,否则,会出现找不到文件的情况。

     

     

     

     

     

    为了节省资源 ,使用256色位图,lv_conf.h中,颜色深度宏参数如下定义

    /*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/

    #define LV_COLOR_DEPTH 8

    实际测试,发现存在如上图中的颜色显示不正常问题。

    如将色深改为32,#define LV_COLOR_DEPTH 32

    使用24位真彩或32位真彩位图,则一切正常,除了lvgl需要的内存大幅飙升(相对于资源紧缺的MCU来说)。

    如果想使用16位色深的图片,windows自带的画图工具并不支持,需要专门的工具进行转换,并且需将色深宏参数定义为16。

    256色(8位)位图为什么不能正常显示,本人目前也还未找到原因,可能是lvgl的bug,也可能是我打开的姿势不对,如有解决此问题的朋友,请不吝告知,十分感谢。

  • 相关阅读:
    Linux —— linuxdeployqt源码编译与打包
    MySQL数据库查询排序
    【零基础入门MyBatis系列】第十五篇——分页插件与注解式开发
    Linux详解(基础、环境配置、项目部署入门)
    【Leetcode】208.实现Trie(前缀树)
    深入理解Linux内核进程的管理与调度(全知乎最详细)
    文件存储服务器调研
    金融领域思考-前言
    易拓SAP上新季 | SAP 分析云 2022年第四季度更新 TOP5 新功能速递
    VSCode将一份代码同步到多台服务器的解决方案
  • 原文地址:https://www.cnblogs.com/flyfire-cn/p/16930694.html