LVGL全程LittleVGL,是一个轻量化的,开源的,用于嵌入式GUI设计的图形库。并且配合LVGL模拟器,可以在电脑对界面进行编辑显示,测试通过后再移植进嵌入式设备中,实现高效的项目开发。
LVGL中文教程手册:极客笔记之LVGL教程
配置信息
芯片:ESP32-PICO-D4
PlatformIO版本:6.1.5
显示屏型号:ST7789V 240x240
一. platformIO生成项目文件
首先生成一个新项目,可以取消最后一行的勾选,自定义项目存储位置。
项目架构
Project
├─ .pio
│ ├─ build # 编译生成的文件
│ ├─ libdeps # 依赖的开源库文件
│ │ ├─ integrity.dat # 库配置文件,这个文件自动生成,不能手动修改
├─ .vscode # vscode配置文件
├─ lib # 私有库文件,里面的文件会被编译为静态库链接到项目中
├─ include # 头文件放置文件夹
├─ src # 源文件放置文件夹
├─ test # 测试文件放置文件夹
├─ .gitignore
└─ platformio.ini # 项目参数配置文件,libdeps中的库文件就在这里进行配置
修改platformio.ini文件
添加烧录串口号和串口监视速率,这里的串口速率只是配置platformio monitor接收数据的速率,并没有配置芯片的串口发送速率。
monitor_speed = 115200
upload_port = COM11
1
2
添加开源库
在下方的界面中搜索相应的库文件,并选择想要的版本添加到文件中。
注意:各个项目的库文件虽然都可以在installed中找到,但是不同项目的库文件不是共享的。也就是说,即使两个项目用了同一个版本的同一个库,installed中会有两个库文件,分别存储在两个项目的libdeps中。
选择添加之后,platformio.ini文件中就会自动生成依赖库代码。
二. 修改配置文件
1. lvgl
复制lv_conf_template.h到同一路径下,并改名为lvgl_conf.h
内容解注释
启用自定义时钟
注意:没有一步的话会导致屏幕停留在第一帧的界面
2.TFT_eSPI
修改User_Setup_Select.h文件,选择屏幕的型号。
这里只能解注释一个 #include ,所以需要把 #include<User_Setup.h> 给注释掉。
修改Setup24_ST7789.h文件,这里需要根据自己屏幕和芯片的连接引脚来确定引脚号。
三. 创建lvgl和屏幕的连接
可以参考lvgl/examples/porting/lv_port_disp_template.c文件,但是里面没有添加屏幕初始化的内容,所以需要结合TFT的demo来编写代码,以下是我用的源码。
注意:需要用cpp文件来编写,因为TFT_eSPI是基于cpp的。
/**
* @file display.cpp
*
*//*********************
* INCLUDES
*********************/
#include "display.h"
#include <stdbool.h>
#include <TFT_eSPI.h>/*********************
* DEFINES
*********************/
#ifndef MY_DISP_HOR_RES
#define MY_DISP_HOR_RES (240)
#endif#ifndef MY_DISP_VER_RES
#define MY_DISP_VER_RES (240)
#endif/**********************
* STATIC VARIABLES
**********************/
TFT_eSPI tft = TFT_eSPI();/**********************
* STATIC PROTOTYPES
**********************/
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1); tft.startWrite();
tft.setAddrWindow(area->x1, area->y1, w, h);
tft.pushColors(&color_p->full, w * h, true);
tft.endWrite(); lv_disp_flush_ready(disp_drv);
}/**********************
* GLOBAL FUNCTIONS
**********************/void Display::init(void)
{
/* Set Backlight mode */
ledcSetup(LCD_BL_PWM_CHANNEL, 5000, 8);
ledcAttachPin(LCD_BL_PIN, LCD_BL_PWM_CHANNEL); /* Init lvgl */
lv_init(); /* Init display device */
tft.begin();
tft.setRotation(4); /* mirror */ /*-----------------------------
* Create a buffer for drawing
*----------------------------*/
static lv_disp_draw_buf_t draw_buf_dsc_1;
static lv_color_t buf_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/
lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/ /*-----------------------------------
* Register the display in LVGL
*----------------------------------*/
static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/ /*Set up the functions to access to your display*/
/*Set the resolution of the display*/
disp_drv.hor_res = MY_DISP_HOR_RES;
disp_drv.ver_res = MY_DISP_VER_RES; /*Used to copy the buffer's content to the display*/
disp_drv.flush_cb = disp_flush; /*Set a display buffer*/
disp_drv.draw_buf = &draw_buf_dsc_1; /*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
}void Display::routine(void)
{
lv_task_handler();
}void Display::setBackLight(float duty)
{
duty = constrain(duty, 0, 1);
duty = 1 - duty;
ledcWrite(LCD_BL_PWM_CHANNEL, (int)(duty * 255));
}
1
#ifndef DISPLAY_H
#define DISPLAY_H#include <lvgl.h>
#define LCD_BL_PIN 5
#define LCD_BL_PWM_CHANNEL 0class Display
{
private:public:
void init();
void routine();
void setBackLight(float);
};#endif
四. 设计UI
这里使用的是官方提供的demo,lvgl/examples 中有很多官方提供的demo可以进行参考。
void lv_demo(void)
{
lv_obj_t * obj = lv_obj_create(lv_scr_act());
lv_obj_set_style_bg_color(obj, lv_palette_main(LV_PALETTE_RED), 0);
lv_obj_set_style_radius(obj, LV_RADIUS_CIRCLE, 0); lv_obj_align(obj, LV_ALIGN_LEFT_MID, 10, 0);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, obj);
lv_anim_set_values(&a, 10, 50);
lv_anim_set_time(&a, 1000);
lv_anim_set_playback_delay(&a, 100);
lv_anim_set_playback_time(&a, 300);
lv_anim_set_repeat_delay(&a, 500);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_path_cb(&a, lv_anim_path_ease_in_out); lv_anim_set_exec_cb(&a, anim_size_cb);
lv_anim_start(&a);
lv_anim_set_exec_cb(&a, anim_x_cb);
lv_anim_set_values(&a, 10, 240);
lv_anim_start(&a);
}
五. 修改main.cpp
/**
* @file main.cpp
* @author jozenlee
* @brief
* @version 0.1
* @date 2022-12-15
*
* @copyright Copyright (c) 2022
*
*/#include <Arduino.h>
#include "lv_demo.h"#include "display.h"
Display screen;// lv_group_t * group;
void setup() {
/* Init Serial */
Serial.begin(115200);
/* Init lvgl display port */
screen.init();
screen.setBackLight(0.2); /* Inflate GUI objects */
lv_demo();
}void loop() {
// run this as often as possible
screen.routine(); /* Serial test */
Serial.println("hello");
}