跳到主要内容

LVGL使用指南

在本篇文章中,我们将详细介绍 Framebuffer(FB)设备和 LittlevGL(LVGL)图形用户界面库的基本概念。通过使用 Luckfox Pico Pro/Max 开发板和 Pico-LCD-1.3 显示屏,我们将演示如何配置 FB 设备,利用 LVGL 库创建应用程序,最后在 LCD 实现界面显示。

快速使用

  1. 硬件准备

    • Luckfox Pico Pro/Max *1
    • Pico-LCD-1.3 *1
  2. 下载压缩包

    • 下载链接:LVGL.zip

    • 压缩包内容:

      LVGL/
      ├── image ------------------------------- 镜像文件
      ├── lvgl_demo --------------------------- 工程目录
      ├── demo -------------------------------- 可执行文件
      └── rv1106g-luckfox-pico-pro-max.dts ---- 设备树文件
  3. 烧录镜像

  4. 运行demo

    将压缩包中的 demo 拷贝至开发板,运行程序:

    chmod +x demo
    ./demo
  5. 修改程序

    • 修改Makefile

      将 lvgl_demo 拷贝至虚拟机,将 Makefile 中 <SDK Directory> 修改为自己的 SDK 路径,如 /home/luckfox/luckfox-pico/

      CC = <SDK Directory>/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf-gcc
    • 编译工程

      命令行执行 make 指令编译工程

      make
    • 运行程序

      编译完成后会在 /build/bin 目录下生成一个可执行文件 demo ,将该文件拷贝至开发板即可直接运行

1.基本概念

Framebuffer(FB)设备

Framebuffer(FB)设备是一种用于图形显示的硬件设备,它提供了一个帧缓冲区,用于绘制图形并直接在屏幕上显示。FB设备的使用通常涉及配置显示分辨率、颜色深度等参数,以及将绘制的图形数据传输到显示设备。

LittlevGL(LVGL)

LVGL(LittlevGL)是一款轻量级、开源的嵌入式图形库,专注于提供灵活易用的图形用户界面(GUI)解决方案。通过LVGL,开发者可以实现丰富的图形界面设计,包括按钮、滑块、文本框等各种常用的GUI控件,以及动画和触摸交互等功能。作为一款开源库,LVGL 广泛应用于各种嵌入式系统,并以其轻量级的特性受到开发者的喜爱。LVGL 支持多种显示设备,其中就包括 Framebuffer,使得开发者可以在嵌入式系统上轻松创建漂亮的用户界面。

2.引脚配置

确保所有与 LCD 通讯的引脚功能正常是驱动 LCD 的基本要求。因此,我们需要在备树文件中配置引脚功能。在此之前,我们需要确定 Pico-LCD-1.3 连接到 Luckfox Pico Pro/Max 的引脚。下面我们以 Pico-LCD-1.3 的摇杆向上引脚 GP2 为例说明,它对应到 Luckfox Pico Pro/Max 上的引脚号为4号,其 GPIO 引脚名称为 GPIO1_C7_d,引脚编号为55。

2.1 接口图

Pico-LCD-1.3
image

Luckfox Pico Pro/Max

2.2 修改设备树

可以看到 GPIO1_C7_d 的默认功能是 PWM 功能,在程序中,我们希望通过读取该引脚电平判断按键状态,所以我们需要将该引脚配置为普通IO。

  1. 设备树文件的路径

    <SDK目录>/sysdrv/source/kernel/arch/arm/boot/dts/rv1106g-luckfox-pico-pro-max.dts
  2. 定义GPIO

    定义一个 GPIO,通常需要添加两段代码。注意按键为低电平有效,需要上拉。以下是一个示例,展示如何在设备树中添加 GPIO1_C7_d 引脚的定义。

    需要添加的代码片段如下:

    /{
    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>;
    };
    };
    };
  3. 注释引脚的外设功能

    注释引脚外设功能可以通过在设备树中将相应的外设节点注释来实现,以下是一个示例,展示如何在设备树中禁用 GPIO1_C7_d 引脚的 PWM 功能。

  4. 依次配置其余引脚

    继续完善LCD_BL、LCD_DC、LCD_RES、按键等引脚配置。

3.配置FB设备

3.1 修改内容

项目文件路径
Kernel 设备树<SDK目录>/sysdrv/source/kernel/arch/arm/boot/dts/rv1106g-luckfox-pico-pro-max.dts
FB 设备支持<SDK目录>/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig

3.2 Kernel 设备树

  1. 文件路径

    <SDK目录>/sysdrv/source/kernel/arch/arm/boot/dts/rv1106g-luckfox-pico-pro-max.dts
  2. 设备树文件修改

    注意先将原 spi0 配置注释掉,再添加以下配置:

    &spi0 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&spi0m0_cs0 &spi0m0_pins>;

    st7789v@0{
    status = "okay";
    compatible = "sitronix,st7789v";
    reg = <0>;
    spi-max-frequency = <20000000>;
    fps = <30>;
    buswidth = <8>;
    debug = <0x7>;
    led-gpios = <&gpio2 RK_PB0 GPIO_ACTIVE_LOW>;//BL
    dc = <&gpio2 RK_PB1 GPIO_ACTIVE_HIGH>; //DC
    reset = <&gpio1 RK_PC3 GPIO_ACTIVE_LOW>; //RES
    };
    };

    &pinctrl {
    spi0 {
    /omit-if-no-ref/
    spi0m0_pins: spi0m0-pins {
    rockchip,pins =
    /* spi0_clk_m0 */
    <1 RK_PC1 4 &pcfg_pull_none>,
    /* spie_miso_m0 */
    // <1 RK_PC3 6 &pcfg_pull_none>,
    /* spi_mosi_m0 */
    <1 RK_PC2 6 &pcfg_pull_none>;
    };
    };
    };

