LVGL移植

常见的 GUI 设计工具:

EMWIN ST-EMWIN MiniGUI TouchGFX QT for MCU - QT

LVGL emwin minigui

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

Lvgl 官网:https://lvgl.io/

Lvgl 官方文档:https://docs.lvgl.io/master/index.html

Lvgl 源码网址:https://github.com/lvgl/lvgl

主要特性

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

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

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

4、支持 UTF-8 编码的多语言

5、多显示器支持,如 TFT,单色显示器

6、完全可定制的图形元素

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

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

64kb

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

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

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

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

13、可移植到 MicroPython

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

15、丰富的文档教程

16、在 MIT 许可下免费和开源

硬件要求

基本上,每个现代控制器(肯定必须要能够驱动显示器)都适合运行 LVGL。LVGL 的最低运行要求很低:

16、32 或 64 位微控制器或处理器最低 16 MHz 时钟频率

Flash/ROM::对于非常重要的组件要求 >64 kB(建议 > 180 kB) 512kb

RAM

1、静态 RAM 使用量:~2 kB,取决于所使用的功能和对象类型

2、堆栈: > 2kB(建议 > 8 kB)

3、动态数据(堆):> 2 KB(如果使用多个对象,则建议 > 16 kB)。由 lv_conf.h 中

的 LV_MEM_SIZE 宏进行设置。

4、显示缓冲区:> “水平分辨率”像素(建议 > 10× “水平分辨率” )

5、MCU 或外部显示控制器中的一帧缓冲区

6、C99 或更高版本的编译器

7、具备基本的 C(或 C ++)知识:指针,结构,回调…

Lvgl 系统框架

应用程序创建 GUI 并处理特定任务的应用程序。

LVGL 本身是一个图形库。我们的应用程序通过调用 LVGL 库来创建 GUI 。它包含一个 HAL (硬件抽象层)接口,用于注册显示和输入设备驱动程序。

驱动程序除、读取触摸板或按钮的输入。特定的驱动程序外,它还有其他的功能,可驱动显示器到 GPU (可选)

根据 MCU ,有两种典型的硬件设置。一个带有内置 LCD/TFT 驱动器的外围设备,而另一种是没有内置 LCD/TFT 驱动器的外围设备。在这两种情况下,都需要一个帧缓冲区 来存储屏幕的当前图像。

集成了 TFT/LCD 驱动器的 MCU 如果 MCU 集成了 TFT/LCD 驱动器外围设备,则可以直接通过 RGB 接口连接显示器。在这种情况下,帧缓冲区可以位于内部 RAM(如果MCU 有足够的 RAM)中,也可以位于外部 RAM(如果 MCU 具有存储器接口)中。

如果 MCU 没有集成 TFT/LCD 驱动程序接口,则必须使用外部显示控制器(例如SSD1963、SSD1306、ILI9341 )。 在这种情况下,MCU 可以通过并行端口,SPI 或通过 I2C与显示控制器进行通信。帧缓冲区通常位于显示控制器中,从而为 MCU 节省了大量RAM 。

Lvgl 移植到 STM32

下载 LVGL 源码

我 们 使 用 的 是 Lvgl7.11 版 本 , 因 此 在 Github 上 找 到 对 应 版 本 源 码 下 载 :

https://github.com/lvgl/lvgl/tree/v7.11.0

其中 lvgl/src 文件夹内存放的是 LVGL 的核心源码,lvgl/examples/porting 文件夹内存放的是 lvgl 与底层的接口函数,这些函数需要我们根据自己的项目进行修改。

将必要文件复制到工程目录

在个人的工程目录下创建一个名为 Lvgl 的文件夹,并将 lvgl/src 目录复制到 Lvgl 目录下,将 lvgl/examples/porting 文件夹复制到 Lvgl 目录下,同时将 lvgl/lvgl.h 文件以及lvgl/lv_conf_template.h 文件复制到 Lvgl 目录下。如下图所示:

将 lv_conf_template.h 文件更名为 lv_conf.h,如下图所示:

将 lv_conf_template.h 文件更名为 lv_conf.h,如下图所示:

修改 port 目录下所需要的文件名字,我们只使用了屏幕的显示功能,因此我们只修改显示接口的文件名字,将 lv_port_disp_template.c/.h 更名为 lv_port_disp.c/.h 如下图所示:

在 Lvgl 目录下再创建一个 app 目录,用于存放我们后期自己写的应用层界面代码,具体操作如下图所示:

打开工程,在工程目录下新建三个分组,分别为 Lvgl/app、Lvgl/porting、Lvgl/src三个目录,具体操作如下图所示:

添加文件到工程目录中,porting 目录下只添加 lv_port_disp.c,以及 Lvgl 目录下的lv_conf.h 文件,这两个文件后面需要修改。

在 src 目录下,添加 Lvgl/src 目录下除去 gpu 文件夹外的所有文件夹内的 c 文件。

配置头文件路径,把 Lvgl 文件夹下所有包含 h 文件的路径,在工程属性中进行配置,具体操作如下图:

修改配置文件

打开 lv_port_disp.c/.h 文件,修改如下内容:

修改 lv_conf.h 文件如下图所示,修改后编译代码,这个时候代码就没有错误了。

接下来适配屏幕接口到 lvgl 上,先修改 lv_conf.h 内的宏定义,通过它可以设置库的基本行为,裁剪不需要模块和功能,在编译时调整内存缓冲区的大小等等,我们先修改一些必须修改的定义,后期的功能我们在具体项目中再做裁剪。

继续适配屏幕接口到 lvgl 上、修改 lv_port_disp.c 文件中的显示接口函数,用于适配我们的屏幕与 lvgl,包含 lcd 屏幕显示的头文件。

修改屏幕显示初始化函数 lv_port_disp_init,我们用方法一显示,同时修改屏幕的大小。

修改 disp_init 函数,该函数一般将我们的屏幕初始化放进去,也可以在硬件层初始化屏幕,这里就可以不写底层屏幕的初始化。

修改 disp_flush 函数,该函数是 lvgl 绘制界面的关键函数,是用于绘制界面的最基本的函数,也是 lvgl 与底层屏幕的绘制适配接口函数。

初始化 LVGL

使用 lvgl 图形库之前,我们还必须初始化 lvlg 以及相关其他组件。

调用 lv_init() 初始化 lvgl 库、初始化驱动程序、在 LVGL 中注册显示和输入设备驱动程序,在 main.c 中包含 lvgl.h、lv_port_disp.h,并在硬件初始化上添加 lv_init()函数以及 lv_port_disp_init()函数。

在中断中每隔 x 毫秒 调用 lv_tick_inc(x) 用以告知 lvgl 经过的时间;我们如果使用的是裸机开发,那么直接将这个函数放到硬件定时器的 1ms 中断服务函数内,如果我们使用的是操作系统,那么我们可以放到系统基础节拍的钩子函数内。

每隔 x 毫秒 定期调用 lv_task_handler() 用以处理与 lvgl 相关的任务。如果是裸机开发,那么我们可以在 while(1)中做一个时间点,1ms 或者 10ms 的调用一次这个函数,如果是使用的操作系统,那么我们可以创建一个任务来周期性的执行它。

TaskHandle_t xLvglTaskHandle = NULL; void vLvglTaskFunction( void * pvParameters )
{
TickType_t xLastWakeTime; const TickType_t xPeriod = pdMS_TO_TICKS( 5 ); xLastWakeTime = xTaskGetTickCount();
for(;;)
{
lv_task_handler(); vTaskDelayUntil( &xLastWakeTime, xPeriod );//绝对延时
}
}
TaskHandle_t xStartTaskHandle = NULL; void vTaskStartCode( void * pvParameters )
{
Bsp_Init();//硬件初始化
taskENTER_CRITICAL();//进入临界区
xTaskCreate(vLvglTaskFunction, "lvgl_task", 512, NULL, 2, &xLvglTaskHandle);
taskEXIT_CRITICAL(); configASSERT( ( ( uint32_t ) pvParameters ) == 1 );
for( ;; ) {
LedToggle(Led1Port, Led1Pin); vTaskDelay(500);
}
}

到此我们的移植算是完成,为了验证我们的 lvgl 是否能使用,我们可以去到官网或者找一个 lvgl 的小例程测试是否能正常显示。

//测试代码--显示一个 label(文本)
lv_obj_t * label1 = lv_label_create(lv_scr_act(), NULL);//在当前屏幕上创建一个文本对象
lv_label_set_long_mode(label1, LV_LABEL_LONG_BREAK);
lv_label_set_recolor(label1, true); //开启重找色功能
lv_label_set_align(label1, LV_LABEL_ALIGN_CENTER);//中央
lv_label_set_text(label1, "#0000ff Re-color# #ff00ff words# #ff0000 of a# label "
"and wrap long text automatically.");
lv_obj_set_width(label1, 150);
lv_obj_align(label1, NULL, LV_ALIGN_CENTER, 0, -30);
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