回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

【花雕学编程】Arduino动手做(238)---ESP32 CYD液晶2.8寸开发板尝试LVGL(轻量级和多功能图形库) 简单

头像 驴友花雕 2024.11.09 11 0

0.jpg

 

ESP32-CYD(2432S028)液晶2.8寸屏开发板使用ESP32-WROOM-32模块作为主控,主控是一款双核MCU,集成了Wi-Fi和蓝牙功能,主频可达240MHz,具有520KB的SRAM、448KB的ROM,闪存容量为4MB+4MB,显示分辨率为240x320,采用电阻式触控式屏幕。该模块包括LCD显示器、背光控制电路、触控式屏幕控制电路、扬声器驱动电路、光敏电路和RGB LED控制电路。支持TF卡界面、序列界面、温湿度感测器界面(DHT11界面)和保留的IO口界面,该模块支持在Arduino IDE、ESP IDE、MicroPython和Mixly中进行开发。

 

00.jpg

安装TFT_eSPI、XPT2046_Touchscreen和LVGL库
网址:
TFT_eSPI库的网址:https://github.com/Bodmer/TFT_eSPI


XPT2046_Touchscreen库的网址: https://github.com/PaulStoffregen/XPT2046_Touchscreen

 

通杀需要根据不同开发板与TFT屏幕正确配置User_Setup.h和lv_conf.h文件。

 

02-4.jpg
02-5.jpg
04.jpg

LVGL (Light and Versatile Graphics Library) 是一个免费的开源图形库,可为需要图形用户界面 (GUI) 的微控制器项目提供各种易于使用的图形元素。

 

04-.jpg

 

以下是它的一些主要功能:

块:按钮、图表、列表、滑块、图像等......
具有动画、抗锯齿、不透明度、平滑滚动的高级图形;
各种输入设备,如触摸板、鼠标、键盘、编码器等......
UTF-8 编码的多语言支持;
多显示器支持,即同时使用多个 TFT 单色显示器;
具有类似 CSS 样式的完全可定制的图形元素;
独立于硬件:与任何微控制器或显示器一起使用;
可扩展:能够在很少的内存下运行(64 kB 闪存,16 kB RAM);
用 C 语言编写,以实现最大的兼容性(C++ 兼容)并绑定到 MicroPython。

它的文档中还有大量可供您使用的代码示例:文本、按钮、滑块、输入字段、键盘、自定义样式、图像、弧线、线条、动画、菜单、选项卡、布局、表格等等......

 

04-1.jpg

  【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
 实验二百三十八:ESP32开发板WiFi蓝牙2.8寸240*320智能液晶显示屏带触摸屏TFT模块
 项目实验之十九:ESP32 CYD液晶2.8寸开发板尝试LVGL(轻量级和多功能图形库)

实验开源代码

 

代码
/*
  【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
  实验二百三十八:ESP32开发板WiFi蓝牙2.8寸240*320智能液晶显示屏带触摸屏TFT模块
  项目实验之十九:ESP32 CYD液晶2.8寸开发板尝试LVGL(轻量级和多功能图形库)
*/

#include <lvgl.h>                 // 引入LVGL图形库
#include <TFT_eSPI.h>             // 引入TFT_eSPI库,用于驱动TFT显示屏
#include <XPT2046_Touchscreen.h>  // 引入XPT2046触摸屏库

// 触摸屏引脚定义
#define XPT2046_IRQ 36   // T_IRQ引脚
#define XPT2046_MOSI 32  // T_DIN引脚
#define XPT2046_MISO 39  // T_OUT引脚
#define XPT2046_CLK 25   // T_CLK引脚
#define XPT2046_CS 33    // T_CS引脚

SPIClass touchscreenSPI = SPIClass(VSPI);                  // 实例化一个SPI类,用于触摸屏通信
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);  // 创建触摸屏对象

#define SCREEN_WIDTH 240   // 屏幕宽度定义
#define SCREEN_HEIGHT 320  // 屏幕高度定义

// 触摸屏坐标:(x, y) 和压力(z)
int x, y, z;

#define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 10 * (LV_COLOR_DEPTH / 8))  // 绘图缓冲区大小定义
uint32_t draw_buf[DRAW_BUF_SIZE / 4];                                             // 绘图缓冲区

// 如果启用了日志记录,它将告知用户库中发生了什么
void log_print(lv_log_level_t level, const char* buf) {
  LV_UNUSED(level);     // LVGL中未使用的宏
  Serial.println(buf);  // 打印日志信息
  Serial.flush();       // 清空串口缓冲区
}

