环境:
硬件:ESP32
LCD : ST7796 3.5寸 480*320 屏
电容触摸 IC: GT911
IDE: Visual Studio Code with Platoform IO extension
LVGL 版本:3.0
移植前准备
移植前已经使用 eSPI 驱动起了 ST7796 屏,别且实现了触摸驱动。
LVGL移植步骤如下:
下载 LVGL 代码
下载 LVGL 文件,放置到 工程的 .lib 库中:
编辑配置文件
把 LVGL 源文件根目录下的 lv_conf_template.h 重命名为 lv_conf.h
首先把第10行左右的宏定义打开:
#if 1 /*Set it to "1" to enable content*/
更改 main.cpp 文件
主文件中导入 LVGL 库函数:
#include "../lib/lvgl/src/lvgl.h" // LVGL 库
添加一些全局变量,定义 UI 元素等:
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];
lv_disp_drv_t disp_drv;
lv_indev_drv_t indev_drv;
lv_obj_t *btn1;
lv_obj_t *btn2;
lv_obj_t *screenMain;
lv_obj_t *label;
两个函数
需要定义两个函数给 LVGL 使用,一个是 TFT 屏的描点函数,一个是触摸屏的获取触摸位置的函数。仅需提描点函数给 LVGL, 它就可以绘制出各种 UI 元素了。这个描点函数就是 TFT 驱动和 LVGL 之间的桥梁。
描点函数如下:
// 描点函数,给 LVGL 使用
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);
}
提供给 LVGL 的获取触摸位置的函数如下:
// 触摸函数,给 LVGL 使用
bool my_input_read(lv_indev_drv_t * drv, lv_indev_data_t*data)
{
uint8_t touches = ts.touched(GT911_MODE_POLLING);
if(touches == 0) return false;
GTPoint p = ts.getPoint(0);
//Serial.printf("#%d %d,%d s:%d\n", p.trackId, p.x, p.y, p.area);
data->state = LV_INDEV_STATE_PR;
data->point.x = p.x;
data->point.y = p.y;
return true; /*No buffering now so no more data read*/
}
定义 UI 事件处理函数
// 触摸函数,给 LVGL 使用
bool my_input_read(lv_indev_drv_t * drv, lv_indev_data_t*data)
{
uint8_t touches = ts.touched(GT911_MODE_POLLING);
if(touches == 0) return false;
GTPoint p = ts.getPoint(0);
//Serial.printf("#%d %d,%d s:%d\n", p.trackId, p.x, p.y, p.area);
data->state = LV_INDEV_STATE_PR;
data->point.x = p.x;
data->point.y = p.y;
return true; /*No buffering now so no more data read*/
}
完整的 main.cpp 代码如下:
#include <Arduino.h>
#include "../lib/TFT_eSPI/TFT_eSPI.h" // eSPI 库,实现 TFT 液晶屏驱动
#include "Wire.h" // I2C 库, GT911 电容触摸芯片接口
#include <../lib/GT911/GT911.h> // GT911 电容触摸屏驱动
#include "../lib/lvgl/src/lvgl.h" // LVGL 库
#define TOUCH_INT_PIN 35
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
GT911 ts = GT911();
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];
lv_disp_drv_t disp_drv;
lv_indev_drv_t indev_drv;
lv_obj_t *btn1;
lv_obj_t *btn2;
lv_obj_t *screenMain;
lv_obj_t *label;
// 描点函数,给 LVGL 使用
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);
}
// 触摸函数,给 LVGL 使用
bool my_input_read(lv_indev_drv_t * drv, lv_indev_data_t*data)
{
uint8_t touches = ts.touched(GT911_MODE_POLLING);
if(touches == 0) return false;
GTPoint p = ts.getPoint(0);
//Serial.printf("#%d %d,%d s:%d\n", p.trackId, p.x, p.y, p.area);
data->state = LV_INDEV_STATE_PR;
data->point.x = p.x;
data->point.y = p.y;
return true; /*No buffering now so no more data read*/
}
// UI 元素事件处理函数
static void event_handler_btn(lv_obj_t * obj, lv_event_t event){
if(event == LV_EVENT_CLICKED) {
if (obj == btn1)
lv_label_set_text(label, "Start");
else if (obj == btn2){
lv_label_set_text(label, "Stop");
}
}
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("eSPI LVGL Demo started");
tft.init();
tft.setRotation(0);
Wire.begin(15, 14);
pinMode(TOUCH_INT_PIN, INPUT);
ts.begin();
lv_init();
lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);
/*Initialize the display*/
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = 320;
disp_drv.ver_res = 480;
disp_drv.flush_cb = my_disp_flush;
disp_drv.buffer = &disp_buf;
lv_disp_drv_register(&disp_drv);
/*Initialize the input device driver*/
lv_indev_drv_init(&indev_drv); /*Descriptor of a input device driver*/
indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device*/
indev_drv.read_cb = my_input_read; /*Set your driver function*/
lv_indev_drv_register(&indev_drv); /*Finally register the driver*/
/*Create screen objects*/
screenMain = lv_obj_create(NULL, NULL);
label = lv_label_create(screenMain, NULL);
lv_label_set_long_mode(label, LV_LABEL_LONG_BREAK);
lv_label_set_text(label, "Press a button");
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
lv_obj_set_size(label, 240, 40);
lv_obj_set_pos(label, 0, 15);
btn1 = lv_btn_create(screenMain, NULL);
lv_obj_set_event_cb(btn1, event_handler_btn);
lv_obj_set_width(btn1, 70);
lv_obj_set_height(btn1, 32);
lv_obj_set_pos(btn1, 32, 100);
lv_obj_t * label1 = lv_label_create(btn1, NULL);
lv_label_set_text(label1, "Start");
btn2 = lv_btn_create(screenMain, NULL);
lv_obj_set_event_cb(btn2, event_handler_btn);
lv_obj_set_width(btn2, 70);
lv_obj_set_height(btn2, 32);
lv_obj_set_pos(btn2, 142, 100);
lv_obj_t * label2 = lv_label_create(btn2, NULL);
lv_label_set_text(label2, "Stop");
lv_scr_load(screenMain);
}
void loop() {
lv_task_handler();
delay(1);
}
加作者微信:jiyuyun18(积雨云), 交流电子技术
留言:CSDN入群,加入电子技术讨论群
留言:ESP32, 加入 ESP32 技术讨论群
留言:CSDN资料,领取免费电子技术学习资料
版权声明:本文为feiduoxuetang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。