添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
跳到主要内容

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

快速使用

  1. 下载压缩包,压缩包目录:

    LVGL/
    ├── image ------------------------------- 镜像文件
    ├── lvgl_demo --------------------------- 工程目录
    ├── demo -------------------------------- 可执行文件
    └── rv1103g-luckfox-pico-plus.dts ---- 设备树文件
    └── rv1103g-luckfox-pico-mini-a.dts/rv1103g-luckfox-pico-mini-b.dts ---- 设备树文件
  2. 将压缩包中的 demo 通过 adb 或者 scp 至开发板,运行程序:

    chmod +x demo
    ./demo
  3. 如果自己修改编译程序,可以将 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环境部署》部分。

  1. 进入内核目录。

    cd /SDK目录/sysdrv/source/kernel
    cp ./arch/arm/configs/luckfox_rv1106_linux_defconfig .config
    make ARCH=arm menuconfig
  2. 在内核中依次开启FB相关的驱动

    CONFIG_VT_CONSOLE=y
    CONFIG_FRAMEBUFFER_CONSOLE=y
    CONFIG_FONTS=y
  3. 保存配置

    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 设备树编写

  1. 在默认的设备树中, 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>;
    };
    };
    };
    • 完整设备请下载网盘的设备树文件,这里仅做部分展示
  2. 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
    };
    };
  3. 修改好设备树编译镜像,测试花屏和清屏

    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 拉取资源

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

    luckfox@luckfox:~$ mkdir lvgl
    luckfox@luckfox:~$ cd lvgl
  2. 拉取资源:

    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
  3. 成功拉取后,在根目录下创建一个工程目录,并创建一个工程:

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

2.5 修改文件

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

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

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

  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_12 LV_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);
      }

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 显示自定义图片

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

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 实现效果

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