这篇文章主要记录lvgl的移植和例程运行,主要参考文章为lvgl官方文章以及 论坛大佬们的文章。
测试例程基于Linux帧缓冲区实现,因此目标设备需要支持帧缓冲区,以下内容摘抄自官方文章:
也许你对 Linux 帧缓冲设备很熟悉。它是一个通常位于/dev/fb0的文件。此文件包含显示器的像素数据。如果您将某些内容写入帧缓冲区文件,则更改将显示在显示屏上。如果您在PC 上使用 Linux,您可以使用终端进行尝试:
- 按Ctrl + Alt + F1 离开桌面并更改为简单字符终端
- 输入sudo su并输入您的密码
- 停止你的显示管理器(在 Ubuntu 上是lightdm):service lightdm stop重要:它会注销你,所以所有的窗口都会被关闭
- 将随机数据写入帧缓冲设备:cat /dev/urandom > /dev/fb0您应该在整个屏幕上看到随机颜色的像素。
- 要返回正常的图形用户界面:service lightdm start
在我们的 开发板上,只需要输入“cat /dev/urandom > /dev/fb0”指令,就能看到屏幕出现雪花屏。
主要下载lvgl库和lv_drivers库,lv_examples库作为可选项(实际上我没有找到该库)。我是直接通过github下载的,网络时好时坏,只能趁墙不注意就疯狂clone了。两个库的地址分别如下:
建议独立下载的一个文件夹中,需要的时候copy出去。
另外需要格外注意,clone下来的2个库需要切换到release分支(我切换到release_v8.2分支),使用master分支可能会出现一些意料之外的事情,比如我遇到SDL的问题,在安装了libsdl2-dev之后,依然报找不到SDL2/SDL.h文件甚至SDL2/_real_SDL_config.h文件的问题。
- 先创建测试例程项目文件夹。
- 复制步骤1中下载的lvgl、lvgl_drivers文件夹到项目文件夹中。
- 复制lvgl目录下的lv_conf_template.h到项目文件夹下,并命名为lv_conf.h,取消15行的if 0(改为if 1即可),将27行的LV_COLOR_DEPTH 更改为32。
- 复制lvgl_drivers目录下的lv_drv_conf_template.h到项目文件夹下,并命名为lv_drv_conf.h,取消11行的if 0。将89行的USE_SDL置为1(此处需要确保已经安装了SDL库,安装的指令为”sudo apt-get install libsdl2-dev“,此处参考 https://www.cnblogs.com/dylancao/p/9039632.html ),将319行的USE_FBDEV设置为1。
- 创建main.c文件
其文件内容来源于官网,代码如下,注意需要更改屏幕尺寸,将800改为480(disp_drv.hor_res = 480;),并且需要定义DISP_BUF_SIZE宏的值。
- #include "lvgl/lvgl.h"
- #include "lv_drivers/display/fbdev.h"
- #include
-
- #define DISP_BUF_SIZE (128 * 1024)
-
- int main(void)
- {
- /*LVGL init*/
- lv_init();
-
- /*Linux frame buffer device init*/
- fbdev_init();
-
- /*A small buffer for LittlevGL to draw the screen's content*/
- static lv_color_t buf[DISP_BUF_SIZE];
-
- /*Initialize a descriptor for the buffer*/
- static lv_disp_draw_buf_t disp_buf;
- lv_disp_draw_buf_init(&disp_buf, buf, NULL, DISP_BUF_SIZE);
-
- /*Initialize and register a display driver*/
- static lv_disp_drv_t disp_drv;
- lv_disp_drv_init(&disp_drv);
- disp_drv.draw_buf = &disp_buf;
- disp_drv.flush_cb = fbdev_flush;
- disp_drv.hor_res = 480;
- disp_drv.ver_res = 480;
- lv_disp_drv_register(&disp_drv);
-
- /*Create a "Hello world!" label*/
- lv_obj_t * label = lv_label_create(lv_scr_act());
- lv_label_set_text(label, "Hello world!");
- lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
-
- /*Handle LitlevGL tasks (tickless mode)*/
- while(1) {
- lv_tick_inc(5);
- lv_timer_handler();
- usleep(5000);
- }
-
- return 0;
- }
复制代码
makefile文件来源于sdk,路径为(tina-d1-h/package/gui/littlevgl-8/lv_examples/src/Makefile),需要修改两个地方:
- 第4行的编译器需要指定为sdk中的交叉编译器:CC = riscv64-unknown-linux-gnu-gcc
- 第17行的内容需要去掉:include $(LVGL_DIR)/lv_demos/lv_demo.mk
完整的makefile文件内容如下:
- #
- # Makefile
- #
- CC = riscv64-unknown-linux-gnu-gcc
- LVGL_DIR_NAME ?= lvgl
- LVGL_DIR ?= ${shell pwd}
- CFLAGS ?= -O3 -g0 -I$(LVGL_DIR)/ -Wall -Wshadow -Wundef -Wmissing-prototypes -Wno-discarded-qualifiers -Wall -Wextra -Wno-unused-function -Wno-error=strict-prototypes -Wpointer-arith -fno-strict-aliasing -Wno-error=cpp -Wuninitialized -Wmaybe-uninitialized -Wno-unused-parameter -Wno-missing-field-initializers -Wtype-limits -Wsizeof-pointer-memaccess -Wno-format-nonliteral -Wno-cast-qual -Wunreachable-code -Wno-switch-default -Wreturn-type -Wmultichar -Wformat-security -Wno-ignored-qualifiers -Wno-error=pedantic -Wno-sign-compare -Wno-error=missing-prototypes -Wdouble-promotion -Wclobbered -Wdeprecated -Wempty-body -Wtype-limits -Wshift-negative-value -Wstack-usage=2048 -Wno-unused-value -Wno-unused-parameter -Wno-missing-field-initializers -Wuninitialized -Wmaybe-uninitialized -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wtype-limits -Wsizeof-pointer-memaccess -Wno-format-nonliteral -Wpointer-arith -Wno-cast-qual -Wmissing-prototypes -Wunreachable-code -Wno-switch-default -Wreturn-type -Wmultichar -Wno-discarded-qualifiers -Wformat-security -Wno-ignored-qualifiers -Wno-sign-compare
- LDFLAGS ?= -lm
- BIN = lvgl_helloworld
-
-
- #Collect the files to compile
- MAINSRC = ./main.c
-
- include $(LVGL_DIR)/lvgl/lvgl.mk
- include $(LVGL_DIR)/lv_drivers/lv_drivers.mk
-
- OBJEXT ?= .o
-
- AOBJS = $(ASRCS:.S=$(OBJEXT))
- COBJS = $(CSRCS:.c=$(OBJEXT))
-
- MAINOBJ = $(MAINSRC:.c=$(OBJEXT))
-
- SRCS = $(ASRCS) $(CSRCS) $(MAINSRC)
- OBJS = $(AOBJS) $(COBJS)
-
- ## MAINOBJ -> OBJFILES
-
- all: default
-
- %.o: %.c
- @$(CC) $(CFLAGS) -c [ DISCUZ_CODE_122 ]lt; -o $@
- [url=home.php?mod=space&uid=70594]@echo[/url] "CC [ DISCUZ_CODE_122 ]lt;"
-
- default: $(AOBJS) $(COBJS) $(MAINOBJ)
- $(CC) -o $(BIN) $(MAINOBJ) $(AOBJS) $(COBJS) $(LDFLAGS)
-
- clean:
- rm -f $(BIN) $(AOBJS) $(COBJS) $(MAINOBJ)
复制代码
在项目文件夹下输入make即可,可以适当使用-j参数提高编译速度。编译完成之后在项目文件下下生成指定的二进制文件(我这里名字叫lvgl_helloworld。
使用file指令查看,得到如下结果:
lvgl_helloworld: ELF 64-bit LSB executable, UCB RISC-V, RVC, double-float ABI, version 1 (SYSV),dynamically linked, interpreter /lib/ld-linux-riscv64xthead-lp64d.so.1, forGNU/Linux 4.15.0, with debug_info, not stripped
将二进制文件传输到开发板并执行,得到如下结果:
这部分参考论坛大佬的文章( 【平头哥Sipeed LicheeRV 86Panel测评】 4-移植lvgl-增加触控 ),其流程如下:
使用“getevent”指令,可以看到输入设备的信息,此时点击触摸屏,将打印坐标信息,如下图所述:
这里可知触摸屏对应的设备为/dev/input/event2。
只需要更改两个位置即可,如下图红框所示:
按键的例程来源于lvgl文档中心的2.1.1章节《Abutton with a label and react on click event》,将其copy到测试程序中,并在main函数中调用按键注册的函数(lv_example_get_started_1)即可。
- #include "lvgl/lvgl.h"
- #include "lv_drivers/display/fbdev.h"
- #include "lv_drivers/indev/evdev.h"
- #include
-
- static void btn_event_cb(lv_event_t * e)
- {
- printf("button event triggern");
- lv_event_code_t code = lv_event_get_code(e);
- lv_obj_t * btn = lv_event_get_target(e);
- if(code == LV_EVENT_CLICKED) {
- static uint8_t cnt = 0;
- cnt++;
- printf("button clicked, cnt:%dn", cnt);
-
- /*Get the first child of the button which is the label and change its text*/
- lv_obj_t * label = lv_obj_get_child(btn, 0);
- lv_label_set_text_fmt(label, " Button: %d" , cnt);
- }
- }
-
- void lv_example_pbt( void)
- {
- lv_obj_t * btn = lv_btn_create(lv_scr_act()); /*Add a button the current screen*/
- lv_obj_set_pos(btn, 10, 50); /*Set its position*/
- lv_obj_set_size(btn, 120, 50); /*Set its size*/
- lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_CLICKED, NULL); /*Assign a callback to the button*/
- lv_obj_t * label = lv_label_create(btn); /*Add a label to the button*/
- lv_label_set_text(label, " Button" ); /*Set the labels text*/
- lv_obj_center(label);
- printf("create button succeedn");
- }
-
- int main(void)
- {
- static uint32_t width = 480, height = 480;
-
- /*LVGL init*/
- lv_init();
-
- /*Linux frame buffer device init*/
- fbdev_init();
-
- evdev_init();
-
- /*A small buffer for LittlevGL to draw the screen's content*/
- static lv_color_t *buf;
- buf = (lv_color_t*) malloc(width * height * sizeof (lv_color_t));
- if (buf == NULL) {
- printf("malloc draw buffer failn");
- return 0;
- }
-
- /*Initialize a descriptor for the buffer*/
- static lv_disp_draw_buf_t disp_buf;
- lv_disp_draw_buf_init(&disp_buf, buf, NULL, width * height);
-
- /*Initialize and register a display driver*/
- static lv_disp_drv_t disp_drv;
- lv_disp_drv_init(&disp_drv);
- disp_drv.draw_buf = &disp_buf;
- disp_drv.flush_cb = fbdev_flush;
- disp_drv.hor_res = width;
- disp_drv.ver_res = height;
- lv_disp_drv_register(&disp_drv);
-
- /*Create a "Hello world!" label*/
- lv_obj_t * label = lv_label_create(lv_scr_act());
- lv_label_set_text(label, "LVGL Base Funtion Test!");
- lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 20);
-
- lv_example_pbt();
-
- /*Handle LitlevGL tasks (tickless mode)*/
- while(1) {
- static uint32_t cnt = 0;
- cnt++;
- if (cnt % 100 == 0) {
- printf("while 1 runring, cnt:%dn", cnt);
- }
- lv_tick_inc(5);
- lv_timer_handler();
- usleep(5000);
- }
-
- return 0;
- }
复制代码
编译并运行,界面能正常显示,但是按键事件无法响应(或者说屏幕的触摸事件没有响应),后来在博文 【平头哥Sipeed LicheeRV 86Panel测评】九、lvgl再使用 中,发现还有一个“初始化和注册事件设备”的动作,其代码如下:
- lv_indev_drv_t indev_drv;
- lv_indev_drv_init(&indev_drv);
- indev_drv.type = LV_INDEV_TYPE_POINTER; //by author. input device type, choice touchpad here
- indev_drv.read_cb = evdev_read; //by author. callback to read input device data
- lv_indev_t *my_indev = lv_indev_drv_register(&indev_drv);
复制代码
将上述代码加入到main函数中,重新编译并上传到开发板运行,此时按键事件已经能够正常触发。
此前看到的lvgl信息大多都是音乐播放器的例程,本来打算试试,将sdk中的例程copy过来并解决编译错误,生成的二进制文件虽然能执行,但是会卡在加载界面,其他例程也是如此,应该是某些地方配置错误或者程序流程处理不合理导致的, 鉴于目前只是简单了解,就不再追究原因。
看了一下lvgl的简介和api,确实很全面,用得好能达到非常好的效果,对于嵌入式( 单片机)非常友好。然而全部需要程序完成界面的绘制,对于一个个人项目来说,我觉得有点累。既然我们的开发板配置足够强大,我打算再试试QT。
0
|
|
|
|