本帖最后由 linguanghua 于 2021-9-1 16:13 编辑
上次移植过单色屏的GUI到AC781X开发板,现在找个彩屏,移植littlevGL(选择叫LVGL)。这个GUI版本更新很快,我最初使用是2019年,那时候国内很少人使用,现在已经更新到8.0版本了,已经很流行了,而原来的API已经面目全非。V7中的原来自带的task任务系统变成V8中的timer,不过本质上是一样的,定时调用。
0.开始移植,准备一个可正常使用的工程,包含LCD驱动。工程目录新建文件夹“LVGL”。
1.下载LVGL代码。目前最新V8.1了。
源码:https://github.com/lvgl/lvgl
官网:https://lvgl.io/
2.文档lvgl-master解压,复制文件夹“src”,文件lvgl.h和lv_conf_template.h 到文件夹“LVGL”,复制 examples下porting文件夹到文件夹“LVGL”。
3.文件夹“LVGL”下,将lv_conf_template.h改名为lv_conf.h,此文件内部,将开头的 #if 0 改为 #if 1,#define LV_COLOR_DEPTH 16这里修改为LCD位深。
此文件内有许多宏定义,可开关特定的功能、性能。
4.将lv_port_disp_template.c改名lv_port_disp.c,对应.H文件名也要修改。
lv_port_disp.c修改如下:(不知道为什么显示不了)
- /**
- * [url=home.php?mod=space&uid=288409]@file[/url] lv_port_disp_templ.c
- *
- */
- /*Copy this file as "lv_port_disp.c" and set this value to "1" to enable content*/
- #if 1
- /*********************
- * INCLUDES
- *********************/
- #include "lv_port_disp.h"
- #include "../../lvgl.h"
- #include "lcd.h"
- /*********************
- * DEFINES
- *********************/
- /**********************
- * TYPEDEFS
- **********************/
- /**********************
- * STATIC PROTOTYPES
- **********************/
- static void disp_init(void);
- static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
- //static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
- // const lv_area_t * fill_area, lv_color_t color);
- /**********************
- * STATIC VARIABLES
- **********************/
- /**********************
- * MACROS
- **********************/
- /* Maximal horizontal and vertical resolution to support by the library.*/
- #define MY_DISP_HOR_RES (160) //320
- #define MY_DISP_VER_RES (128) //480
- /**********************
- * GLOBAL FUNCTIONS
- **********************/
- 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 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.
- */
- /* Example for 1) */
- static lv_disp_draw_buf_t draw_buf_dsc_1;
- static lv_color_t buf_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/
- lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10); /*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 = MY_DISP_HOR_RES;
- disp_drv.ver_res = MY_DISP_VER_RES;
- /*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);
- }
- /**********************
- * STATIC FUNCTIONS
- **********************/
- /*Initialize your display and the required peripherals.*/
- static void disp_init(void)
- {
- /*You code here*/
- }
- /*Flush the content of the internal buffer the specific area on the display
- *You can use DMA or any hardware acceleration to do this operation in the background but
- *'lv_disp_flush_ready()' has to be called when finished.*/
- 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*/
- LCD_Color_Fill(area->x1,area->y1,area->x2,area->y2,(u16*)color_p);
- /*IMPORTANT!!!
- *Inform the graphics library that you are ready with the flushing*/
- lv_disp_flush_ready(disp_drv);
- }
- /*OPTIONAL: GPU INTERFACE*/
- /*If your MCU has hardware accelerator (GPU) then you can use it to fill a memory with a color*/
- //static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
- // const lv_area_t * fill_area, lv_color_t color)
- //{
- // /*It's an example code which should be done by your GPU*/
- // int32_t x, y;
- // dest_buf += dest_width * fill_area->y1; /*Go to the first line*/
- //
- // for(y = fill_area->y1; y <= fill_area->y2; y++) {
- // for(x = fill_area->x1; x <= fill_area->x2; x++) {
- // dest_buf[x] = color;
- // }
- // dest_buf+=dest_width; /*Go to the next line*/
- // }
- //}
- #else /*Enable this file at the top*/
- /*This dummy typedef exists purely to silence -Wpedantic.*/
- typedef int keep_pedantic_happy;
- #endif
5.打开工程文件,添加连个组 lvgl/src 和 lvgl/port ,将各个C文件导入工程。一些字体文件(font)和 extra 内的文件,gpu文件可不用添加,除非使用到。
6.定时器中断函数里加入lv_tick_inc(1);
- /**
- * [url=home.php?mod=space&uid=555622]@prototype[/url] TIM2_IRQnCallBack(uint8_t lparam)
- *
- * @param[in] ...
- * [url=home.php?mod=space&uid=266161]@return[/url] ...
- *
- * [url=home.php?mod=space&uid=247401]@brief[/url] TIM2 module interrupt handler.
- * TIM2中断处理函数.
- */
- void TIM2_IRQnCallBack(uint8_t lparam)
- {
- if (TIMER_GetIntFlag(TIMER2))
- {
-
- g_ctimeflag=1;
- lv_tick_inc(1);
- }
- TIMER_ClrIntFlag(TIMER2);
- }
6.在需要的地方添加头文件(如main.c)
#include "lvgl.h"
#include "lv_port_disp.h"
程序开头加入
- lv_init();
- lv_port_disp_init();
然后在主函数的死循环或者低优先级任务中加入lv_task_handler();
这样就可以正常使用了。
用的屏幕比较小,不好发挥这个GUI的长处,随便弄些看看效果。在大屏中,这个GUI效果很不错。总体上比emWin好看。
|