LVGL使用指南
在本篇文章中,我们将详细介绍 Framebuffer(FB)设备和 LittlevGL(LVGL)图形用户界面库的基本概念。通过使用 Luckfox Pico Plus 开发板和 Pico-LCD-1.3 显示屏,我们将演示如何配置 FB 设备,利用 LVGL 库创建应用程序,最后在 LCD 实现界面显示。Luckfox Pico 和 Luckfox Pico Plus 通过烧录网盘提供的最新镜像,使用 Luckfox-config 工具就可以成功开启 FB 设备驱动。由于 Luckfox Pico Mini 无法直接连接 Pico-1.3-LCD,因此未将其添加到 Luckfox-config 设置中。可以下载以下镜像进行使用。
版本 | 描述 | 下载 |
---|---|---|
Luckfox Pico Mini A/B | 支持Framebuffer固件 | 镜像百度网盘链接 |
LVGL.zip | LVGL 测试程序 | LVGL.zip |
快速使用
-
下载压缩包,压缩包目录:
LVGL/
├── image ------------------------------- 镜像文件
├── lvgl_demo --------------------------- 工程目录
├── demo -------------------------------- 可执行文件
└── rv1103g-luckfox-pico-plus.dts ---- 设备树文件
└── rv1103g-luckfox-pico-mini-a.dts/rv1103g-luckfox-pico-mini-b.dts ---- 设备树文件 -
将压缩包中的
demo
通过adb
或者scp
至开发板,运行程序:chmod +x demo
./demo -
如果自己修改编译程序,可以将 Makefile 中
CC
修改为自己的 SDK 路径,例如:CC = /home/luckfox/luckfox-pico/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf-gcc
make
-
编译完成后会在
/build/bin
目录下生成一个可执行文件demo
,将该文件拷贝至开发板即可直接运行
-
编译完成后会在
1. Framebuffer(FB)设备
Linux 内核中常用的两类图形显示设备驱动框架分别是 DRM(Direct Rendering Manager)和 FBDEV(Framebuffer Device)。在 Framebuffer 驱动框架下,用户可以通过
/dev/fbX
接口直接操作显示设备的显存,进行标准文件操作(如
read
,
write
,
ioctl
)。用户空间程序可以通过这些设备节点和
ioctl
调用来控制帧缓冲设备。Framebuffer 提供基本的 2D 图形操作,如点、线、矩形的绘制,支持多种像素格式和分辨率。
1.1 内核设置
关于内核添加详细使用方法可以参考《SDK环境部署》部分。
-
进入内核目录。
cd /SDK目录/sysdrv/source/kernel
cp ./arch/arm/configs/luckfox_rv1106_linux_defconfig .config
make ARCH=arm menuconfig -
在内核中依次开启FB相关的驱动
CONFIG_VT_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FONTS=y -
保存配置
make ARCH=arm savedefconfig
cp defconfig arch/arm/configs/luckfox_rv1106_linux_defconfig
1.2 设备树文件
要驱动 LCD,除了在内核中启用 FB 相关驱动程序外,还必须确保所有与 LCD 通讯的引脚功能正常。在此之前,我们需要确定 Pico-LCD-1.3 与 Luckfox Pico Pro/Max 的连接引脚。设备树用于描述硬件资源,因此需要对设备树进行相应的修改。
1.2.1 相关引脚
这里面需要注意的是 Pico-LCD-1.3 内部电路做了强制电平转换,将输入电压(VSYS)转换为稳定的3.3V电压,所以可以使用VSYS来供电。更多引脚详情可以参考 Pico-LCD-1.3 的
Wiki
教程。
LCD | Luckfox Pico Plus | 功能 |
---|---|---|
VCC | VSYS | 电源输入 |
GND | GND | 电源地 |
DIN | SPI0_MOSI_M0 | SPI通信MOSI引脚,从设备数据输入 |
CLK | SPI0_CLK_M0 | SPI通信SCK引脚,从设备时钟输入 |
CS | SPI0_CS0_M0 | SPI片选引脚(低电平有效) |
DC | GPIO1_A2_d | 数据/命令控制引脚(高电平数据,低电平命令) |
RST | GPIO1_C3_d | 外部复位引脚(低电平有效) |
BL | GPIO0_A4_d | 背光控制 |
A | GPIO1_D1_d | 用户按键A |
B | GPIO3_A7_d | 用户按键B |
X | GPIO3_A4_d | 用户按键X |
Y | GPIO3_A3_d | 用户按键Y |
UP | GPIO1_C7_d | 摇杆向上 |
DOWM | GPIO3_A5_d | 摇杆向下 |
LEFT | GPIO3_A6_d | 摇杆向左 |
RIGHT | GPIO3_A2_d | 摇杆向右 |
CTRL | GPIO1_C6_d | 摇杆按下 |
LCD | Luckfox Pico Mini A/B | 功能 |
---|---|---|
VCC | 3V3(OUT) | 电源输入 |
GND | GND | 电源地 |
DIN | SPI0_MOSI_M0 | SPI通信MOSI引脚,从设备数据输入 |
CLK | SPI0_CLK_M0 | SPI通信SCK引脚,从设备时钟输入 |
CS | SPI0_CS0_M0 | SPI片选引脚(低电平有效) |
DC | GPIO1_C4_d | 数据/命令控制引脚(高电平数据,低电平命令) |
RST | GPIO1_C3_d | 外部复位引脚(低电平有效) |
BL | GPIO1_C5_d | 背光控制 |
1.2.2 设备树编写
-
在默认的设备树中, GPIO1_C7_d 的默认功能是 PWM 功能,在程序中,我们希望通过读取该引脚电平判断按键状态,所以我们需要将该引脚配置为普通IO。打开
<SDK目录>/sysdrv/source/kernel/arch/arm/boot/dts/rv1106g-luckfox-pico-pro-max.dts
/{
gpio1pc7:gpio1pc7 {
compatible = "regulator-fixed";
pinctrl-names = "default";
pinctrl-0 = <&gpio1_pc7>;
regulator-name = "gpio1_pc7";
regulator-always-on;
};
};
&pinctrl {
gpio1-pc7 {
gpio1_pc7:gpio1-pc7 {
rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
};- 完整设备请下载网盘的设备树文件,这里仅做部分展示
-
SPI 配置需要禁用
spidev@0
,否则fb
无法进行初始化。/**********SPI**********/
/* SPI0_M0 */
&spi0 {
status = "okay";
pinctrl-0 = <&spi0m0_clk &spi0m0_mosi &spi0m0_cs0>;
spidev@0 {
status = "disabled";
spi-max-frequency = <50000000>;
};
fbtft@0{
compatible = "sitronix,st7789v";
reg = <0>;
spi-max-frequency = <20000000>;
fps = <30>;
buswidth = <8>;
debug = <0x7>;
led-gpios = <&gpio1 RK_PC3 GPIO_ACTIVE_LOW>;//BL
dc = <&gpio1 RK_PC4 GPIO_ACTIVE_HIGH>; //DC
reset = <&gpio1 RK_PC5 GPIO_ACTIVE_LOW>; //RES
};
}; -
修改好设备树编译镜像,测试花屏和清屏
cat /dev/urandom > /dev/fb0 #花屏
cat /dev/zero > /dev/fb0 #清屏
2.移植LVGL(PC端)
2.1 LittlevGL 简介
LVGL(LittlevGL)是一款轻量级、开源的嵌入式图形库,专注于提供灵活易用的图形用户界面(GUI)解决方案。通过LVGL,开发者可以实现丰富的图形界面设计,包括按钮、滑块、文本框等各种常用的GUI控件,以及动画和触摸交互等功能。作为一款开源库,LVGL 广泛应用于各种嵌入式系统,并以其轻量级的特性受到开发者的喜爱。LVGL 支持多种显示设备,其中就包括 Framebuffer,使得开发者可以在嵌入式系统上轻松创建漂亮的用户界面。
2.2 所需资源
资源名称 | 仓库地址 | 描述 |
---|---|---|
lvgl | https://github.com/lvgl/lvgl.git | LVGL图形界面控件的源码以及少量例程 |
lv_drivers | https://github.com/lvgl/lv_drivers.git | 驱动LVGL图形界面的驱动接口源代码 |
lv_demos | https://github.com/lvgl/lv_demos.git | LVGL的例程 |
lv_port_linux_frame_buffer | https://github.com/lvgl/lv_port_linux_frame_buffer.git | 适配有Framebuffer的linux系统的接口 |
2.3 拉取资源
-
在根目录下创建一个文件夹存放官方源码:
luckfox@luckfox:~$ mkdir lvgl
luckfox@luckfox:~$ cd lvgl -
拉取资源:
git clone -b v8.1.0 https://github.com/lvgl/lvgl.git
git clone -b v8.1.0 https://github.com/lvgl/lv_drivers.git
git clone -b v8.1.0 https://github.com/lvgl/lv_demos.git
git clone --branch release/v8.2 --single-branch https://github.com/lvgl/lv_port_linux_frame_buffer.git -
成功拉取后,在根目录下创建一个工程目录,并创建一个工程:
luckfox@luckfox:~$ mkdir -p lvgl_project/project_01
luckfox@luckfox:~$ cd lvgl_project/project_01/
2.4 复制文件
-
复制根目录下的 lvgl 文件夹中的 lvgl、lv_drivers 目录
-
复制 lv_port_linux_frame_buffer 中的 main.c 与 Makefile
-
复制 lvgl 中的 lv_conf_template.h 重命名为 lv_conf.h
-
复制 lv_drivers 中的 lv_drv_conf_template.h 重命名为 lv_drv_conf.h
cp -r ~/lvgl/lvgl ./
cp -r ~/lvgl/lv_drivers ./
cp ~/lvgl/lvgl/lv_conf_template.h ./lv_conf.h
cp ~/lvgl/lv_drivers/lv_drv_conf_template.h ./lv_drv_conf.h
cp ~/lvgl/lv_port_linux_frame_buffer/main.c ./
cp ~/lvgl/lv_port_linux_frame_buffer/Makefile ./
查看 project_01 工程目录下文件:
luckfox@luckfox:~/lvgl_project/project_01$ ls -l
总用量 64
-rw-rw-r-- 1 luckfox luckfox 29023 12月 27 19:14 lv_conf.h
drwxrwxr-x 12 luckfox luckfox 4096 12月 27 19:14 lv_drivers
-rw-rw-r-- 1 luckfox luckfox 15184 12月 27 19:14 lv_drv_conf.h
drwxrwxr-x 12 luckfox luckfox 4096 12月 27 19:14 lvgl
-rw-rw-r-- 1 luckfox luckfox 2350 12月 27 19:14 main.c
-rw-rw-r-- 1 luckfox luckfox 2321 12月 27 19:14 Makefile
2.5 修改文件
lv_conf.h
-
使能
将一开始的
#if 0
改成#if 1
/* clang-format off */
#if 1 /*Set it to "1" to enable content*/ -
分配显存
使能
LV_MEM_CUSTOM
,选择自行分配显存/*1: use custom malloc/free, 0: use the built-in `lv_mem_alloc()` and `lv_mem_free()`*/
#define LV_MEM_CUSTOM 1 -
刷新时间
将原本的 30ms 调整成了 10ms
/*Default display refresh period. LVG will redraw changed areas with this period time*/
#define LV_DISP_DEF_REFR_PERIOD 10 /*[ms]*/
/*Input device read period in milliseconds*/
#define LV_INDEV_DEF_READ_PERIOD 10 /*[ms]*/ -
TICK配置
使能
LV_TICK_CUSTOM
,选择在应用程序中自定义 Tick 定时器配置函数原内容:
#define LV_TICK_CUSTOM 0
#if LV_TICK_CUSTOM
#define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/
#endif /*LV_TICK_CUSTOM*/更改为:
#define LV_TICK_CUSTOM 1
#if LV_TICK_CUSTOM
#define LV_TICK_CUSTOM_INCLUDE <stdint.h> /*Header for the system time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (custom_tick_get()) /*Expression evaluating to current system time in ms*/
#endif /*LV_TICK_CUSTOM*/
lv_drv_conf.h
-
使能
将一开始的
#if 0
改成#if 1
/* clang-format off */
#if 1 /*Set it to "1" to enable the content*/ -
支持设备
使能
USE_FBDEV
,支持Framebuffer设备/*-----------------------------------------
* Linux frame buffer device (/dev/fbx)
*-----------------------------------------*/
#ifndef USE_FBDEV
# define USE_FBDEV 1
#endif
#if USE_FBDEV
# define FBDEV_PATH "/dev/fb0"
#endif
Makefile
替换原 Makefile 内容,将 Makefile 中 <SDK Directory
>
修改为自己的 SDK 路径,如
/home/luckfox/luckfox-pico/
#
# Makefile
#
CC = <SDK Directory>/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf-gcc
LVGL_DIR_NAME ?= lvgl
LVGL_DIR ?= .
WARNINGS := -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 -std=c99
CFLAGS ?= -O3 -g0 -I$(LVGL_DIR)/ $(WARNINGS)
LDFLAGS ?= -lm
BIN = demo
BUILD_DIR = ./build
BUILD_OBJ_DIR = $(BUILD_DIR)/obj
BUILD_BIN_DIR = $(BUILD_DIR)/bin
prefix ?= /usr
bindir ?= $(prefix)/bin
#Collect the files to compile
MAINSRC = $(wildcard ./*.c)
include $(LVGL_DIR)/lvgl/lvgl.mk
include $(LVGL_DIR)/lv_drivers/lv_drivers.mk
# CSRCS +=$(LVGL_DIR)/mouse_cursor_icon.c
OBJEXT ?= .o
AOBJS = $(ASRCS:.S=$(OBJEXT))
COBJS = $(CSRCS:.c=$(OBJEXT))
MAINOBJ = $(MAINSRC:.c=$(OBJEXT))
SRCS = $(ASRCS) $(CSRCS) $(MAINSRC)
OBJS = $(AOBJS) $(COBJS) $(MAINOBJ)
TARGET = $(addprefix $(BUILD_OBJ_DIR)/, $(patsubst ./%, %, $(OBJS)))
## MAINOBJ -> OBJFILES
all: default
$(BUILD_OBJ_DIR)/%.o: %.c
@mkdir -p $(dir $@)
@$(CC) $(CFLAGS) -c $< -o $@
@echo "CC $<"
default: $(TARGET)
@mkdir -p $(dir $(BUILD_BIN_DIR)/)
$(CC) -o $(BUILD_BIN_DIR)/$(BIN) $(TARGET) $(LDFLAGS)
clean:
rm -rf $(BUILD_DIR)
install:
install -d $(DESTDIR)$(bindir)
install $(BUILD_BIN_DIR)/$(BIN) $(DESTDIR)$(bindir)
uninstall:
$(RM) -r $(addprefix $(DESTDIR)$(bindir)/,$(BIN))
main.c
-
注释头文件
// #include "lvgl/demos/lv_demos.h"
// #include "lv_drivers/indev/evdev.h" -
修改屏幕分辨率
#define DISP_BUF_SIZE (240 * 240)
...
disp_drv.hor_res = 240;
disp_drv.ver_res = 240; -
注释下面代码
无外部输入设备,注释下面代码:
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*/不使用官方demo,注释下面代码:
/*Create a Demo*/
lv_demo_widgets();
2.6 编译和运行
上述文件修改完成后,在命令行输入
make
命令编译工程,编译完成后会在
/build/bin
目录下生成一个可执行文件
demo
,编译后的目录结构如下:
project_01/
├── build
│ ├── bin
│ │ └── demo
│ └── obj
│ ├── lv_drivers
│ ├── lvgl
│ └── ...
├── lv_conf.h
├── lv_drivers
├── lv_drv_conf.h
├── lvgl
├── main.c
└── Makefile
我们只需要将
demo
拷贝至开发板,即可在板子上运行程序。后续可以根据需求自行修改
main.c
文件和添加文件,实现自己想要的显示效果。
2.7 官方demo
若需要使用官方提供的例程,按照下面步骤进行操作:
-
复制文件
-
复制根目录下的 lvgl 文件夹中的 lv_demos 目录
-
复制 lv_demos 中的 lv_demo_conf_template.h 重命名为 lv_demo_conf.h
cp -r ~/lvgl/lv_demos ./
cp ~/lvgl/lv_demos/lv_demo_conf_template.h ./lv_demo_conf.h
-
-
修改 lv_demo_conf.h
-
使能
/* clang-format off */
#if 1 /*Set it to "1" to enable the content*/ -
使能 widget demo
/*Show some widget*/
#define LV_USE_DEMO_WIDGETS 1
-
-
修改 lv_conf.h
使能
LV_FONT_MONTSERRAT_12
和LV_FONT_MONTSERRAT_16
#define LV_FONT_MONTSERRAT_12 1
#define LV_FONT_MONTSERRAT_16 1 -
Makefile
include $(LVGL_DIR)/lvgl/lvgl.mk
include $(LVGL_DIR)/lv_drivers/lv_drivers.mk
#Add lv_demo.mk:
include $(LVGL_DIR)/lv_demos/lv_demo.mk -
修改 main.c
-
添加头文件
#include "lv_demos/lv_demo.h"
-
调用接口函数
lv_demo_widgets();
while(1) {
lv_timer_handler();
usleep(5000);
}
-
3.示例程序
3.1 工程目录
烧录好镜像,创建好工程文件后,就可以开始自行修改程序了,这里我们使用 Luckfox Pico Pro/Max 开发板和 Pico-LCD-1.3 显示屏实现界面显示,修改后的工程目录如下:
lvgl_demo/
├── cat.c -------------------- 图片转换后得到的文件
├── galaxy.c ----------------- 图片转换后得到的文件
├── Luckfox.c ---------------- 图片转换后得到的文件
├── saint.c ------------------ 图片转换后得到的文件
├── main.c ------------------- 主程序文件
├── Debug.h ------------------ 调试信息头文件
├── DEV_Config.c ------------- GPIO 控制接口文件
├── DEV_Config.h ------------- GPIO 控制接口头文件
├── sysfs_gpio.c ------------- sysfs GPIO 控制实现文件
├── sysfs_gpio.h ------------- sysfs GPIO 控制头文件
└── ...
3.2 显示自定义图片
-
在线转换
-
转换图片
注意,PNG图片颜色格式选择CF_TRUE_COLOR_ALPHA,JPG图片颜色格式选择CF_TRUE_COLOR,转换完成后将c文件拷贝至工程目录
-
修改main.c
添加声明
LV_IMG_DECLARE(Luckfox);
显示图片
lv_obj_t *scr = lv_disp_get_scr_act(NULL);
lv_obj_t *img = lv_img_create(scr);
lv_show_img(img,Luckfox);
lv_obj_center(img);
3.3 主程序
main.c
#include "lvgl/lvgl.h"
#include "DEV_Config.h"
#include "lv_drivers/display/fbdev.h"
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#define DISP_BUF_SIZE (240 * 240)
/*Image declare*/
LV_IMG_DECLARE(Luckfox);
LV_IMG_DECLARE(cat);
LV_IMG_DECLARE(galaxy);
LV_IMG_DECLARE(saint);
void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p);
/**
* A meter with multiple arcs
*/
void lv_show_img(lv_obj_t * img,const lv_img_dsc_t img_dat){
lv_obj_clean(img);
lv_img_set_src(img, &img_dat);
lv_obj_center(img);
}
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 = 240;
disp_drv.ver_res = 240;
lv_disp_drv_register(&disp_drv);
/*Initialize pin*/
DEV_ModuleInit();
/*Show an image*/
lv_obj_t *scr = lv_disp_get_scr_act(NULL);
lv_obj_t *img = lv_img_create(scr);
lv_show_img(img,Luckfox);
lv_obj_center(img);
/*Create a cursor*/
lv_obj_t *cursor = lv_img_create(scr);
lv_img_set_src(cursor, LV_SYMBOL_GPS);
lv_obj_set_pos(cursor, 70, 120);
int x=70,y=120,move=0;
/*Handle LitlevGL tasks (tickless mode)*/
while(1) {
lv_timer_handler();
usleep(5000);
/*Key*/
if(GET_KEYA == 0){
lv_show_img(img,Luckfox);
}
else if(GET_KEYB == 0){
lv_show_img(img,cat);
}
else if(GET_KEYX == 0){
lv_show_img(img,galaxy);
}
else if(GET_KEYY == 0){
lv_show_img(img,saint);
}
/*Joystick*/
if(GET_KEY_UP == 0){
x += 1;
if(x > 226)x = 226;
move =1;
}
else if(GET_KEY_DOWN == 0){
x -= 1;
if(x < 0)x = 0;
move =1;
}
else if(GET_KEY_LEFT == 0){
y -= 1;
if(y < 0)y = 0;
move =1;
}
else if(GET_KEY_RIGHT == 0){
y += 1;
if(y > 224)y = 224;
move =1;
}
else if(GET_KEY_PRESS == 0){
x = 70;
y = 120;
move =1;
}
if(move == 1){
lv_obj_set_pos(cursor, x, y);
move = 0;
}
}
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;
}
代码解析:
图片声明
依次声明程序中将要使用的图片
/*Image declare*/
LV_IMG_DECLARE(Luckfox);
LV_IMG_DECLARE(cat);
LV_IMG_DECLARE(galaxy);
LV_IMG_DECLARE(saint);
引脚初始化
调用接口,初始化 LCD 的控制引脚
/*Initialize pin*/
DEV_ModuleInit();
显示图片
这段代码的作用是在LVGL图形界面中显示一张图片,并将该图片居中显示在当前活动的屏幕上
/*Show an image*/
lv_obj_t *scr = lv_disp_get_scr_act(NULL);
lv_obj_t *img = lv_img_create(scr);
lv_show_img(img,Luckfox);
lv_obj_center(img);
-
lv_disp_get_scr_act(NULL)
: 获取当前活动的屏幕对象。lv_obj_t *scr
指向该屏幕对象。 -
lv_img_create(scr)
: 在屏幕对象上创建一个图像对象。lv_obj_t *img
指向创建的图像对象。 -
lv_show_img(img, Luckfox)
: 在创建的图像对象上显示名为Luckfox
的图片。 -
lv_obj_center(img)
: 将图像对象居中放置在屏幕上。
当用户分别按下按键A、B、X、Y时,控制 LCD 显示不同的图片
/*Key*/
if(GET_KEYA == 0){
lv_show_img(img,Luckfox);
}
else if(GET_KEYB == 0){
lv_show_img(img,cat);
}
else if(GET_KEYX == 0){
lv_show_img(img,galaxy);
}
else if(GET_KEYY == 0){
lv_show_img(img,saint);
}
显示光标
这段代码的目的是创建一个光标对象,并设置光标的位置和图像源。
/*Create a cursor*/
lv_obj_t *cursor = lv_img_create(scr);
lv_img_set_src(cursor, LV_SYMBOL_GPS);
lv_obj_set_pos(cursor, 70, 120);
int x=70,y=120,move=0;
-
lv_img_create(scr)
: 在屏幕对象上创建一个图像对象,lv_obj_t *cursor
指向创建的图像对。这个图像对象将用作光标。 -
lv_img_set_src(cursor, LV_SYMBOL_GPS)
: 设置光标的图像源为GPS符号。LV_SYMBOL_GPS
是LVGL库中定义的一个GPS符号。 -
lv_obj_set_pos(cursor, 70, 120)
: 设置光标的位置为(70, 120)
。 -
int x=70, y=120, move=0;
: 定义了三个变量,分别表示光标的初始横坐标x
、纵坐标y
,以及移动标志move
。
这段代码实现通过手柄控制光标在屏幕上的位置,当用户操作手柄时x、y值会根据方向进行变化,然后将 move 标志置1,后续在判断 move 标志为1时重新显示光标位置,即可实现光标移动的效果。
/*Joystick*/
if(GET_KEY_UP == 0){
x += 1;
if(x > 226)x = 226;
move =1;
}
else if(GET_KEY_DOWN == 0){
x -= 1;
if(x < 0)x = 0;
move =1;
}
else if(GET_KEY_LEFT == 0){
y -= 1;
if(y < 0)y = 0;
move =1;
}
else if(GET_KEY_RIGHT == 0){
y += 1;
if(y > 224)y = 224;
move =1;
}
else if(GET_KEY_PRESS == 0){
x = 70;
y = 120;
move =1;
}
if(move == 1){
lv_obj_set_pos(cursor, x, y);
move = 0;
}
3.4 实现效果
-
硬件连接
-
显示效果