之前有记录过在 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

  1. git 命令
1
2
3
4
5
6
7
8
9


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
  1. 注意:拉取的时候已经要加 –recursive,否则项目中的子工程拉不下来,如果拉取时忘记加 –recursive 参数,可以在拉取完成是使用 git submodule update –init –recursive 命令更新一下即可。

  2. 工程目录

    拉取完成后,工程目录如下所示:

  3. 编译工程

    直接使用 make 命令编译即可,完成后如下图所示:会直接生成可执行文件,如下图所示:

    注意: 发现可执行文件后,基本就完成了,直接运行即可,./demo ,毫无疑问基本会运行失败,结果如下图所示:

  4. 修改显示驱动

    这里的显示驱动都是使用的 Framebuffer 缓冲区,我之间有个简单的笔记使用,不了解的小伙伴,可以看我之前的笔记,Linux Framebuffer 实验,知道自己的缓冲区设备后,就可以直接在文件 lv_drv_conf.h 中进行修改,不过多数情况下都是 /dev/fb0 可以不用修改,如下图所示:

  5. 修改鼠标或触摸驱动

    在修改鼠标或触摸驱动时,需要借助 evtest 工具,找到自己设备的输入事件。

    找到鼠标事件后,直接在 lv_drv_conf.h 文件中,更改对应的事件编号即可,如下图所示:

    • 安装 evtset 工具
1
2
3


sudo apt-get install evtest

使用命令 sudo evtest 找到对应的事件编号,如下图所示:

运行测试

完成驱动修改后,重新编译测试,因为使用的是 Framebuffer 缓冲区,所以在 ubuntu 缓冲区中使用是,需要关闭图形显示后,才是正常使用 Framebuffer ,命令如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18


# 关闭图形显示





systemctl set-default multi-user.targetreboot


# 打开图形显示





systemctl set-default graphical.targetreboot

关闭图形显示后,测试结果如下图所示:

三、方式二

上面我们已经完成了,在 ubuntu 中测试 LVGL 操作还是比较简单的,现在我们开始尝试手动创建工程,并将编译后生成的.o文件放到指定目录下,然后更改编译工具,使其在arm开发板中进行使用。

注意: 在创建过程中,有什么问题可以直接参考上面的工程,可以解决我们过程中遇到的问题

  1. 下载 LVGL

  2. 创建工程目录

    这里我就不详细说明了,直接上图,只要文件目录如图所示一样即可,路径图下图所示:

  3. 将 lvgl 移动到 lib 文件下,并删除多余的文件,如下图所示:

    注意:其中的 lv_conf.h 文件是直接将 lv_conf_template.h 拷贝后进行重命名的,完成后将文件中的 #if 0 改为 #if 1

  4. 将 lvgl 目录下的 demos 文件拷贝到 lib 文件下,如下图所示:

    注意:这里为了 demos 使用中减少问题,我直接拷贝了 lvgl 文件下的 demos 并重命名为 lv_demos

  5. 将 lv_drivers 拷贝到 lib 文件下,并删除多余的文件,如下图所示:

    注意:其中 lv_drv_conf.h 文件是拷贝 lv_drv_conf_template.h 文件重命名后得到的,完成后将文件中的 #if 0 改为 #if 1

  6. 将 lvgl 目录下的 examples 文件拷贝到 lib 文件下,如下图所示:

  7. 在 application 文件下创建 main.c 文件,内容如下:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246


#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;


}
  1. 拷贝鼠标文件 mouse_cursor_icon.c

    将方式一中获取到的鼠标文件拷贝到 application 文件下

  2. 在 lib 目录下创建 lib.mk 文件,内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54


##################################### 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 文件,内容如下:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168


#


# 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)

注意: 到此工程文件已经创建好了,接下来只需要解决我们工程放置文件路径导致的问题即可,目录结构如下图所示:

  1. 修改 lib/lv_demos/lv_demos.mk 文件内容如下:
1
2
3


CSRCS += $(shell find -L $(LVGL_DIR)/lv_demos -name "*.c")
  1. 修改 lib/lv_examples/lv_examples.mk 文件,内容如下:
1
2
3


CSRCS += $(shell find -L $(LVGL_DIR)/lv_examples -name \*.c)
  1. 修改 lib/lvgl/lvgl.mk

  2. 启动相应的功

    • USE_FBDEV:在文件 lv_drv_conf.h 中

    • USE_EVDEV:在文件 lv_drv_conf.h 中

    • LV_USE_DEMO_WIDGETS:在文件 lv_conf.h,主要作用是启动相应的案例

  3. 在编译的过程中会有 lvgl.h 头文件的引用错误。如下所示:

    1
    2
    3
    
    
    
    #include "../../../lvgl.h"
    

    这是因为我们移动路径导致的,所以只需要将所以文件引用改为 #include “lvgl.h” 即可

注意:到此我们自己在 Linux 环境下创建的 LVGL 工程就已经完成了,这里自己创建 lvgl 的目的主要是方便版本的选择,可以根据自己的需要选择相应的 LVGL 版本。

四、指定 .o 文件的存放路径

上面的工程中会发现编译生成的.o文件和.c文件是在同一路径下的,那么在实际开发中有不方便之处,所以将.o文件指定到build文件下,操作比较简单,只需要将 Makefile 文件进行更改即可,如下所示:

Makefile 文件

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162


#


# 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)