今天给大家带来的是LVGL移植的详细过程,有需要的小伙伴可以拿去尝试一下啦,感谢本文的笔者“想象之中”提供技术文章。
大家使用过SGUI的,也可以做了对比,两者小编认为都是不错的东西,其他的废话不多说,一起来看下详细的移植过程吧,另外,还没关注过的小伙伴抓紧关注起来哦!会有开发板、核心板等不定时参与活动赠送哦,目前已经赠送了2波啦!
/* 正文 */
官网下载LVGL源码,(可以通过github下载,也可以打包下载)甚至可以选择以前的版本进行下载
解压,得到下面的文件,我们暂时只用得上下面框住的文件
移植当中需要注意的是examples\porting文件夹下的文件,
还有就是src下面的源文件
准备好可以驱动显示器的MCU程序,这里以战舰板驱动3.5寸屏幕为例!!!
先在工程文件目录下创建文件夹“GUI”,在GUI文件夹下创建文件夹LVGL(文件夹的位置和名字不重要,在工程当中能够找到相关源程序即可)并将下载的源码文件夹下的所有文件复制到GUI文件夹下的LVGL文件夹下(我使用的是lvgl-8.0.3-dev)
把LVGL文件夹下的文件“lv_conf_template.h”剪切到上一层目录“GUI”下(注意是剪切),并将文件名改为lv_conf.h(你也可以不改,主要为了命名规范一点)
将GUI\LVGL\examples\porting文件夹下的文件命名进行更改,(你也可以不改,主要为了命名规范一点)如下图所示,暂时只用到显示部分,其他文件名暂时不更改。
打开工程,在工程当中创建三个文件夹,如下图所示:
然后将GUI文件夹目录下的文件“lv_conf.h”添加到“LVGL/USER”当中,将GUI\LVGL\examples\porting文件夹目录下的文件“lv_port_disp.c”添加到“LVGL/PORT”当中,将GUI\LVGL\src文件夹目录下的所有C文件添加到“LVGL/SRC”当中。
(GUI\LVGL\src\gpu文件夹下的文件暂时用不到,可以不用添加到工程当中,不过我还是添加到工程当中了)
添加头文件路径到工程当中,同时勾选上C99编译!!!
编译!!!查看错误
工程移植的差不多了,解析来就是移植LVGL的API了
首先打开文件“lv_port_disp.c”并使能,更改头文件名称(如果之前更改了GUI\LVGL\examples\porting文件夹目录下的文件名称的话),并添加显示屏的头文件,例如我的是:#include "nt35310_lcd.h"
然后打开对应的头文件“lv_port_disp.h”并使能,并添加函数”void lv_port_disp_init(void)“的声明
接下来我们需要更改函数“lv_port_disp.c”的内部实现方法!!!
首先我们需要对屏幕进行初始化,使用函数为:”disp_init()“,在函数内部实现对屏幕的初始化!!
我在初始化完将屏幕刷新成浅蓝色了。
static void disp_init(void) { /*You code here*/ NT35310_LCD_Init();//LCD初始化 NT35310_LCD_Clear(LIGHTBLUE);//填充浅蓝色 }
然后是更改函数”void lv_port_disp_init(void)“,其在内部提供有三种设置缓冲区的方法,这里我们使用第一种,将其他方式先屏蔽掉,这里用到了头文件"nt35310_lcd.h"当中定义了表示屏幕分辨率的宏,我们需要使用到它,用来告诉LVGL屏幕的大小,更改内容如下:
void lv_port_disp_init(void) { //#defineNT35310_LCD_WIDTH320//LCD水平分辨率 //#defineNT35310_LCD_HEIGHT480//LCD垂直分辨率 /*------------------------- * 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 to your display driver's `flush_cb` to copy its content to your display. * The buffer has to be greater than 1 display row * * There are 3 buffering configurations: * 1. Create ONE buffer: * LVGL will draw the display's content here and writes it to your display * * 2. Create TWO buffer: * 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. Double buffering * Set 2 screens sized buffers and set disp_drv.full_refresh = 1. * This way LVGL will always provide the whole rendered screen in `flush_cb` * and you only need to change the frame buffer's address. */ /*----------------------------------- * Register the display in LVGL *----------------------------------*/ static 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 = NT35310_LCD_WIDTH; disp_drv.ver_res = NT35310_LCD_HEIGHT; /*Used to copy the buffer's content to the display*/ disp_drv.flush_cb = disp_flush; /* Example for 1) */ static lv_disp_draw_buf_t draw_buf_dsc_1; static lv_color_t buf_1[NT35310_LCD_WIDTH * 10]; /*A buffer for 10 rows*/ lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, NT35310_LCD_WIDTH * 10); /*Initialize the display buffer*/ // /* Example for 2) */ // static lv_disp_draw_buf_t draw_buf_dsc_2; // static lv_color_t buf_2_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/ // static lv_color_t buf_2_1[MY_DISP_HOR_RES * 10]; /*An other buffer for 10 rows*/ // lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_1, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/ // /* Example for 3) also set disp_drv.full_refresh = 1 below*/ // static lv_disp_draw_buf_t draw_buf_dsc_3; // static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*A screen sized buffer*/ // static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*An other screen sized buffer*/ // lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2, MY_DISP_VER_RES * LV_VER_RES_MAX); /*Initialize the display buffer*/ // /*----------------------------------- // * Register the display in LVGL // *----------------------------------*/ // static 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 = 480; // disp_drv.ver_res = 320; // /*Used to copy the buffer's content to the display*/ // disp_drv.flush_cb = disp_flush; /*Set a display buffer*/ disp_drv.draw_buf = &draw_buf_dsc_1; /*Required for Example 3)*/ //disp_drv.full_refresh = 1 /* Fill a memory array with a color if you have GPU. * Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL. * But if you have a different GPU you can use with this callback.*/ //disp_drv.gpu_fill_cb = gpu_fill; /*Finally register the driver*/ lv_disp_drv_register(&disp_drv); }
因为STM32F103没有GPU(DMA2D)功能,所以只能使用函数”disp_flush“进行刷新,在函数内部替换成我们的画点函数,更改代码如下
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/ int32_t x; int32_t y; for(y = area->y1; y <= area->y2; y++) { for(x = area->x1; x <= area->x2; x++) { /*Put a pixel to the display. For example:*/ /*put_px(x, y, *color_p)*/ NT35310_LCD_DrawPoint(x, y, (color_p)++->full); } } /*IMPORTANT!!! *Inform the graphics library that you are ready with the flushing*/ lv_disp_flush_ready(disp_drv); }
到这里我们的显示API就移植的差不多了,解析来就是要开启LVGL!
开启LVGL需要调用以下函数,但是咱们暂时只用到了显示器,所以只需要调用前两个函数即可,后三个函数与下examples\porting文件夹下的文件一一对应。
lv_init(); // lvgl初始化函数,在使用LVGL前必须调用 lv_port_disp_init(); // 显示器初始化 lv_port_indev_init(); // 输入设备初始化 lv_port_fs_init(); // 文件系统设备初始化
然后是使得LVGL进行心跳,需要调用以下函数
lv_tick_inc(LVGL_TICK);// tick 提供时钟,LVGL_TICK 一般为 5ms 即可 lv_timer_handler(); // 运行所有lvgl的timer
咱们暂时不使用RTOS,所以通过下面的方式进行初始化:
//添加头文件 #include "lv_port_disp.h" #include <lvgl.h> #define LVGL_TICK 5 int main(void) { lv_init(); lv_port_disp_init(); // 显示器初始化 while(1) { // 先调用 lv_tick_inc 再调用 lv_timer_handler lv_tick_inc(LVGL_TICK);// tick 提供时钟,LVGL_TICK 一般为 5ms 即可 lv_timer_handler(); // 运行所有lvgl的timer DelayMs(LVGL_TICK); } }
最后一步,配置LVGL!!
打开配置文件"lv_conf.h"并使能,选择自己屏幕对应的颜色深度!!!
更改LVGL运行所使用的RAM大小:
开启监控设置
最后在主程序当中写入例子程序!!!
编译下载运行,结果如下:
更改堆栈空间的方法:
至此移植就全部结束啦,感谢“想象之中”分享的技术文章。如果你也有好的文章、笔记分享,也和小编联系吧!
如果觉得本篇文章多少有点帮助的话大家不要忘了,点赞、关注、评论、转发哦,你们的支持是小编创作的最大动力。