// 获取触摸屏数据
void touchscreen_read(lv_indev_t* indev, lv_indev_data_t* data) {
  // 检查触摸屏是否被触摸,并打印X, Y和压力(Z)
  if (touchscreen.tirqTouched() && touchscreen.touched()) {
    // 获取触摸屏坐标点
    TS_Point p = touchscreen.getPoint();
    // 使用map函数校准触摸屏坐标点到正确的宽度和高度
    x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);
    y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);
    z = p.z;

    data->state = LV_INDEV_STATE_PRESSED;  // 设置状态为按下

    // 设置坐标点
    data->point.x = x;
    data->point.y = y;

    // 在串口监视器上打印触摸屏信息关于X, Y和压力(Z)
    /* Serial.print("X = ");
    Serial.print(x);
    Serial.print(" | Y = ");
    Serial.print(y);
    Serial.print(" | Pressure = ");
    Serial.print(z);
    Serial.println();*/
  } else {
    data->state = LV_INDEV_STATE_RELEASED;  // 设置状态为释放
  }
}

int btn1_count = 0;  // 按钮1的计数器
// 当按钮1被点击时触发的回调函数
static void event_handler_btn1(lv_event_t* e) {
  lv_event_code_t code = lv_event_get_code(e);  // 获取事件代码
  if (code == LV_EVENT_CLICKED) {
    btn1_count++;                                       // 按钮计数器加1
    LV_LOG_USER("Button clicked %d", (int)btn1_count);  // 用户日志记录按钮点击次数
  }
}

// 当按钮2被点击/切换时触发的回调函数
static void event_handler_btn2(lv_event_t* e) {
  lv_event_code_t code = lv_event_get_code(e);        // 获取事件代码
  lv_obj_t* obj = (lv_obj_t*)lv_event_get_target(e);  // 获取事件目标对象
  if (code == LV_EVENT_VALUE_CHANGED) {
    LV_UNUSED(obj);                                                                     // LVGL中未使用的宏
    LV_LOG_USER("Toggled %s", lv_obj_has_state(obj, LV_STATE_CHECKED) ? "on" : "off");  // 用户日志记录开关状态
  }
}

static lv_obj_t* slider_label;  // 滑块标签对象
// 回调函数,用于在TFT显示屏和串口监视器上打印当前滑块值,用于调试目的
static void slider_event_callback(lv_event_t* e) {
  lv_obj_t* slider = (lv_obj_t*)lv_event_get_target(e);                     // 获取事件目标对象(滑块)
  char buf[8];                                                              // 缓冲区
  lv_snprintf(buf, sizeof(buf), "%d%%", (int)lv_slider_get_value(slider));  // 获取滑块值并格式化为字符串
  lv_label_set_text(slider_label, buf);                                     // 设置滑块标签文本
  lv_obj_align_to(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);    // 将滑块标签对齐到滑块下方
  LV_LOG_USER("Slider changed to %d%%", (int)lv_slider_get_value(slider));  // 用户日志记录滑块值
}

