ESP32使用LVGL GUI库
Published:
ESP32使用LVGL GUI库,在单片机设备上使用现代且华丽的GUI。
本文基于ESP32使用Arduino框架驱动树莓派3.5寸LCD屏幕,首先确保TFT_eSPI能够正常驱动3.5寸LCD屏幕工作。如果没有设置好驱动,请首先参考此处引用文章进行LCD屏幕的设置。
LVGL是一个开源图形库,提供创建嵌入式GUI所需的一切,具有易于使用的图形元素、优美的视觉效果和较低的内存占用。本文最终的效果如图。
1.在arduino ide中安装lvgl和lv_examples库
此处使用7.11.0版本,8.x版本目前正在开发阶段。
2.配置LVGL
在arduino ide中,项目 -> 显示项目文件夹,在文件管理器中打开当前项目文件夹,然后向上一级目录,找到libraries
文件夹并进入,进入lvgl
文件夹,复制lv_conf_template.h
文件,向上一级目录,粘贴并重命名为lv_conf.h
。此时lv_conf.h
在libraries
文件夹中。
修改如下内容:
第10行,将其设为1。
#if 1 /*Set it to "1" to enable content*/
第23行,输入自己显示器的尺寸,笔者的尺寸大小是480x320
#define LV_HOR_RES_MAX (480)
#define LV_VER_RES_MAX (320)
第32行,设置自己显示器的颜色深度,笔者对自己显示器的颜色深度也不是很了解,故使用的默认值16。
第303行,将LV_TICK_CUSTOM设为1
#define LV_TICK_CUSTOM 1
第384行,将列出的字体全部设为1,在lv_examples中,用到了很多不同的字体大小。
#define LV_FONT_MONTSERRAT_8 1
#define LV_FONT_MONTSERRAT_10 1
#define LV_FONT_MONTSERRAT_12 1
#define LV_FONT_MONTSERRAT_14 1
#define LV_FONT_MONTSERRAT_16 1
#define LV_FONT_MONTSERRAT_18 1
#define LV_FONT_MONTSERRAT_20 1
#define LV_FONT_MONTSERRAT_22 1
#define LV_FONT_MONTSERRAT_24 1
#define LV_FONT_MONTSERRAT_26 1
#define LV_FONT_MONTSERRAT_28 1
#define LV_FONT_MONTSERRAT_30 1
#define LV_FONT_MONTSERRAT_32 1
#define LV_FONT_MONTSERRAT_34 1
#define LV_FONT_MONTSERRAT_36 1
#define LV_FONT_MONTSERRAT_38 1
#define LV_FONT_MONTSERRAT_40 1
#define LV_FONT_MONTSERRAT_42 1
#define LV_FONT_MONTSERRAT_44 1
#define LV_FONT_MONTSERRAT_46 1
#define LV_FONT_MONTSERRAT_48 1
3.配置lv_examples
lv_examples提供了很多的lvgl例程。
进入步骤2
中描述的libraries
文件夹,进入lv_examples
文件夹,复制lv_ex_conf_template.h
,向上一级目录,粘贴并重命名为lv_ex_conf.h
。此时lv_ex_conf.h
与lv_conf.h
在同一文件夹中。
打开lv_ex_conf.h
并修改:
第10行,将其设为1
#if 1 /*Set it to "1" to enable the content*/
下面的内容使用什么就将其设为1,在这里我们开启benchmark和music例子。benchmark用来测试单片机的性能,music是一个音乐播放器。
第40行,
#define LV_USE_DEMO_BENCHMARK 1
第47行,
#define LV_USE_DEMO_MUSIC 1
4.编写主文件
打开main.ino
文件,文件内容如下:
#include <Arduino.h>
//#include "./includes/oled.h"
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <lv_examples.h>
// extern Adafruit_SH1106G display;
TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];
#if USE_LV_LOG != 0
/* Serial debugging */
void my_print(lv_log_level_t level, const char *file, uint32_t line, const char *dsc)
{
Serial.printf("%s@%d->%s\r\n", file, line, dsc);
Serial.flush();
}
#endif
/* Display flushing */
void my_disp_flush(lv_disp_drv_t *disp, 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);
}
/*Read the touchpad*/
bool my_touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
{
uint16_t touchX, touchY;
bool touched = tft.getTouch(&touchX, &touchY, 600);
if (!touched)
{
data->state = LV_INDEV_STATE_REL;
}
else
{
data->state = LV_INDEV_STATE_PR;
/*Set the coordinates*/
data->point.x = touchX;
data->point.y = touchY;
Serial.print("Data x");
Serial.println(touchX);
Serial.print("Data y");
Serial.println(touchY);
}
return false; /*Return `false` because we are not buffering and no more data to read*/
}
void setup()
{
// put your setup code here, to run once:
// Serial.begin(9600);
// //testdrawcircle();
// display.begin(i2c_Address,true);
// testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH);
Serial.begin(115200); /* prepare for possible serial debug */
lv_init();
#if USE_LV_LOG != 0
lv_log_register_print_cb(my_print); /* register print function for debugging */
#endif
tft.begin(); /* TFT init */
tft.setRotation(1); /* Landscape orientation */
uint16_t calData[5] = {275, 3620, 264, 3532, 1};
tft.setTouch(calData);
lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);
/*Initialize the display*/
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = 480;
disp_drv.ver_res = 320;
disp_drv.flush_cb = my_disp_flush;
disp_drv.buffer = &disp_buf;
lv_disp_drv_register(&disp_drv);
/*Initialize the (dummy) input device driver*/
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = my_touchpad_read;
lv_indev_drv_register(&indev_drv);
// lv_demo_benchmark();
lv_demo_music();
}
void loop()
{
// put your main code here, to run repeatedly:
// testdrawcircle();
// Serial.println("hello");
// delay(1000);
// Serial.println(getCpuFrequencyMhz());
// delay(1000);
lv_task_handler();
delay(5);
}
其中,部分注释掉的内容是上一篇文章中用来测试LCD驱动的文件。
其中,第105、106行分别是benchmark和music的测试代码。
最终的显示效果如文章开头所示,在benchmark的测试结果中,笔者的esp32芯片的性能结果为
FPS:10 Slow but common cases.