- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
引言 。
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 - 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,也可能是我打开的姿势不对,如有解决此问题的朋友,请不吝告知,十分感谢.
最后此篇关于在Windows模拟器中使用LVGL8.3的文章就讲到这里了,如果你想了解更多关于在Windows模拟器中使用LVGL8.3的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!