大数跨境

LVGL 8.3.6 版本移植记录

LVGL 8.3.6 版本移植记录 飞多学堂
2023-04-28
2
导读:LVGL 8.3.6 版本移植记录

环境

单片机:ESP32

ESP32 框架:Arduino

LCD : ST7796 3.5寸 480*320 屏

电容触摸 IC: GT911

IDE: Visual Studio Code with Platoform IO extension

LVGL 版本:8.3.6

本文的移植方法同样适应于 STM32 等其他单片机或者 IDF 等其他 ESP32 框架。

移植前准备

移植前需要先搞好了液晶屏和触摸屏驱动。液晶屏驱动仅需实现一个描点函数就可以了。

移植前我已经使用 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/lvgl.h"           // LVGL 库

添加一些全局变量,定义 UI 元素等:

lv_obj_t *screenMain;
lv_obj_t *btn1;
lv_obj_t *btn2;
lv_obj_t *label;

/*Change to your screen resolution*/
static const uint16_t screenWidth  = 320;
static const uint16_t screenHeight = 480;

static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[ screenWidth * 10 ];

如果使用 Arduino 框架函数编程,需要把下面的86行左右的宏也打开:

/*Use a custom tick source that tells the elapsed time in milliseconds.
*It removes the need to manually update the tick with `lv_tick_inc()`)*/
#define LV_TICK_CUSTOM 1

两个函数

需要定义两个函数给 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( ( uint16_t * )&color_p->full, w * h, true );
   tft.endWrite();

   lv_disp_flush_ready( disp );
}

提供给 LVGL 的获取触摸位置的函数如下:

/ 触摸函数,给 LVGL 使用
void 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;

 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; /*No buffering now so no more data read*/
}

添加 UI 事件处理函数

有了上述两个函数,LVGL 界面就可以跑起来了,但如果想要在点击按钮时有所反应,需要定义 UI 事件处理函数:

// UI 元素事件处理函数
static void event_handler_btn(lv_event_t * e)
{
   lv_event_code_t code = lv_event_get_code(e);

   if(code == LV_EVENT_CLICKED) {
       LV_LOG_USER("Clicked");
       if (e->target == btn1)
         lv_label_set_text(label, "Start");
       else if (e->target == btn2)
         lv_label_set_text(label, "Stop");
  }
   else if(code == LV_EVENT_VALUE_CHANGED) {
       LV_LOG_USER("Toggled");
  }
}

完整 main.cpp 代码

完整的 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/lvgl.h"           // LVGL 库

#define TOUCH_INT_PIN 35

TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
GT911 ts = GT911();

lv_obj_t *screenMain;
lv_obj_t *btn1;
lv_obj_t *btn2;
lv_obj_t *label;

/*Change to your screen resolution*/
static const uint16_t screenWidth  = 320;
static const uint16_t screenHeight = 480;

static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[ screenWidth * 10 ];

// 描点函数,给 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( ( uint16_t * )&color_p->full, w * h, true );
   tft.endWrite();

   lv_disp_flush_ready( disp );
}

// 触摸函数,给 LVGL 使用
void 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;

 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; /*No buffering now so no more data read*/
}

// UI 元素事件处理函数
static void event_handler_btn(lv_event_t * e)
{
   lv_event_code_t code = lv_event_get_code(e);

   if(code == LV_EVENT_CLICKED) {
       LV_LOG_USER("Clicked");
       if (e->target == btn1)
         lv_label_set_text(label, "Start");
       else if (e->target == btn2)
         lv_label_set_text(label, "Stop");
  }
   else if(code == LV_EVENT_VALUE_CHANGED) {
       LV_LOG_USER("Toggled");
  }
}

void setup()
{
 Serial.begin(115200);

 String LVGL_Arduino = "Hello Arduino! ";
 LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();

 Serial.println( LVGL_Arduino );
 Serial.println( "I am LVGL_Arduino" );

 tft.init();
 tft.setRotation( 0 ); /* Landscape orientation, flipped */

 Wire.begin(15, 14);
 pinMode(TOUCH_INT_PIN, INPUT);
 ts.begin();

 lv_init();
 lv_disp_draw_buf_init( &draw_buf, buf, NULL, screenWidth * 10 );

 /*Initialize the display*/
 static lv_disp_drv_t disp_drv;
 lv_disp_drv_init(&disp_drv);
 /*Change the following line to your display resolution*/
 disp_drv.hor_res = screenWidth;
 disp_drv.ver_res = screenHeight;
 disp_drv.flush_cb = my_disp_flush;
 disp_drv.draw_buf = &draw_buf;
 lv_disp_drv_register(&disp_drv);

 /*Initialize the input device driver*/
 static lv_indev_drv_t indev_drv;
 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_scr_act();

 label = lv_label_create(screenMain);
 lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
 lv_label_set_text(label, "Press a button");
 lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 30);

 btn1 = lv_btn_create(screenMain);
 lv_obj_add_event_cb(btn1, event_handler_btn, LV_EVENT_ALL, NULL);
 lv_obj_align(btn1, LV_ALIGN_CENTER, -60, 0);

 lv_obj_t * label1 = lv_label_create(btn1);
 lv_label_set_text(label1, "Start");

 btn2 = lv_btn_create(screenMain);
 lv_obj_add_event_cb(btn2, event_handler_btn, LV_EVENT_ALL, NULL);
 lv_obj_align(btn2, LV_ALIGN_CENTER, 60, 0);

 lv_obj_t * label2 = lv_label_create(btn2);
 lv_label_set_text(label2, "Stop");

 lv_scr_load(screenMain);
}

void loop()
{
 lv_timer_handler(); /* let the GUI do its work */
 delay( 5 );
}

加作者微信:jiyuyun18(积雨云), 交流电子技术

留言:CSDN入群,加入电子技术讨论群

留言:ESP32,     加入 ESP32 技术讨论群

留言:CSDN资料,领取免费电子技术学习资料


【声明】内容源于网络
0
0
飞多学堂
1234
内容 157
粉丝 0
飞多学堂 1234
总阅读62
粉丝0
内容157