【LVGL学习笔记】(四)PlatformIO + LVGL8.3配置

发布时间 2023-11-14 00:15:36作者: MaxBruce

原文:https://blog.csdn.net/weixin_45728705/article/details/128383151

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 0


class 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");
}