lvgl的区别 qt_lvgl最新版本在STM32上的移植使用-嵌入式系统-与非网

前言

有读者在后台回复了LVGL,应该是想获取本公众号关于LVGL的内容。之前推送关于LVGL的内容较少,现在补上一篇。

另:本公众号由于开通得比较晚,所以不具备留言功能。所以大家想看哪些内容,可以在公众号聊天界面留言,小编会参考大家的意见输出、整理一些相关的内容。一起成长、一起进步。期待留言~

下面我们一起来看一看LVGL在STM32上的移植使用。

lvgl简介

LittlevGL是一个免费的开源图形库,提供了创建嵌入式GUI所需的一切,具有易于使用的图形元素、漂亮的视觉效果和低内存占用。

b74c063a797165e3eb116da77b6fdcda.png

特点:

强大的构建模组 按钮、图表、列表、滑块、图像等先进的图形 动画、反锯齿、半透明、平滑滚动多样的输入设备 触摸板、鼠标、键盘、编码器等多显示器支持 支持同时使用多个TFT或单色显示器多语言支持 UTF-8格式文字编码完全自定义 图形元素硬件无关 可用于任意微控制器或显示器可裁剪 用于小内存(80 KB FLASH,12 KB RAM)操作操作系统、外部存储以及GPU 支持但非必须单帧缓存 即可实现先进的图形效果C语言编写 以最大化兼容(C++ 兼容)模拟器 无需嵌入式硬件就可以在电脑上开始GUI设计教程、示例、主题 从而快速GUI设计文档 在线及离线免费开源 基于MIT协议

运行的硬件要求:

ec07a1bcae5c367cb25b6c21bb062443.png

lvgl资料

LVGL的资料很丰富,下面列出一些常用的资料链接:

1、lvgl英文官网:

https://lvgl.io/

2、lvgl中文网:

https://littlevgl.cn/    (还在建设中)

3、lvgl源码:

https://github.com/lvgl/lvgl

4、lvgl基于Visual sudio 的PC模拟器:

https://github.com/lvgl/lv_sim_visual_studio

5、正点原子lvgl教程资料:

http://www.openedv.com/docs/book-videos/zdyzshipin/4free/littleVGL.html

6、基于荔枝派Nano开发板的lvgl教程:

http://nano.lichee.pro/application/littlevgl.html

7、基于野牛开发板的 lvgl 6.0 例程:

https://gitee.com/mzy2364/LittlevGL_Demo

8、lvgl在线体验例程(可在浏览器体验):

https://lvgl.io/demos

9、lvgl官网教程:

https://docs.lvgl.io/latest/en/html/index.html

10、lvgl官方DEMO:

https://github.com/lvgl/lv_examples

lvgl移植到STM32

1、下载源码

源码链接中下载一份源码,lvgl已经更新迭代了很多个版本,这里我们选择目前最新的7.10.1版本来移植:

b22d4f12ad358cd9463cd9621d6b467d.png

注意:不同版本之间可能有很大的不同,所以看本篇教程移植的的小伙伴尽量使用与本文相同的版本。

下载得到:

41a08e767fcb9373ba0a6ec6857e1ba6.png

2、准备stm32工程

下面我基于普中的stm32f103开发板来移植,首先准备一个lcd显示的例程,并更名为lvgl_test:

7c3563199120a9bfe256bcbe3c2a397d.png

3、新建GUI文件夹

在工程目录下新建一个GUI文件夹,GUI文件夹下新建两个子文件夹:

195684db39c64ec23bf7ad238b56b437.png

把刚才下载的lvgl-7.10.1里的所有内容复制到lvgl文件夹中,lvgl_app文件夹暂时留空。

4、移植文件更名

下面,我们把GUI\lvgl\examples\porting下的文件进行一个更名操作(其实不更名也可以,为了文件名看起来规范一些我们进行一个更名):

6567e8d0f675a88110bf884fc90eb8ef.png

这是移植相关的几个文件,其中:

lv_port_disp:显示相关。

lv_port_indev:输入相关。

lv_port_fs:文件系统相关。

5、配置文件更名

把GUI\lvgl\下的lv_conf_template.h文件复制到GUI文件夹下并更名为lv_conf.h:

a0b45fbb8dd5b73beeb9d6ce7381c436.png

6、keil工程配置

(1)导入文件

