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中进行开发。
安装TFT_eSPI、XPT2046_Touchscreen、BasicLinearAlgebra和LVGL库
网址:
TFT_eSPI库的网址:https://github.com/Bodmer/TFT_eSPI
XPT2046_Touchscreen库的网址: https://github.com/PaulStoffregen/XPT2046_Touchscreen
BasicLinearAlgebra库:https://github.com/tomstewart89/BasicLinearAlgebra
要正确使用 TFT_eSPI 库,需要根据不同开发板与TFT屏幕正确配置User_Setup.h和lv_conf.h文件。
LVGL中文开发手册:https://lvgl.100ask.net/master/
DS18B20 是一种非常受欢迎的数字温度传感器,常用于各种温度监测应用。它具有以下特点:
1、高精度:DS18B20 的温度测量精度为 ±0.5°C,可以提供高达 0.0625°C 的分辨率。
2、数字输出:它通过一条数据线与微控制器进行通信,使用单线制(1-Wire)协议,简化了电路设计。
3、低功耗:该传感器在测量过程中的功耗非常低,适合用于电池供电的设备。
4、广泛的温度范围:DS18B20 可以测量从 -55°C 到 +125°C 的温度范围。
5、高可靠性:由于其数字化设计,DS18B20 具有较高的稳定性和可靠性。
这种传感器非常适合用于环境监测、食品冷藏设备、温度控制系统等领域。
在 ESP32 Cheap Yellow Display 上,有一个扩展的 IO 插槽,可让您连接外部外围设备。我们将传感器连接到 CN1 连接器,并使用 GPIO 27。
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百三十八:ESP32开发板WiFi蓝牙2.8寸240*320智能液晶显示屏带触摸屏TFT模块
项目实验之二十二:带 LVGL 的 ESP32 CYD:使用 DS18B20 传感器显示温度(曲面仪表)
实验开源代码
/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百三十八:ESP32开发板WiFi蓝牙2.8寸240*320智能液晶显示屏带触摸屏TFT模块
项目实验之二十二:带 LVGL 的 ESP32 CYD:使用 DS18B20 传感器显示温度(曲面仪表)
*/
// 包含LVGL库
#include <lvgl.h>
// 安装“TFT_eSPI”库来与TFT显示屏接口 - https://github.com/Bodmer/TFT_eSPI - 重要:网上的User_Setup.h可能无法与Random Nerd Tutorials的示例配合使用
#include <TFT_eSPI.h>
// 安装OneWire和DallasTemperature库
#include <OneWire.h>
#include <DallasTemperature.h>
// DS18B20传感器连接到的GPIO
const int oneWireBus = 27;
// 设置一个OneWire实例与任何OneWire设备通信
OneWire oneWire(oneWireBus);
// 将OneWire引用传递给Dallas Temperature传感器
DallasTemperature sensors(&oneWire);
// 设置变量为0表示华氏温度
#define TEMP_CELSIUS 1
#if TEMP_CELSIUS
#define TEMP_ARC_MIN -20
#define TEMP_ARC_MAX 40
#else
#define TEMP_ARC_MIN -4
#define TEMP_ARC_MAX 104
#endif
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 320
#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);
Serial.println(buf);
Serial.flush();
}
lv_obj_t* arc;
// 在弧形图和文本标签中设置温度值
static void set_temp(void* text_label_temp_value, int32_t v) {
sensors.requestTemperatures();
// 获取最新的温度读数(摄氏度或华氏度)
#if TEMP_CELSIUS
float ds18b20_temp = sensors.getTempCByIndex(0);
if (ds18b20_temp <= 10.0) {
lv_obj_set_style_text_color((lv_obj_t*)text_label_temp_value, lv_palette_main(LV_PALETTE_BLUE), 0);
} else if (ds18b20_temp > 10.0 && ds18b20_temp <= 29.0) {
lv_obj_set_style_text_color((lv_obj_t*)text_label_temp_value, lv_palette_main(LV_PALETTE_GREEN), 0);
} else {
lv_obj_set_style_text_color((lv_obj_t*)text_label_temp_value, lv_palette_main(LV_PALETTE_RED), 0);
}
const char degree_symbol[] = "\u00B0C";
#else
float ds18b20_temp = sensors.getTempFByIndex(0);
if (ds18b20_temp <= 50.0) {
lv_obj_set_style_text_color((lv_obj_t*)text_label_temp_value, lv_palette_main(LV_PALETTE_BLUE), 0);
} else if (ds18b20_temp > 50.0 && ds18b20_temp <= 84.2) {
lv_obj_set_style_text_color((lv_obj_t*)text_label_temp_value, lv_palette_main(LV_PALETTE_GREEN), 0);
} else {
lv_obj_set_style_text_color((lv_obj_t*)text_label_temp_value, lv_palette_main(LV_PALETTE_RED), 0);
}
const char degree_symbol[] = "\u00B0F";
#endif
lv_arc_set_value(arc, map(int(ds18b20_temp), TEMP_ARC_MIN, TEMP_ARC_MAX, 0, 100));
String ds18b20_temp_text = String(ds18b20_temp) + degree_symbol;
lv_label_set_text((lv_obj_t*)text_label_temp_value, ds18b20_temp_text.c_str());
Serial.print("Temperature: ");
Serial.println(ds18b20_temp_text);
}
void lv_create_main_gui(void) {
// 创建一个弧形图
arc = lv_arc_create(lv_screen_active());
lv_obj_set_size(arc, 210, 210);
lv_arc_set_rotation(arc, 135);
lv_arc_set_bg_angles(arc, 0, 270);
lv_obj_set_style_arc_color(arc, lv_color_hex(0x666666), LV_PART_INDICATOR);
lv_obj_set_style_bg_color(arc, lv_color_hex(0x333333), LV_PART_KNOB);
lv_obj_align(arc, LV_ALIGN_CENTER, 0, 10);
// 创建一个字体大小为32的文本标签来显示最新的温度读数
lv_obj_t* text_label_temp_value = lv_label_create(lv_screen_active());
lv_label_set_text(text_label_temp_value, "--.--");
lv_obj_align(text_label_temp_value, LV_ALIGN_CENTER, 0, 10);
static lv_style_t style_temp;
lv_style_init(&style_temp);
lv_style_set_text_font(&style_temp, &lv_font_montserrat_32);
lv_obj_add_style(text_label_temp_value, &style_temp, 0);
// 创建一个动画,每10秒更新一次最新的温度值
lv_anim_t a_temp;
lv_anim_init(&a_temp);
lv_anim_set_exec_cb(&a_temp, set_temp);
lv_anim_set_duration(&a_temp, 1000000);
lv_anim_set_playback_duration(&a_temp, 1000000);
lv_anim_set_var(&a_temp, text_label_temp_value);
lv_anim_set_values(&a_temp, 0, 100);
lv_anim_set_repeat_count(&a_temp, LV_ANIM_REPEAT_INFINITE);
lv_anim_start(&a_temp);
}
void setup() {
String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
Serial.begin(115200);
Serial.println(LVGL_Arduino);
// 启动DS18B20传感器
sensors.begin();
// 启动LVGL
lv_init();
// 注册打印函数用于调试
lv_log_register_print_cb(log_print);
// 创建显示对象
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);
// 绘制GUI
lv_create_main_gui();
}
void loop() {
lv_task_handler(); // 让GUI完成它的工作
lv_tick_inc(5); // 告诉LVGL已经过去了多长时间
delay(5); // 让这段时间过去吧
}
此代码通过ESP32控制一个DS18B20温度传感器和一个TFT显示屏,并且使用LVGL库在显示屏上显示温度信息。
代码说明:
cpp
#include <lvgl.h>
这是LVGL(Light and Versatile Graphics Library)的头文件,它用来创建图形用户界面(GUI)。
cpp
#include <TFT_eSPI.h>
此头文件是TFT_eSPI库,用来与TFT显示屏接口。
cpp
#include <OneWire.h> #include <DallasTemperature.h>
这两个头文件分别是OneWire和DallasTemperature库,用来与DS18B20温度传感器通信。
cpp
const int oneWireBus = 27; OneWire oneWire(oneWireBus); DallasTemperature sensors(&oneWire);
定义了DS18B20传感器的数据引脚为27,并初始化OneWire实例和DallasTemperature实例。
cpp
#define TEMP_CELSIUS 1 #if TEMP_CELSIUS #define TEMP_ARC_MIN -20 #define TEMP_ARC_MAX 40 #else #define TEMP_ARC_MIN -4 #define TEMP_ARC_MAX 104 #endif
定义了温度单位为摄氏度或华氏度,根据选择不同的温度范围。
cpp
#define SCREEN_WIDTH 240 #define SCREEN_HEIGHT 320 #define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 10 * (LV_COLOR_DEPTH / 8)) uint32_t draw_buf[DRAW_BUF_SIZE / 4];
定义了屏幕宽度和高度,并根据屏幕大小定义绘图缓冲区。
cpp
void log_print(lv_log_level_t level, const char * buf) { LV_UNUSED(level); Serial.println(buf); Serial.flush(); }
这是LVGL库的日志打印函数,用于在串口监视器中输出调试信息。
cpp
lv_obj_t * arc;
定义了一个LVGL对象arc,用于绘制圆弧。
cpp
static void set_temp(void * text_label_temp_value, int32_t v) { sensors.requestTemperatures(); #if TEMP_CELSIUS float ds18b20_temp = sensors.getTempCByIndex(0); if(ds18b20_temp <= 10.0) { lv_obj_set_style_text_color((lv_obj_t*) text_label_temp_value, lv_palette_main(LV_PALETTE_BLUE), 0); } else if (ds18b20_temp > 10.0 && ds18b20_temp <= 29.0) { lv_obj_set_style_text_color((lv_obj_t*) text_label_temp_value, lv_palette_main(LV_PALETTE_GREEN), 0); } else { lv_obj_set_style_text_color((lv_obj_t*) text_label_temp_value, lv_palette_main(LV_PALETTE_RED), 0); } const char degree_symbol[] = "\u00B0C"; #else float ds18b20_temp = sensors.getTempFByIndex(0); if(ds18b20_temp <= 50.0) { lv_obj_set_style_text_color((lv_obj_t*) text_label_temp_value, lv_palette_main(LV_PALETTE_BLUE), 0); } else if (ds18b20_temp > 50.0 && ds18b20_temp <= 84.2) { lv_obj_set_style_text_color((lv_obj_t*) text_label_temp_value, lv_palette_main(LV_PALETTE_GREEN), 0); } else { lv_obj_set_style_text_color((lv_obj_t*) text_label_temp_value, lv_palette_main(LV_PALETTE_RED), 0); } const char degree_symbol[] = "\u00B0F"; #endif lv_arc_set_value(arc, map(int(ds18b20_temp), TEMP_ARC_MIN, TEMP_ARC_MAX, 0, 100)); String ds18b20_temp_text = String(ds18b20_temp) + degree_symbol; lv_label_set_text((lv_obj_t*) text_label_temp_value, ds18b20_temp_text.c_str()); Serial.print("Temperature: "); Serial.println(ds18b20_temp_text); }
该函数从DS18B20传感器读取温度数据,并根据温度值设置颜色和文本。在指定的LVGL对象上显示温度信息。
cpp
void lv_create_main_gui(void) { arc = lv_arc_create(lv_screen_active()); lv_obj_set_size(arc, 210, 210); lv_arc_set_rotation(arc, 135); lv_arc_set_bg_angles(arc, 0, 270); lv_obj_set_style_arc_color(arc, lv_color_hex(0x666666), LV_PART_INDICATOR); lv_obj_set_style_bg_color(arc, lv_color_hex(0x333333), LV_PART_KNOB); lv_obj_align(arc, LV_ALIGN_CENTER, 0, 10); lv_obj_t * text_label_temp_value = lv_label_create(lv_screen_active()); lv_label_set_text(text_label_temp_value, "--.--"); lv_obj_align(text_label_temp_value, LV_ALIGN_CENTER, 0, 10); static lv_style_t style_temp; lv_style_init(&style_temp); lv_style_set_text_font(&style_temp, &lv_font_montserrat_32); lv_obj_add_style(text_label_temp_value, &style_temp, 0); lv_anim_t a_temp; lv_anim_init(&a_temp); lv_anim_set_exec_cb(&a_temp, set_temp); lv_anim_set_duration(&a_temp, 1000000); lv_anim_set_playback_duration(&a_temp, 1000000); lv_anim_set_var(&a_temp, text_label_temp_value); lv_anim_set_values(&a_temp, 0, 100); lv_anim_set_repeat_count(&a_temp, LV_ANIM_REPEAT_INFINITE); lv_anim_start(&a_temp); }
该函数创建主界面,包括温度显示的圆弧和文本标签,并设置动画定时更新温度数据。
cpp
void setup() { String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch(); Serial.begin(115200); Serial.println(LVGL_Arduino); sensors.begin(); lv_init(); lv_log_register_print_cb(log_print); lv_display_t * disp; disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf)); lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270); lv_create_main_gui(); }
该函数初始化串口、DS18B20传感器、LVGL库和TFT显示屏,并调用函数创建主界面。
cpp
void loop() { lv_task_handler(); lv_tick_inc(5); delay(5); }
在主循环中,持续更新LVGL的任务处理和时间,以确保图形用户界面正常运行。
实验场景图
评论