之前有记录过在 esp32 中使用 LVGL 的笔记,需要的小伙伴可以了解一下,esp-idf 移植 lvgl8.3.3
我之前整理的学习资料:https://www.cnblogs.com/jzcn/p/16647106.html
开发板:一块 linux 的开发板 或 linux 的虚拟机
lvgl:8.3.3
系统:ubuntu 18.04
注意:在 linux 环境下使用 lvgl 就相对比较简单了,这里记录了两个方式。
二、方式一
因为 linux 环境下,官方已经简历好项目的,所以只需要直接拉取就好了。
仓库地址:https://github.com/lvgl/lv_port_linux_frame_buffer
-
git 命令
git clone --recursive https://github.com/lvgl/lv_port_linux_frame_buffer.git # 如果拉取不下来,可以使用下面的加速地址,我也不知道是否会失效 https://github.moeyy.xyz/https://github.com/lvgl/lv_port_linux_frame_buffer.git
注意:拉取的时候已经要加
--recursive
,否则项目中的子工程拉不下来,如果拉取时忘记加--recursive
参数,可以在拉取完成是使用git submodule update --init --recursive
命令更新一下即可。 -
工程目录
拉取完成后,工程目录如下所示: -
编译工程
直接使用make
命令编译即可,完成后如下图所示:会直接生成可执行文件,如下图所示:注意: 发现可执行文件后,基本就完成了,直接运行即可,
./demo
,毫无疑问基本会运行失败,结果如下图所示: -
修改显示驱动
这里的显示驱动都是使用的 Framebuffer 缓冲区,我之间有个简单的笔记使用,不了解的小伙伴,可以看我之前的笔记,Linux Framebuffer 实验,知道自己的缓冲区设备后,就可以直接在文件lv_drv_conf.h
中进行修改,不过多数情况下都是/dev/fb0
可以不用修改,如下图所示: -
修改鼠标或触摸驱动
在修改鼠标或触摸驱动时,需要借助evtest
工具,找到自己设备的输入事件。-
安装 evtset 工具
sudo apt-get install evtest
-
使用命令
sudo evtest
找到对应的事件编号,如下图所示:
找到鼠标事件后,直接在
lv_drv_conf.h
文件中,更改对应的事件编号即可,如下图所示: -
-
运行测试
完成驱动修改后,重新编译测试,因为使用的是 Framebuffer 缓冲区,所以在 ubuntu 缓冲区中使用是,需要关闭图形显示后,才是正常使用 Framebuffer ,命令如下# 关闭图形显示 systemctl set-default multi-user.target reboot # 打开图形显示 systemctl set-default graphical.target reboot
关闭图形显示后,测试结果如下图所示:
三、方式二
上面我们已经完成了,在 ubuntu 中测试 LVGL 操作还是比较简单的,现在我们开始尝试手动创建工程,并将编译后生成的.o文件放到指定目录下,然后更改编译工具,使其在arm开发板中进行使用。
注意: 在创建过程中,有什么问题可以直接参考上面的工程,可以解决我们过程中遇到的问题
-
下载 LVGL
- lvlg:https://github.com/lvgl/lvgl
- lv_drivers:https://github.com/lvgl/lv_drivers
- lv_demos:https://github.com/lvgl/lv_demos
-
创建工程目录
这里我就不详细说明了,直接上图,只要文件目录如图所示一样即可,路径图下图所示: -
将 lvgl 移动到 lib 文件下,并删除多余的文件,如下图所示:
注意:其中的lv_conf.h
文件是直接将lv_conf_template.h
拷贝后进行重命名的,完成后将文件中的#if 0
改为#if 1
-
将 lvgl 目录下的 demos 文件拷贝到 lib 文件下,如下图所示:
注意:这里为了 demos 使用中减少问题,我直接拷贝了 lvgl 文件下的 demos 并重命名为 lv_demos -
将 lv_drivers 拷贝到 lib 文件下,并删除多余的文件,如下图所示:
注意:其中lv_drv_conf.h
文件是拷贝lv_drv_conf_template.h
文件重命名后得到的,完成后将文件中的#if 0
改为#if 1
-
将 lvgl 目录下的 examples 文件拷贝到 lib 文件下,如下图所示:
-
在 application 文件下创建 main.c 文件,内容如下:
#include "lvgl.h" #include "../lib/lv_demos/lv_demos.h" #include "../lib/lv_drivers/display/fbdev.h" #include "../lib/lv_drivers/indev/evdev.h" #include <unistd.h> #include <pthread.h> #include <time.h> #include <sys/time.h> #define DISP_BUF_SIZE (128 * 1024) int main(void) { /*LittlevGL 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 = 800; disp_drv.ver_res = 480; lv_disp_drv_register(&disp_drv); evdev_init(); static lv_indev_drv_t indev_drv_1; lv_indev_drv_init(&indev_drv_1); /*Basic initialization*/ indev_drv_1.type = LV_INDEV_TYPE_POINTER; /*This function will be called periodically (by the library) to get the mouse position and state*/ indev_drv_1.read_cb = evdev_read; lv_indev_t *mouse_indev = lv_indev_drv_register(&indev_drv_1); /*Set a cursor for the mouse*/ LV_IMG_DECLARE(mouse_cursor_icon) lv_obj_t * cursor_obj = lv_img_create(lv_scr_act()); /*Create an image object for the cursor */ lv_img_set_src(cursor_obj, &mouse_cursor_icon); /*Set the image source*/ lv_indev_set_cursor(mouse_indev, cursor_obj); /*Connect the image object to the driver*/ /*Create a Demo*/ lv_demo_widgets(); /*Handle LitlevGL tasks (tickless mode)*/ while(1) { lv_timer_handler(); usleep(5000); } return 0; } /*Set in lv_conf.h as `LV_TICK_CUSTOM_SYS_TIME_EXPR`*/ uint32_t custom_tick_get(void) { static uint64_t start_ms = 0; if(start_ms == 0) { struct timeval tv_start; gettimeofday(&tv_start, NULL); start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000; } struct timeval tv_now; gettimeofday(&tv_now, NULL); uint64_t now_ms; now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000; uint32_t time_ms = now_ms - start_ms; return time_ms; }
-
拷贝鼠标文件 mouse_cursor_icon.c
将方式一中获取到的鼠标文件拷贝到 application 文件下 -
在 lib 目录下创建 lib.mk 文件,内容如下:
##################################### lvgl库 ##################################### # 文件路径 LVGL_DIR ?= $(PROJECT_PATH)/lib # 所需的宏定义 CFLAGS += -DLV_CONF_INCLUDE_SIMPLE CFLAGS += -DLV_LVGL_H_INCLUDE_SIMPLE # lvgl库 LVGL_DIR_NAME ?= lvgl # 所需头文件的路径 CFLAGS += -I$(LVGL_DIR)/lvgl # 收集需要编译的源文件 include $(LVGL_DIR)/lv_demos/lv_demos.mk include $(LVGL_DIR)/lv_examples/lv_examples.mk include $(LVGL_DIR)/lv_drivers/lv_drivers.mk include $(LVGL_DIR)/$(LVGL_DIR_NAME)/lvgl.mk
-
在主目录下创建 Makefile 文件,内容如下:
# # Makefile # 编译的.o文件和.c文件在同一路径下 # $(info "start...") # 可执行文件名 PROJECT_NAME = lvgl_app ##################################### 项目路径 ##################################### PROJECT_PATH ?= ${shell pwd} OBJ_DIR := $(PROJECT_PATH)/build ##################################### 设置编译器,默认使用GCC ##################################### CC = arm-linux-gnueabihf-gcc CC ?= gcc ##################################### 所需头文件的路径 ##################################### # lv_conf.h CFLAGS += -I$(PROJECT_PATH)/lib/lvgl # lv_drv_conf.h CFLAGS += -I$(PROJECT_PATH)/lib/lv_drivers ##################################### 编译和链接参数 ##################################### CFLAGS ?= -O3 -g0 -Wall -Wshadow -Wundef -Wmissing-prototypes -Wno-discarded-qualifiers -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 \ -Wshift-negative-value -Wstack-usage=2048 -Wno-unused-value LDFLAGS ?= -lm ##################################### 收集需要编译的源文件 ##################################### CSRCS += $(PROJECT_PATH)/application/main.c CSRCS += $(PROJECT_PATH)/application/mouse_cursor_icon.c include $(PROJECT_PATH)/lib/lib.mk ##################################### 将文件名替换为.o文件 ##################################### AOBJS = $(ASRCS:.S=.o) COBJS = $(CSRCS:.c=.o) # CXX_SOURCES = $(foreach dir,$(CSRCS), $(wildcard $(dir)/*.c)) # CXX_OBJCTS = $(patsubst %.c, $(OBJ_DIR)/%.o, $(CSRCS)) all: default %.o: %.c @$(CC) $(CFLAGS) -c $< -o $@ #@echo "CC $<" default: $(COBJS) $(CC) -o $(PROJECT_NAME) $(COBJS) $(AOBJS) $(LDFLAGS) clean: rm -f $(PROJECT_NAME) $(COBJS) $(AOBJS)
注意: 到此工程文件已经创建好了,接下来只需要解决我们工程放置文件路径导致的问题即可,目录结构如下图所示:
-
修改 lib/lv_demos/lv_demos.mk 文件内容如下:
CSRCS += $(shell find -L $(LVGL_DIR)/lv_demos -name "*.c")
-
修改 lib/lv_examples/lv_examples.mk 文件,内容如下:
CSRCS += $(shell find -L $(LVGL_DIR)/lv_examples -name \*.c)
-
修改 lib/lvgl/lvgl.mk
-
启动相应的功
- USE_FBDEV:在文件 lv_drv_conf.h 中
- USE_EVDEV:在文件 lv_drv_conf.h 中
- LV_USE_DEMO_WIDGETS:在文件 lv_conf.h,主要作用是启动相应的案例
-
在编译的过程中会有 lvgl.h 头文件的引用错误。如下所示:
#include "../../../lvgl.h"
这是因为我们移动路径导致的,所以只需要将所以文件引用改为
#include "lvgl.h"
即可
注意:到此我们自己在 Linux 环境下创建的 LVGL 工程就已经完成了,这里自己创建 lvgl 的目的主要是方便版本的选择,可以根据自己的需要选择相应的 LVGL 版本。
四、指定 .o 文件的存放路径
上面的工程中会发现编译生成的.o文件和.c文件是在同一路径下的,那么在实际开发中有不方便之处,所以将.o文件指定到build文件下,操作比较简单,只需要将 Makefile 文件进行更改即可,如下所示:
Makefile 文件
#
# Makefile
# 编译的.o文件和.c文件在同一路径下
#
$(info "start...")
# 可执行文件名
PROJECT_NAME = lvgl_app
##################################### 项目路径 #####################################
PROJECT_PATH ?= ${shell pwd}
OBJ_DIR := $(PROJECT_PATH)/build
##################################### 设置编译器,默认使用GCC #####################################
CC = arm-linux-gnueabihf-gcc
CC ?= gcc
##################################### 所需头文件的路径 #####################################
# lv_conf.h
CFLAGS += -I$(PROJECT_PATH)/lib/lvgl
# lv_drv_conf.h
CFLAGS += -I$(PROJECT_PATH)/lib/lv_drivers
##################################### 编译和链接参数 #####################################
CFLAGS ?= -O3 -g0 -Wall -Wshadow -Wundef -Wmissing-prototypes -Wno-discarded-qualifiers -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 \
-Wshift-negative-value -Wstack-usage=2048 -Wno-unused-value
LDFLAGS ?= -lm
##################################### 收集需要编译的源文件 #####################################
CSRCS += $(PROJECT_PATH)/application/main.c
CSRCS += $(PROJECT_PATH)/application/mouse_cursor_icon.c
include $(PROJECT_PATH)/lib/lib.mk
##################################### 将文件名替换为.o文件 #####################################
CXX_OBJCTS = $(patsubst %.c, $(OBJ_DIR)/%.o, $(notdir $(CSRCS)))
SOURSE_DIR = $(dir $(CSRCS))
vpath %.c $(SOURSE_DIR)
$(OBJ_DIR)/%.o: %.c
@$(CC) $(CFLAGS) -c $< -o $@
#@echo "CC $<"
all: $(CXX_OBJCTS)
@$(CC) -o $(PROJECT_NAME) $(CXX_OBJCTS) $(LDFLAGS)
clean:
@rm -f $(PROJECT_NAME) $(CXX_OBJCTS)
笔记到此结束,有写得不好的地方望各位大佬指出