打开keil工程,在工程下新建三个组,并导入文件:

0a2c9a2754c1dd72aa55eb918dd7c189.png

导入完成后得到:

b390c83c01f2d699b8c98b9191942a83.png

这里的lvgl_porting中我们暂时只导入lv_port_disp.c文件,这是显示相关的移植文件。本篇笔记先把显示打通,其它两个文件后续有机会再弄。

(2)包含头文件路径

下面包含头文件路径:

2e97ff284edf0e41b166520e0ca0681f.png

(3)修改堆栈大小

因为官方说明文档中推荐我们堆、栈大小设置为8k:

4410b33217a23aae1e37fac45a0bde5d.png

所以这里我们就按推荐进行设置:

64f467703f6d45adbf812996e4a46bc9.png

(4)设置C99模式

lvgl需要编译器支持C99或更新的标准:

cb85859c191fc3b2064958db70ad3942.png

C99模式可进行如下设置:

6a0a289fc9108bd51772e074846f8606.png

(5)使能lv_conf.h的条件编译

进行上面的设置后我们首先进行编译,会报很多个错误:

9ce606fd3413461b90229d6a97f15d8f.png

这是因为需要lv_conf.h里的一些东西,打开lv_conf.h里的条件编译即可:

6b9756578da6c6496fe28b2e70ed895f.png

再次编译,编译通过:

979692d8cd1b3b679a2f4aa03a474d98.png

(6)lvgl配置

我们可以对lvgl进行一些定制配置,这些配置内容在lv_conf.h文件中,下面进行一些关键配置:

显示器宽度:#define LV_HOR_RES_MAX (240)显示器高度:#define LV_VER_RES_MAX (480)色彩深度: #define LV_COLOR_DEPTH 16DPI: #define LV_DPI  100提供给lvgl的空间: #define LV_MEM_SIZE  (32U * 1024U)

其中调整LV_DPI  可以调整各控件间的紧凑,可根据实际情况进行更改;LV_MEM_SIZE  为lvgl可用空间,资源允许的情况下可以稍微设大些,这个设置过小的话,在跑一些稍微复杂的demo时界面就会刷不出来。

这里只是列出了几个常用的配置,lv_conf.h还有很多的配置,可根据实际情况进行配置。

(7)填充、修改lv_port_disp.c

dc0e1728352666ddcb4e33d963a26669.png

c8f81acb8a042df80fdfbe2e4b100bc4.png

lv_port_disp.c里面的内容主要有:

3abc16446c056736bb8fc186aba498a2.png

我们需要重点关注lv_port_disp_init显示接口初始化函数与disp_flush屏幕刷新两个函数。

其中,lv_port_disp_init函数里主要要选择一种写缓存的方式及设置显示分辨。我们选择第一种写缓存的方式,修改后的函数如:

void lv_port_disp_init(void)

