由于尝试过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();

这样子我们就可以实现一个小时更新一次天气数据了。



嘉立创PCB

还没有评论,抢个沙发!