由于尝试过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();
这样子我们就可以实现一个小时更新一次天气数据了。
登录 或 注册 后才可以进行评论哦!
还没有评论,抢个沙发!