一、GUI基础
GUI,全称为图形用户界面(Graphical User Interface),是一种允许用户通过图形元素与计算机软件进行交互的界面。与传统的命令行界面(CLI)不同,GUI使用图标、按钮、窗口和菜单等视觉元素,使用户能够更加直观和便捷地操作程序。
GUI库:图形用户界面库,只要调用GUI库的函数即可快速绘制出所需要的用户界面。
嵌入式中常用的GUI库:emWin、LVGL、TouchGFX、QT等。本节课我们主要讲解LVGL库的使用。
二、LVGL基础
LVGL是一个轻量、多功能的开源图形库,是当前最流行的免费开源嵌入式图形库之一,常用于嵌入式领域。官方网址:下载地址
1. LVGL移植要求(以版本8.2为例)
微控制器或处理器 | 16、32或64位 |
主控频率 | >16Mhz |
Flash/ROM | >64kb,建议在180kb以上 |
RAM | >8kb,建议在24kb以上 |
编译器 | C99或更新版本 |
图形缓冲区 | >水平分辨率像素,建议大于1/10屏幕总像素 |
2. 优化LVGL效果的方法
(1)提高芯片主频:更高的主频可以提高处理器的计算能力,从而加快图形渲染和界面的响应速度。
(2)增大 SRAM 容量、提高读写速度:增加 SRAM 的容量可以存储更多的图形数据和缓存,提高数据的读写速度,有助于更流畅地处理图形。
(3)增大图形缓冲区、使用双缓冲:双缓冲技术可以减少屏幕闪烁和撕裂现象,通过在一个缓冲区绘制图像的同时,在另一个缓冲区准备下一个帧,从而实现更平滑的视觉效果。
(4)减小需要刷新的总像素:通过优化界面布局,减少每次刷新所需处理的像素数量,可以提高刷新效率,降低 CPU 的负担。
(5)提高图像数据的传输速度:加快图像数据从存储到显示的传输速度,可以减少延迟,提高整体用户体验。
3. STM32工程添加LVGL
(1)通过LVGL官网进入Github仓库,选择对应的版本进行下载。
(2)查看了解源码目录。
了解源码结构,方便后续对不需要使用到的代码进行裁剪。文件功能解释:
(3)裁剪LVGL最小使用库。
在stm32工程下新建LVGL文件夹。将源码下列文件拷贝到新建文件夹中。注意:examples文件夹只需要拷贝该文件夹里的porting文件夹即可!拷贝移植完成,把lv_conf_template.h文件重命名为lv_conf.h。如下所示:
(4)向工程中添加C文件。
新建LVGL组,向组中添加src目录下的core、 draw 、font 、hal 、misc、 widgets中所有的C文件(多级目录下的C文件也全填加进来)。将extra目录下的下列文件的C文件(如图所示)也全部添加进LVGL组。具体为:
新建LVGL_PORT组,添加porting下的所有C文件。
(5)向工程中添加头文件路径。
(6)修改文件内容
修改工程文件夹里的LVGL/porting文件夹中C文化和H文件。将开头的#if 0改为#if 1。注意这里只修改显示相关和触摸屏相关的文件即可!文件系统我们用不到的话先不要修改。
修改完成后,还需要将修改的两个C文件和H文件中lvhl的头文件路径,以LVGL/porting/lv_port_disp_template.h文件为例修改如下:
修改LVGL/lv_conf.h文件开头中的#if 0改为#if 1,并添加以下代码。#define LV_COLOR_DEPTH 16 //颜色位深 #define MY_DISP_HOR_RES 160 //定义屏幕的最大水平分辨率 #define MY_DISP_VER_RES 128 //定义屏幕的最大垂直分辨率
修改LVGL/src/lv_conf_internal.h文件。
修改LVGL/porting/lv_port_disp_template.c中文件,总需要修改两处。(该文件用于显示)
(1)屏蔽后两种图形缓冲模式,如下图所示。缓冲模式分为3种。模式1:单缓冲。模式2:双缓冲。模式3:双屏幕缓冲。
(2)完善刷新函数,用于图形填充的,这里介绍两种方法,第一种是不断画点,只需要把红色部分写成你原来工程中的画点的函数就可以了,如果你的画点函数传入的形参中颜色的定义并不是指针的方式的话,一定要写成图中color_p->full的形式,不然会报错的。
画点函数参数为(x,y,color)。
(7)测试
前提条件:屏幕支持触摸、STM32工程代码中必须包含有定时器、屏幕驱动、画点函数。
▲在main.c添加头文件
#include "lvgl.h" #include "lv_port_disp_template.h" #include "lv_port_indev_template.h"
▲需要一个定时器里加一个跳动的“心脏”进行刷新。在定时器中断添加下面的函数。lv_tick_inc(1); (在中断里面进行刷新)
//定时器3中断服务程序 void TIM3_IRQHandler(void) //TIM3中断 {if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否{TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志 lv_tick_inc(1);//lvgl的1ms中断} }
▲编写测试函数
// 定义一个函数,用于创建和配置标签 void lv_ex_label(void) {// 定义一个指向字符串的指针,存储GitHub(或类似平台)的地址char* github_addr = "https://gitee.com/W23";// 在当前活动的屏幕上创建一个标签对象lv_obj_t * label = lv_label_create(lv_scr_act());// 允许标签文本中的颜色代码(例如#ff0000表示红色)被解析和应用lv_label_set_recolor(label, true);// 设置标签的长文本模式为循环滚动。当文本超出标签宽度时,文本会循环滚动显示lv_label_set_long_mode(label, LV_LABEL_LONG_SCROLL_CIRCULAR); /*Circular scroll*/// 设置标签的宽度为120像素lv_obj_set_width(label, 120);// 设置标签的文本,其中#ff0000表示红色文本,"Gitee: "是普通文本,%s会被后面的github_addr替换,#表示颜色代码结束// 结果是显示红色的"Gitee: https://gitee.com/W23"lv_label_set_text_fmt(label, "#ff0000 Gitee: %s#", github_addr);// 将标签对象在其父容器(这里是活动屏幕)中居中对齐,垂直偏移量为10像素(向下偏移)lv_obj_align(label, LV_ALIGN_CENTER, 0, 10);// 创建第二个标签对象lv_obj_t * label2 = lv_label_create(lv_scr_act());// 同样允许颜色代码lv_label_set_recolor(label2, true);// 设置长文本模式为循环滚动lv_label_set_long_mode(label2, LV_LABEL_LONG_SCROLL_CIRCULAR); /*Circular scroll*/// 设置第二个标签的宽度也为120像素lv_obj_set_width(label2, 120);// 设置第二个标签的文本,这里展示了如何在同一文本中使用多种颜色// "#ff0000 Hello#" 会显示红色的"Hello"," #0000ff world !123456789#"会显示蓝色的"world !123456789"// 注意:这里的"123456789"不会被当作颜色代码,因为它前面没有#号lv_label_set_text_fmt(label2, "#ff0000 Hello# #0000ff world !123456789#");// 将第二个标签对象在其父容器中居中对齐,垂直偏移量为-10像素(向上偏移),相对于第一个标签lv_obj_align(label2, LV_ALIGN_CENTER, 0, -10); }
#include "lvgl.h" #include "lv_port_disp_template.h" #include "lv_port_indev_template.h"// include ......int main() {LCD_init();//屏幕初始化IIME3_init(71,999);lv_init();lv_port_disp_init();lv_port_indev_init(); // lvgl输入接口初始化,放在lv_init()的后面lv_ex_label();while(1){lv_task_handler();HAL_Delay(10);} }