由于尝试过TFT屏幕不能显示中文,因此我们如果想要显示中文的话就需要导入新的字库,但是尝试过比较麻烦,而且我们所需要使用的中文字库量并不是很大,于是我们选择使用图片来代替字库,将中文作为图片打印到TFT屏幕上。

我暂时想的UI设计如下,分为七块区域分别是:标题、地区、天气、日期、星期、时间以及自己的DIY区域。天气部分由于心知天气免费版所获得的天气信息只有地区、天气、气温三样信息,而天气我们可以暂时总结为晴天、多云、雨天。因此我们需要制作这三类相关的图片。
我们从网上找到一些免费的开源图片,打开PS将其转换为我们的TFT屏幕需要的大小(我选择的是50x50)之后打开我们的取模软件(私信LCD取模软件后发送链接)将图片转换为16进制字符串信息。

注意蓝色框内的设置,否则会出错。
点击保存之后就可以获得我们的数组信息。

将数组信息复制下来,注意的是需要将保存到的信息中的const修饰符去掉以及加上PROGMEM使数据以代码的形式保存下来。

到我们的代码中,我们使用TFT_eSPI库中的pushImage函数打印我们的图片。
就可以在指定位置打印我们的图片啦,注意图片的长度和宽度都要一一对应。我们查看 pushImage的函数声明可以发现,我们调用的红框的函数,但是这个函数的数据部分是没有加
const的所以我们原本的数据如果加上const就会报错(以后有机会讲讲C++的函数重载)


同样的我们做出其他部分的图片信息,例如星期,以及地名还有天气情况。
我们可以使用PS(主要是限制一下文字大小)制作我们的时间信息

和 上一期获取天气的代码 类似(文末给出全部代码)
void getWeatherData() {
HTTPClient http;//创建连接结构体
http.begin(weatherApiUrl);//尝试连接
int httpCode = http.GET();
if (httpCode == HTTP_CODE_OK) {
String weatherData = http.getString();//获取HTTP响应
Serial.println(weatherData);
DynamicJsonDocument doc(1024);
deserializeJson(doc, weatherData);//解析HTTP
weather.City = doc["results"][0]["location"]["name"].as<String>();//城市
weather.description = doc["results"][0]["now"]["code"].as<int>();;//天气
weather.temperature = doc["results"][0]["now"]["temperature"].as<double>();//
}
else {
Serial.println("Failed to fetch weather data");
}
/*
根据天气情况打印相对应天气图片,这个天气代码对应的值在心知天气的官网
查看API文档获得
*/
if(weather.description == 0 || weather.description == 1 )
{
tft.pushImage(190,0,50,50,qingtian);
}
if(weather.description >= 4 && weather.description <= 9 )
{
tft.pushImage(190,0,50,50,duoyun);
}
if(weather.description >= 10 && weather.description <= 18 )
{
tft.pushImage(190,0,50,50,yutian);
}
/*
根据城市打印城市地点(目前只做了杭州)
*/
if(weather.City.equals("杭州"))
{
tft.pushImage(110,0,80,50,hangzhou);
}
http.end();
/*
获得时间信息
*/
struct tm timeinfo;
time_t now = timeClient.getEpochTime();
gmtime_r(&now, &timeinfo);
tft.setCursor(0,65);
tft.setTextSize(4);//设置大字体
/*
打印日期
*/
tft.print(timeinfo.tm_mon+1);//月份从0~11,所以要+1
tft.print('.');
tft.print(timeinfo.tm_mday);//答应日期
switch(timeinfo.tm_wday)//根据星期来打印日期
{
case 0:tft.pushImage(130,50,110,50,zhouri);break;
case 1:tft.pushImage(130,50,110,50,zhouyi);break;
case 2:tft.pushImage(130,50,110,50,zhouer);break;
case 3:tft.pushImage(130,50,110,50,zhousan);break;
case 4:tft.pushImage(130,50,110,50,zhousi);break;
case 5:tft.pushImage(130,50,110,50,zhouwu);break;
case 6:tft.pushImage(130,50,110,50,zhouliu);break;
}
tft.pushImage(0,0,110,50,tianqishizhong);//打印标题
Serial.println(weather.description);
Serial.println(weather.City);
}
同样的,我们也需要打印时间信息,时间信息和上期也几乎没有区别,但是把串口输出换成了屏幕。我们通过设置不同的字体使时间的显示有层次感。
void displaytime() {
tft.setTextSize(2);
tft.setCursor(10, 110);
tft.fillRect(0,110,240,130,TFT_WHITE); // 清空屏幕以便显示新时间
// 获取当前时间
int hours = timeClient.getHours();
int minutes = timeClient.getMinutes();
int seconds = timeClient.getSeconds();
tft.setTextSize(5);//设置大字体
// 打印小时
tft.print(hours);
// 打印分钟
tft.print(":");
tft.print(minutes);
tft.setTextSize(4);//设置小字体
// 打印秒钟
tft.print(":");
tft.println(seconds);
}
在主函数中我们需要设置我们的刷新时间以及获取天气情况的频率。我们设置一个计时。但是后来想想还是选择加入定时器的使用。
我们在库管理导入ESP32Timerintterupt库,并写入头文件中。
#include <ESP32TimerInterrupt.h>
ESP32Timer ITimer(1); // 使用定时器 1
const uint64_t timer_period = 3600000000; // 1 小时的微秒数
void IRAM_ATTR onTimer() {
//获取天气数据
getWeatherData();
//或者更新显示的时间
displaytime();
}
并且在主函数中启动定时器,写在void setup()中
ITimer.attachInterruptInterval(timer_period, onTimer); // 设置定时器中断 ITimer.start();
这样子我们就可以实现一个小时更新一次天气数据了。



登录 或 注册 后才可以进行评论哦!
还没有评论,抢个沙发!