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/
要获取您所在时区的准确日期和时间,我们将使用 WorldTimeAPI。要从 API 获取时间,ESP32 需要连接到互联网,因此您需要在周围环境中安装路由器,以便 ESP32 可以连接到它。
安装 ArduinoJson 库
对于此项目,您需要安装 ArduinoJSON 库,以便在向 WorldTimeAPI 发出请求时处理 JSON 响应。
在 Arduino IDE 中,转到 Sketch > Include Library > Manage Libraries。搜索 ArduinoJSON 并安装 Benoit Blanchon 提供的库。我们使用的是 7.0.4 版本。我们建议使用相同的版本。
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百三十八:ESP32开发板WiFi蓝牙2.8寸240*320智能液晶显示屏带触摸屏TFT模块
项目实验之二十四:带 LVGL 的 ESP32 CYD:显示时间和日期的数字时钟
实验开源代码
/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百三十八:ESP32开发板WiFi蓝牙2.8寸240*320智能液晶显示屏带触摸屏TFT模块
项目实验之二十四:带 LVGL 的 ESP32 CYD:显示时间和日期的数字时钟
*/
#include <lvgl.h> // 引入LVGL图形库
#include <TFT_eSPI.h> // 引入TFT_eSPI库,用于驱动TFT显示屏
#include <WiFi.h> // 引入WiFi库,用于WiFi连接
#include <HTTPClient.h> // 引入HTTPClient库,用于发起HTTP请求
#include <ArduinoJson.h> // 引入ArduinoJson库,用于处理JSON数据
// 替换为您的网络凭据
const char* ssid = "zhz3";// WiFi名称
const char* password = "z156721";// WiFi密码
// 指定您想要获取时间的时区:https://worldtimeapi.org/api/timezone
// 葡萄牙时区示例:"Europe/Lisbon"
const char* timezone = "Europe/Lisbon"; // 设置时区
// 存储日期和时间
String current_date; // 当前日期
String current_time; // 当前时间
// 存储小时、分钟、秒
static int32_t hour; // 小时
static int32_t minute; // 分钟
static int32_t second; // 秒
bool sync_time_date = false; // 是否同步日期和时间
#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(); // 清空串口缓冲区
}
String format_time(int time) { // 格式化时间为两位数
return (time < 10) ? "0" + String(time) : String(time);
}
static lv_obj_t * text_label_time; // 时间标签
static lv_obj_t * text_label_date; // 日期标签
static void timer_cb(lv_timer_t * timer){ // 定时器回调函数
LV_UNUSED(timer);
second++;
if(second > 59) { // 秒数超过59则进位
second = 0;
minute++;
if(minute > 59) { // 分钟超过59则进位
minute = 0;
hour++;
sync_time_date = true; // 设置同步日期和时间标志
Serial.println(sync_time_date);
Serial.println("\n\n\n\n\n\n\n\n");
if(hour > 23) { // 小时超过23则归零
hour = 0;
}
}
}
String hour_time_f = format_time(hour); // 格式化小时
String minute_time_f = format_time(minute); // 格式化分钟
String second_time_f = format_time(second); // 格式化秒
String final_time_str = String(hour_time_f) + ":" + String(minute_time_f) + ":" + String(second_time_f); // 组合成最终时间字符串
//Serial.println(final_time_str);
lv_label_set_text(text_label_time, final_time_str.c_str()); // 设置时间标签文本
lv_label_set_text(text_label_date, current_date.c_str()); // 设置日期标签文本
}
void lv_create_main_gui(void) { // 创建主GUI界面
// 从WorldTimeAPI获取时间和日期
while(hour==0 && minute==0 && second==0) {
get_date_and_time();
}
Serial.println("Current Time: " + current_time); // 打印当前时间
Serial.println("Current Date: " + current_date); // 打印当前日期
lv_timer_t * timer = lv_timer_create(timer_cb, 1000, NULL); // 创建定时器
lv_timer_ready(timer); // 定时器立即执行
// 创建居中对齐的时间文本标签
text_label_time = lv_label_create(lv_screen_active()); // 创建标签
lv_label_set_text(text_label_time, ""); // 设置标签文本为空
lv_obj_align(text_label_time, LV_ALIGN_CENTER, 0, -30); // 设置标签位置
// 设置字体类型和大小
static lv_style_t style_text_label;
lv_style_init(&style_text_label); // 初始化样式
lv_style_set_text_font(&style_text_label, &lv_font_montserrat_48); // 设置字体为48号
lv_obj_add_style(text_label_time, &style_text_label, 0); // 应用样式
// 创建居中对齐的日期文本标签
text_label_date = lv_label_create(lv_screen_active()); // 创建标签
lv_label_set_text(text_label_date, current_date.c_str()); // 设置标签文本
lv_obj_align(text_label_date, LV_ALIGN_CENTER, 0, 40); // 设置标签位置
// 设置字体类型和大小
static lv_style_t style_text_label2;
lv_style_init(&style_text_label2); // 初始化样式
lv_style_set_text_font(&style_text_label2, &lv_font_montserrat_30); // 设置字体为30号
lv_obj_add_style(text_label_date, &style_text_label2, 0); // 应用样式
lv_obj_set_style_text_color((lv_obj_t*) text_label_date, lv_palette_main(LV_PALETTE_GREY), 0); // 设置文本颜色为灰色
}
void get_date_and_time() { // 获取日期和时间
if (WiFi.status() == WL_CONNECTED) { // 如果WiFi已连接
HTTPClient http; // 创建HTTPClient对象
// 构造API端点
String url = String("http://worldtimeapi.org/api/timezone/") + timezone;
http.begin(url); // 初始化HTTP请求
int httpCode = http.GET(); // 发起GET请求
if (httpCode > 0) { // 如果请求成功
// 检查响应
if (httpCode == HTTP_CODE_OK) { // 如果响应码为OK
String payload = http.getString(); // 获取响应内容
//Serial.println("Time information:");
//Serial.println(payload);
// 解析JSON以提取时间
JsonDocument doc; // 创建JSON文档
DeserializationError error = deserializeJson(doc, payload); // 反序列化JSON
if (!error) { // 如果没有错误
const char* datetime = doc["datetime"]; // 获取datetime字段
// 将datetime分割为日期和时间
String datetime_str = String(datetime);
int splitIndex = datetime_str.indexOf('T');
current_date = datetime_str.substring(0, splitIndex); // 提取日期部分
current_time = datetime_str.substring(splitIndex + 1, splitIndex + 9); // 提取时间部分
hour = current_time.substring(0, 2).toInt(); // 提取小时
minute = current_time.substring(3, 5).toInt(); // 提取分钟
second = current_time.substring(6, 8).toInt(); // 提取秒
} else { // 如果反序列化失败
Serial.print("deserializeJson() failed: ");
Serial.println(error.c_str()); // 打印错误信息
}
}
} else { // 如果请求失败
Serial.printf("GET request failed, error: %s\n", http.errorToString(httpCode).c_str()); // 打印错误信息
sync_time_date = true; // 设置同步日期和时间标志
}
http.end(); // 关闭连接
} else { // 如果WiFi未连接
Serial.println("Not connected to Wi-Fi"); // 打印未连接信息
}
}
void setup() {
String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch(); // LVGL库版本
Serial.begin(115200); // 初始化串口通信
Serial.println(LVGL_Arduino); // 打印LVGL库版本
// 连接到WiFi
WiFi.begin(ssid, password); // 初始化WiFi连接
Serial.print("Connecting"); // 打印连接信息
while (WiFi.status() != WL_CONNECTED) { // 等待WiFi连接
delay(500); // 延时
Serial.print("."); // 打印点以显示进度
}
Serial.print("\nConnected to Wi-Fi network with IP Address: "); // 打印连接成功的信息
Serial.println(WiFi.localIP()); // 打印IP地址
// 开始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); // 设置屏幕旋转方向为270度
// 函数用于绘制GUI
lv_create_main_gui();
}
void loop() {
// 从WorldTimeAPI获取日期和时间
if(sync_time_date) { // 如果需要同步日期和时间
sync_time_date = false; // 重置同步标志
get_date_and_time(); // 获取日期和时间
while(hour==0 && minute==0 && second==0) { // 如果获取的时间无效(即小时、分钟、秒都为0)
get_date_and_time(); // 再次尝试获取日期和时间
}
}
lv_task_handler(); // 让LVGL执行GUI任务
lv_tick_inc(5); // 告诉LVGL已经过去了5毫秒
delay(5); // 等待5毫秒
}
代码的简要说明:
1、引入库:
lvgl.h:用于图形界面的LVGL库。
TFT_eSPI.h:用于驱动TFT显示屏的TFT_eSPI库。
WiFi.h:用于WiFi连接的库。
HTTPClient.h:用于发起HTTP请求的库。
ArduinoJson.h:用于处理JSON数据的库。
2、WiFi设置:
ssid和password:用于连接到WiFi网络的凭据。
3、时区设置:
timezone:设置为葡萄牙的时区"Europe/Lisbon"。
4、日期和时间变量:
current_date和current_time:存储当前日期和时间的字符串。
hour、minute、second:存储小时、分钟、秒的整数变量。
sync_time_date:标志变量,用于指示是否需要同步日期和时间。
5、屏幕参数:
SCREEN_WIDTH和SCREEN_HEIGHT:屏幕的宽度和高度。
DRAW_BUF_SIZE和draw_buf:绘图缓冲区的大小和数组。
6、日志打印函数:
log_print:用于打印LVGL日志的函数。
7、时间格式化函数:
format_time:将时间格式化为两位数的字符串。
8、定时器回调函数:
timer_cb:每秒更新时间显示,并在需要时同步日期和时间。
9、主GUI创建函数:
lv_create_main_gui:初始化GUI界面,包括创建时间标签和日期标签,并设置它们的样式和位置。
10、日期和时间获取函数:
get_date_and_time:从WorldTimeAPI获取当前的日期和时间,并解析JSON数据。
11、setup函数:
初始化串口通信,连接到WiFi网络,初始化LVGL和显示屏,并创建主GUI。
12、loop函数:
周期性地检查是否需要更新时间,并处理LVGL的GUI任务,以及更新屏幕显示。
代码编译时,出现错误
错误信息
Sketch uses 1448233 bytes (110%) of program storage space. Maximum is 1310720 bytes.
Global variables use 63176 bytes (19%) of dynamic memory, leaving 264504 bytes for local variables. Maximum is 327680 bytes.
Sketch too big; see https://support.arduino.cc/hc/en-us/articles/360013825179 for tips on reducing it.
text section exceeds available space in board
Compilation error: text section exceeds available space in board
Sketch使用1448233字节(110%)的程序存储空间。最大值为1310720字节。
全局变量使用63176字节(19%)的动态内存,留下264504字节用于局部变量。最大为327680字节。
草图太大;看https://support.arduino.cc/hc/en-us/articles/360013825179以获取减少它的提示。
文本部分超出板上的可用空间
编译错误:文本部分超出板上的可用空间
没有想到,ESP32也会遇到程序存储空间不够的情况。
后来采取扩大存储,在 Arduino IDE 中转到工具 > 分区方案>选择任何超过 1.4MB APP 的内容,例如:“Huge APP (3MB No OTA/1MB SPIFFS”)。
重新上传代码,可以运行了,实验串口返回情况
检查API的服务状态
访问WorldTimeAPI网站(https://worldtimeapi.org/),才发现API服务不能正常运行。
没想到,过了一天,这个网站又可以正常访问了
连接CYD,打开Arduono IDE,实验串口返回情况
实验场景图 动态图
实验场景图
评论