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/
安装 ArduinoJson 库
对于此项目,您需要安装 ArduinoJSON 库,以便在向 WorldTimeAPI 发出请求时处理 JSON 响应。
在 Arduino IDE 中,转到 Sketch > Include Library > Manage Libraries。搜索 ArduinoJSON 并安装 Benoit Blanchon 提供的库。我们使用的是 7.0.4 版本。我们建议使用相同的版本。
ESP32 CYD 气象站 – weather_images.h 文件
要使用 LVGL 加载自定义图像,您需要创建一个名为 weather_images.h 的额外文件,该文件必须放在 sketch 文件夹中。我们已经为您准备了该文件。为了加载此气象站项目的自定义图像,您需要下载这个文件。
重要提示:weather_images.h 文件应放置在工程的 sketch 文件夹中的 .ino 文件旁边。
为了获得您所在位置的准确天气描述,我们将使用免费的 Open-Meteo API(https://open-meteo.com/en/docs/cma-api)。要从 API 获取数据,ESP32 需要连接到互联网,因此您需要在周围环境中安装路由器,以便 ESP32 可以连接到它。
【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>
#include <TFT_eSPI.h>
#include "weather_images.h"
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
// Replace with your network credentials
const char* ssid = "zhz3";
const char* password = "z156721";
// Replace with the latitude and longitude to where you want to get the weather
String latitude = "41.14961";
String longitude = "-8.61099";
// Enter your location
String location = "Porto";
// Type the timezone you want to get the time for
String timezone = "Europe/Lisbon";
// Store date and time
String current_date;
String last_weather_update;
String temperature;
String humidity;
int is_day;
int weather_code = 0;
String weather_description;
// SET VARIABLE TO 0 FOR TEMPERATURE IN FAHRENHEIT DEGREES
#define TEMP_CELSIUS 1
#if TEMP_CELSIUS
String temperature_unit = "";
const char degree_symbol[] = "\u00B0C";
#else
String temperature_unit = "&temperature_unit=fahrenheit";
const char degree_symbol[] = "\u00B0F";
#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];
// If logging is enabled, it will inform the user about what is happening in the library
void log_print(lv_log_level_t level, const char * buf) {
LV_UNUSED(level);
Serial.println(buf);
Serial.flush();
}
static lv_obj_t * weather_image;
static lv_obj_t * text_label_date;
static lv_obj_t * text_label_temperature;
static lv_obj_t * text_label_humidity;
static lv_obj_t * text_label_weather_description;
static lv_obj_t * text_label_time_location;
static void timer_cb(lv_timer_t * timer){
LV_UNUSED(timer);
get_weather_data();
get_weather_description(weather_code);
lv_label_set_text(text_label_date, current_date.c_str());
lv_label_set_text(text_label_temperature, String(" " + temperature + degree_symbol).c_str());
lv_label_set_text(text_label_humidity, String(" " + humidity + "%").c_str());
lv_label_set_text(text_label_weather_description, weather_description.c_str());
lv_label_set_text(text_label_time_location, String("Last Update: " + last_weather_update + " | " + location).c_str());
}
void lv_create_main_gui(void) {
LV_IMAGE_DECLARE(image_weather_sun);
LV_IMAGE_DECLARE(image_weather_cloud);
LV_IMAGE_DECLARE(image_weather_rain);
LV_IMAGE_DECLARE(image_weather_thunder);
LV_IMAGE_DECLARE(image_weather_snow);
LV_IMAGE_DECLARE(image_weather_night);
LV_IMAGE_DECLARE(image_weather_temperature);
LV_IMAGE_DECLARE(image_weather_humidity);
// Get the weather data from open-meteo.com API
get_weather_data();
weather_image = lv_image_create(lv_screen_active());
lv_obj_align(weather_image, LV_ALIGN_CENTER, -80, -20);
get_weather_description(weather_code);
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, 70, -70);
lv_obj_set_style_text_font((lv_obj_t*) text_label_date, &lv_font_montserrat_26, 0);
lv_obj_set_style_text_color((lv_obj_t*) text_label_date, lv_palette_main(LV_PALETTE_TEAL), 0);
lv_obj_t * weather_image_temperature = lv_image_create(lv_screen_active());
lv_image_set_src(weather_image_temperature, &image_weather_temperature);
lv_obj_align(weather_image_temperature, LV_ALIGN_CENTER, 30, -25);
text_label_temperature = lv_label_create(lv_screen_active());
lv_label_set_text(text_label_temperature, String(" " + temperature + degree_symbol).c_str());
lv_obj_align(text_label_temperature, LV_ALIGN_CENTER, 70, -25);
lv_obj_set_style_text_font((lv_obj_t*) text_label_temperature, &lv_font_montserrat_22, 0);
lv_obj_t * weather_image_humidity = lv_image_create(lv_screen_active());
lv_image_set_src(weather_image_humidity, &image_weather_humidity);
lv_obj_align(weather_image_humidity, LV_ALIGN_CENTER, 30, 20);
text_label_humidity = lv_label_create(lv_screen_active());
lv_label_set_text(text_label_humidity, String(" " + humidity + "%").c_str());
lv_obj_align(text_label_humidity, LV_ALIGN_CENTER, 70, 20);
lv_obj_set_style_text_font((lv_obj_t*) text_label_humidity, &lv_font_montserrat_22, 0);
text_label_weather_description = lv_label_create(lv_screen_active());
lv_label_set_text(text_label_weather_description, weather_description.c_str());
lv_obj_align(text_label_weather_description, LV_ALIGN_BOTTOM_MID, 0, -40);
lv_obj_set_style_text_font((lv_obj_t*) text_label_weather_description, &lv_font_montserrat_18, 0);
// Create a text label for the time and timezone aligned center in the bottom of the screen
text_label_time_location = lv_label_create(lv_screen_active());
lv_label_set_text(text_label_time_location, String("Last Update: " + last_weather_update + " | " + location).c_str());
lv_obj_align(text_label_time_location, LV_ALIGN_BOTTOM_MID, 0, -10);
lv_obj_set_style_text_font((lv_obj_t*) text_label_time_location, &lv_font_montserrat_12, 0);
lv_obj_set_style_text_color((lv_obj_t*) text_label_time_location, lv_palette_main(LV_PALETTE_GREY), 0);
lv_timer_t * timer = lv_timer_create(timer_cb, 600000, NULL);
lv_timer_ready(timer);
}
/*
WMO Weather interpretation codes (WW)- Code Description
0 Clear sky
1, 2, 3 Mainly clear, partly cloudy, and overcast
45, 48 Fog and depositing rime fog
51, 53, 55 Drizzle: Light, moderate, and dense intensity
56, 57 Freezing Drizzle: Light and dense intensity
61, 63, 65 Rain: Slight, moderate and heavy intensity
66, 67 Freezing Rain: Light and heavy intensity
71, 73, 75 Snow fall: Slight, moderate, and heavy intensity
77 Snow grains
80, 81, 82 Rain showers: Slight, moderate, and violent
85, 86 Snow showers slight and heavy
95 * Thunderstorm: Slight or moderate
96, 99 * Thunderstorm with slight and heavy hail
*/
void get_weather_description(int code) {
switch (code) {
case 0:
if(is_day==1) { lv_image_set_src(weather_image, &image_weather_sun); }
else { lv_image_set_src(weather_image, &image_weather_night); }
weather_description = "CLEAR SKY";
break;
case 1:
if(is_day==1) { lv_image_set_src(weather_image, &image_weather_sun); }
else { lv_image_set_src(weather_image, &image_weather_night); }
weather_description = "MAINLY CLEAR";
break;
case 2:
lv_image_set_src(weather_image, &image_weather_cloud);
weather_description = "PARTLY CLOUDY";
break;
case 3:
lv_image_set_src(weather_image, &image_weather_cloud);
weather_description = "OVERCAST";
break;
case 45:
lv_image_set_src(weather_image, &image_weather_cloud);
weather_description = "FOG";
break;
case 48:
lv_image_set_src(weather_image, &image_weather_cloud);
weather_description = "DEPOSITING RIME FOG";
break;
case 51:
lv_image_set_src(weather_image, &image_weather_rain);
weather_description = "DRIZZLE LIGHT INTENSITY";
break;
case 53:
lv_image_set_src(weather_image, &image_weather_rain);
weather_description = "DRIZZLE MODERATE INTENSITY";
break;
case 55:
lv_image_set_src(weather_image, &image_weather_rain);
weather_description = "DRIZZLE DENSE INTENSITY";
break;
case 56:
lv_image_set_src(weather_image, &image_weather_rain);
weather_description = "FREEZING DRIZZLE LIGHT";
break;
case 57:
lv_image_set_src(weather_image, &image_weather_rain);
weather_description = "FREEZING DRIZZLE DENSE";
break;
case 61:
lv_image_set_src(weather_image, &image_weather_rain);
weather_description = "RAIN SLIGHT INTENSITY";
break;
case 63:
lv_image_set_src(weather_image, &image_weather_rain);
weather_description = "RAIN MODERATE INTENSITY";
break;
case 65:
lv_image_set_src(weather_image, &image_weather_rain);
weather_description = "RAIN HEAVY INTENSITY";
break;
case 66:
lv_image_set_src(weather_image, &image_weather_rain);
weather_description = "FREEZING RAIN LIGHT INTENSITY";
break;
case 67:
lv_image_set_src(weather_image, &image_weather_rain);
weather_description = "FREEZING RAIN HEAVY INTENSITY";
break;
case 71:
lv_image_set_src(weather_image, &image_weather_snow);
weather_description = "SNOW FALL SLIGHT INTENSITY";
break;
case 73:
lv_image_set_src(weather_image, &image_weather_snow);
weather_description = "SNOW FALL MODERATE INTENSITY";
break;
case 75:
lv_image_set_src(weather_image, &image_weather_snow);
weather_description = "SNOW FALL HEAVY INTENSITY";
break;
case 77:
lv_image_set_src(weather_image, &image_weather_snow);
weather_description = "SNOW GRAINS";
break;
case 80:
lv_image_set_src(weather_image, &image_weather_rain);
weather_description = "RAIN SHOWERS SLIGHT";
break;
case 81:
lv_image_set_src(weather_image, &image_weather_rain);
weather_description = "RAIN SHOWERS MODERATE";
break;
case 82:
lv_image_set_src(weather_image, &image_weather_rain);
weather_description = "RAIN SHOWERS VIOLENT";
break;
case 85:
lv_image_set_src(weather_image, &image_weather_snow);
weather_description = "SNOW SHOWERS SLIGHT";
break;
case 86:
lv_image_set_src(weather_image, &image_weather_snow);
weather_description = "SNOW SHOWERS HEAVY";
break;
case 95:
lv_image_set_src(weather_image, &image_weather_thunder);
weather_description = "THUNDERSTORM";
break;
case 96:
lv_image_set_src(weather_image, &image_weather_thunder);
weather_description = "THUNDERSTORM SLIGHT HAIL";
break;
case 99:
lv_image_set_src(weather_image, &image_weather_thunder);
weather_description = "THUNDERSTORM HEAVY HAIL";
break;
default:
weather_description = "UNKNOWN WEATHER CODE";
break;
}
}
void get_weather_data() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
// Construct the API endpoint
String url = String("http://api.open-meteo.com/v1/forecast?latitude=" + latitude + "&longitude=" + longitude + "¤t=temperature_2m,relative_humidity_2m,is_day,precipitation,rain,weather_code" + temperature_unit + "&timezone=" + timezone + "&forecast_days=1");
http.begin(url);
int httpCode = http.GET(); // Make the GET request
if (httpCode > 0) {
// Check for the response
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
//Serial.println("Request information:");
//Serial.println(payload);
// Parse the JSON to extract the time
JsonDocument doc;
DeserializationError error = deserializeJson(doc, payload);
if (!error) {
const char* datetime = doc["current"]["time"];
temperature = String(doc["current"]["temperature_2m"]);
humidity = String(doc["current"]["relative_humidity_2m"]);
is_day = String(doc["current"]["is_day"]).toInt();
weather_code = String(doc["current"]["weather_code"]).toInt();
/*Serial.println(temperature);
Serial.println(humidity);
Serial.println(is_day);
Serial.println(weather_code);
Serial.println(String(timezone));*/
// Split the datetime into date and time
String datetime_str = String(datetime);
int splitIndex = datetime_str.indexOf('T');
current_date = datetime_str.substring(0, splitIndex);
last_weather_update = datetime_str.substring(splitIndex + 1, splitIndex + 9); // Extract time portion
} else {
Serial.print("deserializeJson() failed: ");
Serial.println(error.c_str());
}
}
else {
Serial.println("Failed");
}
} else {
Serial.printf("GET request failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end(); // Close connection
} else {
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();
Serial.begin(115200);
Serial.println(LVGL_Arduino);
// Connect to Wi-Fi
WiFi.begin(ssid, password);
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.print("\nConnected to Wi-Fi network with IP Address: ");
Serial.println(WiFi.localIP());
// Start LVGL
lv_init();
// Register print function for debugging
lv_log_register_print_cb(log_print);
// Create a display object
lv_display_t * disp;
// Initialize the TFT display using the TFT_eSPI library
disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);
// Function to draw the GUI
lv_create_main_gui();
}
void loop() {
lv_task_handler(); // let the GUI do its work
lv_tick_inc(5); // tell LVGL how much time has passed
delay(5); // let this time pass
}
这段代码是一个使用ESP32开发板和2.8寸TFT显示屏(带触摸屏)的气象站项目,它通过LVGL图形库显示天气信息,包括天气描述、温度和湿度。以下是对代码的十点解读:
1、网络配置:
代码中包含了WiFi网络的SSID和密码,用于连接到互联网获取天气数据。
2、地理位置信息:
通过latitude和longitude变量设置了想要获取天气信息的地理位置,location变量用于标识位置名称。
3、时区设置:
timezone变量用于设置时区,这对于获取正确的日期和时间信息至关重要。
4、天气数据变量:
定义了多个字符串变量来存储当前日期、最后更新时间、温度、湿度和天气描述。
5、温度单位设置:
通过TEMP_CELSIUS宏定义来决定温度单位是摄氏度还是华氏度。
6、屏幕参数和绘图缓冲区:
定义了屏幕的宽度和高度,以及绘图缓冲区的大小,这对于TFT显示屏的正确显示是必要的。
7、日志打印函数:
log_print函数用于打印LVGL库的日志信息,方便调试。
8、GUI组件创建:
lv_create_main_gui函数中创建了多个GUI组件,包括天气图像、日期标签、温度标签、湿度标签和天气描述标签。
9、天气数据获取:
get_weather_data函数通过HTTP请求从open-meteo.comAPI获取天气数据,并解析JSON响应。
10天气描述映射:
get_weather_description函数根据天气代码映射到具体的天气描述,并设置相应的天气图像。
实验串口返回情况
已连接到IP地址为192.168.28.13的Wi-Fi网络
GET请求失败,错误:连接丢失
实验场景图 (只有LVGL,连接丢失没有数据)
评论