3.3 FB 设备支持

  1. 文件路径

    <SDK目录>/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig
  2. 编译驱动

    添加以下内容:

    CONFIG_SPI_MASTER=y
    CONFIG_FB=y

3.4 FB 设备验证

  1. 查看fb驱动是否正常加载

    完成以上修改后,重新编译并烧录镜像。上电后可以执行dmesg查看fb驱动是否正常加载:

    # dmesg | grep fb_
    [ 0.432873] fb_st7789v spi0.0: fbtft_write_reg8_bus8: e1 d0 05 0a 09 08 05 2e 43 45 0f 16 16 2b 33
    [ 0.432898] fb_st7789v spi0.0: fbtft_write_spi(len=1): e1
    [ 0.432972] fb_st7789v spi0.0: fbtft_write_spi(len=14): d0 05 0a 09 08 05 2e 43 45 0f 16 16 2b 33
    [ 0.433078] fb_st7789v spi0.0: fbtft_register_backlight(): led pin not set, exiting.
    [ 0.433515] graphics fb0: fb_st7789v frame buffer, 240x320, 150 KiB video memory, 4 KiB buffer memory, fps=30, spi0.0 at 20 MHz
  2. 测试花屏:

    cat /dev/urandom > /dev/fb0
  3. 测试清屏:

    cat /dev/zero > /dev/fb0

    如果花屏、清屏功能正常,则说明驱动可以正常加载。

4.移植LVGL

4.1 所需资源

资源名称仓库地址描述
lvglhttps://github.com/lvgl/lvgl.gitLVGL图形界面控件的源码以及少量例程
lv_drivershttps://github.com/lvgl/lv_drivers.git驱动LVGL图形界面的驱动接口源代码
lv_demoshttps://github.com/lvgl/lv_demos.gitLVGL的例程
lv_port_linux_frame_bufferhttps://github.com/lvgl/lv_port_linux_frame_buffer.git适配有Framebuffer的linux系统的接口

4.2 拉取资源

在根目录下创建一个文件夹存放官方源码:

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 lvgl_project
luckfox@luckfox:~$ cd lvgl_project/
luckfox@luckfox:~/lvgl_project$ mkdir project_01
luckfox@luckfox:~/lvgl_project$ cd project_01/

4.3 复制文件

  • 复制根目录下的 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 1227 19:14 lv_conf.h
drwxrwxr-x 12 luckfox luckfox 4096 1227 19:14 lv_drivers
-rw-rw-r-- 1 luckfox luckfox 15184 1227 19:14 lv_drv_conf.h
drwxrwxr-x 12 luckfox luckfox 4096 1227 19:14 lvgl
-rw-rw-r-- 1 luckfox luckfox 2350 1227 19:14 main.c
-rw-rw-r-- 1 luckfox luckfox 2321 1227 19:14 Makefile

4.4 修改文件

lv_conf.h

  1. 使能

    将一开始的 #if 0 改成 #if 1

    /* clang-format off */
    #if 1 /*Set it to "1" to enable content*/
  2. 分配显存

    使能 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
  3. 刷新时间

    将原本的 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]*/
  4. 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

  1. 使能

    将一开始的 #if 0 改成 #if 1

    /* clang-format off */
    #if 1 /*Set it to "1" to enable the content*/
  2. 支持设备

    使能 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

  1. 注释头文件

    // #include "lvgl/demos/lv_demos.h"
    // #include "lv_drivers/indev/evdev.h"
  2. 修改屏幕分辨率

    #define DISP_BUF_SIZE (240 * 240)
    ...
    disp_drv.hor_res = 240;
    disp_drv.ver_res = 240;
  3. 注释下面代码

    无外部输入设备,注释下面代码:

    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();

4.5 编译和运行

上述文件修改完成后,在命令行输入 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 文件和添加文件,实现自己想要的显示效果。

4.6 官方demo

若需要使用官方提供的例程,按照下面步骤进行操作:

  1. 复制文件

    • 复制根目录下的 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
  2. 修改 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
  3. 修改 lv_conf.h

    使能 LV_FONT_MONTSERRAT_12LV_FONT_MONTSERRAT_16

    #define LV_FONT_MONTSERRAT_12 1
    #define LV_FONT_MONTSERRAT_16 1
  4. 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
  5. 修改 main.c

    • 添加头文件

      #include "lv_demos/lv_demo.h"
    • 调用接口函数

      lv_demo_widgets();

      while(1) {
      lv_timer_handler();
      usleep(5000);
      }

5.示例程序

5.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 控制头文件
└── ...

5.2 显示自定义图片

  1. 在线转换

    Online Image Converter

  2. 转换图片

    注意,PNG图片颜色格式选择CF_TRUE_COLOR_ALPHA,JPG图片颜色格式选择CF_TRUE_COLOR,转换完成后将c文件拷贝至工程目录

  3. 修改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);

5.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;
}

5.4 实现效果

  1. 硬件连接
  2. 显示效果