{

/*-------------------------

* Initialize your display

* -----------------------*/

disp_init();

/*-----------------------------

* Create a buffer for drawing

*----------------------------*/

/* LVGL requires a buffer where it internally draws the widgets.

* Later this buffer will passed your display drivers `flush_cb` to copy its content to your display.

* The buffer has to be greater than 1 display row

*

* There are three buffering configurations:

* 1. Create ONE buffer with some rows:

*      LVGL will draw the display's content here and writes it to your display

*

* 2. Create TWO buffer with some rows:

*      LVGL will draw the display's content to a buffer and writes it your display.

*      You should use DMA to write the buffer's content to the display.

*      It will enable LVGL to draw the next part of the screen to the other buffer while

*      the data is being sent form the first buffer. It makes rendering and flushing parallel.

*

* 3. Create TWO screen-sized buffer:

*      Similar to 2) but the buffer have to be screen sized. When LVGL is ready it will give the

*      whole frame to display. This way you only need to change the frame buffer's address instead of

*      copying the pixels.

* */

/* Example for 1) */

static lv_disp_buf_t draw_buf_dsc_1;

static lv_color_t draw_buf_1[LV_HOR_RES_MAX * 10];                          /*A buffer for 10 rows*/

lv_disp_buf_init(&draw_buf_dsc_1, draw_buf_1, NULL, LV_HOR_RES_MAX * 10);   /*Initialize the display buffer*/

// /* Example for 2) */

// static lv_disp_buf_t draw_buf_dsc_2;

// static lv_color_t draw_buf_2_1[LV_HOR_RES_MAX * 10];                        /*A buffer for 10 rows*/

// static lv_color_t draw_buf_2_1[LV_HOR_RES_MAX * 10];                        /*An other buffer for 10 rows*/

// lv_disp_buf_init(&draw_buf_dsc_2, draw_buf_2_1, draw_buf_2_1, LV_HOR_RES_MAX * 10);   /*Initialize the display buffer*/

// /* Example for 3) */

// static lv_disp_buf_t draw_buf_dsc_3;

// static lv_color_t draw_buf_3_1[LV_HOR_RES_MAX * LV_VER_RES_MAX];            /*A screen sized buffer*/

// static lv_color_t draw_buf_3_1[LV_HOR_RES_MAX * LV_VER_RES_MAX];            /*An other screen sized buffer*/

// lv_disp_buf_init(&draw_buf_dsc_3, draw_buf_3_1, draw_buf_3_2, LV_HOR_RES_MAX * LV_VER_RES_MAX);   /*Initialize the display buffer*/

/*-----------------------------------

* Register the display in LVGL

*----------------------------------*/

lv_disp_drv_t disp_drv;                         /*Descriptor of a display driver*/

lv_disp_drv_init(&disp_drv);                    /*Basic initialization*/

/*Set up the functions to access to your display*/

/*Set the resolution of the display*/

disp_drv.hor_res = 240;

disp_drv.ver_res = 400;

/*Used to copy the buffer's content to the display*/

disp_drv.flush_cb = disp_flush;

/*Set a display buffer*/

disp_drv.buffer = &draw_buf_dsc_1;

#if LV_USE_GPU

/*Optionally add functions to access the GPU. (Only in buffered mode, LV_VDB_SIZE != 0)*/

/*Blend two color array using opacity*/

disp_drv.gpu_blend_cb = gpu_blend;

/*Fill a memory array with a color*/

disp_drv.gpu_fill_cb = gpu_fill;

#endif

/*Finally register the driver*/

lv_disp_drv_register(&disp_drv);

}

disp_flush需要调用底层lcd操作接口,这里修改为:

60451ab7e92a13e4ea2c338f13107704.png

这里我们调用一个写像素点的函数,也可以直接调用一个显示的填充方形函数。

最后,需要再头文件中声明lv_port_disp_init函数:

68ac86e057dfa452cbc164e28832333b.png

(8)配置一个定时器为lvgl提供心跳

lvgl需要一个心跳节拍,可以使用系统滴答定时器,也可以使用其它定时器。我们这里的配置如下:

TIM4_Init(999, 71);     // 1ms进入一次中断,为lvgl提供心跳

void TIM4_IRQHandler(void)

{

if(TIM_GetITStatus(TIM4,TIM_IT_Update))

{

lv_tick_inc(1);

}

TIM_ClearITPendingBit(TIM4,TIM_IT_Update);

}

(9)测试官方demo

下面开始进行测试,至此我们的GUI\lvgl_app文件夹里还没有任何内容,我们下载官方提供的demo来进行测试,同样地,下载官方demo:

ddd6f334439badc8edf43e1c30233b6b.png

官方给我们提供了很多demo:

2e2ecde299df7cf255cad9cd3166574e.png

复制lv_examples-7.10.1整个文件夹至GUI\lvgl_app文件夹下并更名为lv_examples:

d5facc7bc9e133895f2e5fbdb969f8dd.png

把GUI\lvgl_app\lv_examples下的lv_ex_conf_template.h复制到GUI文件夹下并更名为lv_ex_conf.h,这是demo的配置文件:

298c5ab90f0bdd08dd0fdbf827beb164.png

0bafb3cef48b2df94b1b0ad1c5411970.png

想跑哪个demo就配置相关宏。

下面我们跑一个lv_demo_widgets的demo进行演示:

b60b661a5157d48835d4a7f0103a9265.png

afa85f2fd2a96fe25d392fb7d3dec00a.png

da26b4f51ec0499d2ac6a936f6151800.png

主函数:

474f7c6869892c958eb1b97f5270efe8.png

运行测试:

a745064d795ef1cf8cd0ec05341e3037.png

至此,lvgl显示移植成功。要想演示其它综合demo或控件例子也同上面一样导入源文件、包含头文件、打开demo宏开关等步骤进行演示。


版权声明:本文为weixin_28698129原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。