void lv_create_main_gui(void) {
  // 创建一个文本标签,居中显示在顶部("Hello, world!")
  lv_obj_t* text_label = lv_label_create(lv_screen_active());
  lv_label_set_long_mode(text_label, LV_LABEL_LONG_WRAP);  // 自动换行
  lv_label_set_text(text_label, "Hello, world!");
  lv_obj_set_width(text_label, 150);  // 设置较小的宽度以使文本换行
  lv_obj_set_style_text_align(text_label, LV_TEXT_ALIGN_CENTER, 0);
  lv_obj_align(text_label, LV_ALIGN_CENTER, 0, -90);

  lv_obj_t* btn_label;
  // 创建一个按钮(btn1)
  lv_obj_t* btn1 = lv_button_create(lv_screen_active());
  lv_obj_add_event_cb(btn1, event_handler_btn1, LV_EVENT_ALL, NULL);
  lv_obj_align(btn1, LV_ALIGN_CENTER, 0, -50);
  lv_obj_remove_flag(btn1, LV_OBJ_FLAG_PRESS_LOCK);

  btn_label = lv_label_create(btn1);
  lv_label_set_text(btn_label, "Button");
  lv_obj_center(btn_label);

  // 创建一个切换按钮(btn2)
  lv_obj_t* btn2 = lv_button_create(lv_screen_active());
  lv_obj_add_event_cb(btn2, event_handler_btn2, LV_EVENT_ALL, NULL);
  lv_obj_align(btn2, LV_ALIGN_CENTER, 0, 10);
  lv_obj_add_flag(btn2, LV_OBJ_FLAG_CHECKABLE);
  lv_obj_set_height(btn2, LV_SIZE_CONTENT);

  btn_label = lv_label_create(btn2);
  lv_label_set_text(btn_label, "Toggle");
  lv_obj_center(btn_label);

  // 在TFT显示屏底部居中创建一个滑块
  lv_obj_t* slider = lv_slider_create(lv_screen_active());
  lv_obj_align(slider, LV_ALIGN_CENTER, 0, 60);
  lv_obj_add_event_cb(slider, slider_event_callback, LV_EVENT_VALUE_CHANGED, NULL);
  lv_slider_set_range(slider, 0, 100);
  lv_obj_set_style_anim_duration(slider, 2000, 0);

  // 在滑块下方创建一个标签以显示当前滑块值
  slider_label = lv_label_create(lv_screen_active());
  lv_label_set_text(slider_label, "0%");
  lv_obj_align_to(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
}

void setup() {
  String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
  Serial.begin(115200);          // 初始化串口通信,波特率为115200
  Serial.println(LVGL_Arduino);  // 打印LVGL库版本信息

  // 启动LVGL
  lv_init();
  // 注册打印函数用于调试
  lv_log_register_print_cb(log_print);

  // 启动触摸屏的SPI并初始化触摸屏
  touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
  touchscreen.begin(touchscreenSPI);
  // 设置触摸屏旋转为横屏模式
  // 注意:在某些显示屏上,触摸屏可能是倒置的,因此可能需要将旋转设置为0:touchscreen.setRotation(0);
  touchscreen.setRotation(2);

  // 创建一个显示对象
  lv_display_t* disp;
  // 使用TFT_eSPI库初始化TFT显示屏
  disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
  lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);

  // 初始化一个LVGL输入设备对象(触摸屏)
  lv_indev_t* indev = lv_indev_create();
  lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
  // 设置回调函数以读取触摸屏输入
  lv_indev_set_read_cb(indev, touchscreen_read);  // 注册触摸屏读取回调函数

  // 绘制GUI(文本、按钮和滑块)
  lv_create_main_gui();
}

void loop() {
  lv_task_handler();  // 让GUI执行其任务
  lv_tick_inc(5);     // 告诉LVGL已经过去了多少时间
  delay(5);           // 让这段时间过去
}

代码解读
这段代码是一个用于Arduino的示例,它结合了LVGL图形库和TFT_eSPI库以及XPT2046触摸屏库,用于在TFT显示屏上创建一个简单的图形用户界面(GUI)。下面是代码的主要功能和组件的解释:

1;包含库:

lvgl.h:LVGL图形库的头文件。
TFT_eSPI.h:用于驱动TFT显示屏的TFT_eSPI库。
XPT2046_Touchscreen.h:用于驱动XPT2046触摸屏的库。

2、触摸屏引脚定义:

定义了连接XPT2046触摸屏的Arduino引脚。

3、SPI类实例化:

实例化了一个SPI类touchscreenSPI,用于与触摸屏通信。

4、触摸屏对象:

创建了一个XPT2046_Touchscreen对象touchscreen,用于管理触摸屏。

5、屏幕和缓冲区定义:

定义了屏幕的宽度和高度。
定义了一个缓冲区draw_buf,用于LVGL的绘图操作。

6、日志打印函数:

log_print函数用于将LVGL的日志信息打印到串口。

7、触摸屏读取函数:

touchscreen_read函数用于读取触摸屏的数据,并将其转换为LVGL可以理解的坐标。

8、按钮和滑块事件处理函数:

event_handler_btn1、event_handler_btn2和slider_event_callback函数分别用于处理按钮点击、切换和滑块值变化的事件。

9、GUI创建函数:

lv_create_main_gui函数用于创建GUI界面,包括文本标签、按钮和滑块。

10、setup函数:

初始化串口通信。
初始化LVGL库。
初始化触摸屏。
创建显示对象和输入设备对象。
调用lv_create_main_gui函数来绘制GUI。

11、loop函数:

包含LVGL的任务处理和时间增量,以保持GUI的响应。
这段代码展示了如何使用LVGL在TFT显示屏上创建一个基本的GUI,包括文本显示、按钮和滑块,并通过触摸屏进行交互。

 

实验串口返回情况

 

04-2.jpg
04-3.jpg

实验场景图

 

04-4.jpg
04-5.jpg
04-6.jpg
04-7.jpg

评论

user-avatar
icon 他的勋章
    展开更多