目录
本文基于platformio,使用esp32和freertos修改了一个开源作品。
主要功能为实时显示当前时间和日期和天气状况。主要分为weather更新任务,button任务,scroller任务,timer任务,Animate任务。
weather任务:每隔5分钟更新天气情况
button任务:检测是否有按键按下,按下就触发重置任务
scroller任务:实时滚动显示当前天气情况,温度等情况。
timer任务:实时显示当前时间
Animate任务:实时右下角刷新动图
tft显示屏SLC接D18,SDA接D23,RES接D26,DC接D25,CS接D27,BLK接D22。插上电源开机等待提示手机连接esp32的AP,联入之后填写地区等要素然后结束,esp32自动重启开始联网。
代码如下。
- /* *****************************************************************
- *
- *
- * 小型桌面显示器
- *
- * 现作者:大益
- * 原 作 者:指针阿飞
- *
- * 创 建 日 期:2024.4.22
- *
- *
- *
- *
- * *****************************************************************/
-
- /* *****************************************************************
- * 库文件、头文件
- * *****************************************************************/
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
//内存 - #include
//按钮库 - #include
- #include
- #include "config.h" //配置文件
- #include "weatherNum/weatherNum.h" //天气图库
- #include "Animate/Animate.h" //动画模块
- #include "wifiReFlash/wifiReFlash.h" //WIFI功能模块
- #include "Animate/img/hutao.h"
- #define Version "v1.0.0"
- /* *****************************************************************
- * 配置使能位
- * *****************************************************************/
-
- #if WM_EN
- #include
- // WiFiManager 参数
- WiFiManager wm; // global wm instance
- // WiFiManagerParameter custom_field; // global param ( for non blocking w params )
- #endif
-
- // 定义按钮引脚
- Button2 Button_sw1 = Button2(15);
- /* *****************************************************************
- * 字库、图片库
- * *****************************************************************/
- #include "font/ZdyLwFont_20.h" //字体库
- #include "font/timeClockFont.h" //字体库
- #include "font/Chancery_L_20.h" //字体库
- #include "img/temperature.h" //温度图标
- #include "img/humidity.h" //湿度图标
- #include "font/KT_20.h"
- SemaphoreHandle_t xMutex; // 互斥锁句柄
- // struct tm timeinfo;
- // const long gmtOffset_sec = 8 * 3600;
- // const int daylightOffset_sec = 0;
- /* *****************************************************************
- * 函数声明
- * *****************************************************************/
- void sendNTPpacket(IPAddress &address); // 向NTP服务器发送请求
- time_t getNtpTime(); // 从NTP获取时间
- void digitalClockDisplay(int reflash_en);
- void printDigits(int digits);
- void LCD_reflash();
- void clear_screen();
- void savewificonfig(); // wifi ssid,psw保存到eeprom
- void readwificonfig(); // 从eeprom读取WiFi信息ssid,psw
- void deletewificonfig(); // 删除原有eeprom中的信息
- void getCityCode(); // 发送HTTP请求并且将服务器响应通过串口输出
- void getCityWeater(); // 获取城市天气
- void wifi_reset(Button2 &btn); // WIFI重设
- void saveParamCallback();
- void esp_reset(Button2 &btn);
- void scrollBanner();
- void weaterData(String *cityDZ, String *dataSK, String *dataFC); // 天气信息写到屏幕上
-
- /* *****************************************************************
- * 参数设置
- * *****************************************************************/
- struct config_type
- {
- char stassid[32]; // 定义配网得到的WIFI名长度(最大32字节)
- char stapsw[64]; // 定义配网得到的WIFI密码长度(最大64字节)
- };
- //---------------修改此处""内的信息--------------------
- // 如开启WEB配网则可不用设置这里的参数,前一个为wifi ssid,后一个为密码
- config_type wificonf = {{"WiFi名"}, {"密码"}};
-
- // 天气更新时间 X 分钟(默认3分钟)
- unsigned int updateweater_time = WEATHER_UPDATE_TIME;
- // 天气信息
- struct Weather_Msg
- {
- String cityDZ;
- String dataSK;
- String dataFC;
- };
-
- Weather_Msg weather_msg = {{""}, {""}, {""}};
- //----------------------------------------------------
-
- // LCD屏幕相关设置
- TFT_eSPI tft = TFT_eSPI(); // 引脚请自行配置tft_espi库中的 User_Setup.h文件
- TFT_eSprite clk = TFT_eSprite(&tft);
- #define LCD_BL_PIN 5 // LCD背光引脚
- uint16_t bgColor = 0x0000;
- uint16_t pinkColor = tft.color565(255, 174, 201);
- uint16_t zongseColor = tft.color565(128, 64, 64);
- uint16_t whiteColor = tft.color565(245, 246, 247);
- uint16_t fhColor = tft.color565(253, 99, 139);
- uint16_t blueColor = tft.color565(175, 221, 224);
- // 其余状态标志位
- int LCD_Rotation = 0; // LCD屏幕方向
- int LCD_BL_PWM = 50; // 屏幕亮度0-100,默认50
- uint8_t Wifi_en = 1; // WIFI模块启动 1:打开 0:关闭
- uint8_t UpdateWeater_en = 0; // 更新时间标志位
- int prevTime = 0; // 滚动显示更新标志位
- int DHT_img_flag = 0; // DHT传感器使用标志位
-
- // EEPROM参数存储地址位
- int BL_addr = 1; // 被写入数据的EEPROM地址编号 1亮度
- int Ro_addr = 2; // 被写入数据的EEPROM地址编号 2 旋转方向
- int DHT_addr = 3; // 3 DHT使能标志位
- int CC_addr = 10; // 被写入数据的EEPROM地址编号 10城市
- int wifi_addr = 30; // 被写入数据的EEPROM地址编号 20wifi-ssid-psw
-
- time_t prevDisplay = 0; // 显示时间显示记录
- int Amimate_reflash_Time = 0; // 更新时间记录
- int Amilove_reflash_Time = 0; // 更新时间记录
-
- /*** Component objects ***/
- WeatherNum wrat;
-
- uint32_t targetTime = 0;
- String cityCode = "101190402"; // 天气城市代码
- int tempnum = 0; // 温度百分比
- int huminum = 0; // 湿度百分比
- int tempcol = 0xffff; // 温度显示颜色
- int humicol = 0xffff; // 湿度显示颜色
-
- // NTP服务器参数
- static const char ntpServerName[] = "ntp3.aliyun.com";
- const int timeZone = 8; // 东八区
-
- // wifi连接UDP设置参数
- WiFiUDP Udp;
- WiFiClient wificlient;
- unsigned int localPort = 8000;
- float duty = 0;
-
- // 星期
- String week()
- {
- String wk[7] = {"日", "一", "二", "三", "四", "五", "六"};
- String s = "周" + wk[weekday() - 1];
- return s;
- }
-
- // 月日
- String monthDay()
- {
- String s = String(month());
- s = s + "月" + day() + "日";
- return s;
- }
-
- /* *****************************************************************
- * 函数
- * *****************************************************************/
-
- // wifi ssid,psw保存到eeprom
- void savewificonfig()
- {
- // 开始写入
- uint8_t *p = (uint8_t *)(&wificonf);
- for (unsigned int i = 0; i < sizeof(wificonf); i++)
- {
- EEPROM.write(i + wifi_addr, *(p + i)); // 在闪存内模拟写入
- }
- delay(10);
- EEPROM.commit(); // 执行写入ROM
- delay(10);
- }
-
- // TFT屏幕输出函数
- bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap)
- {
- if (y >= tft.height())
- return 0;
- tft.pushImage(x, y, w, h, bitmap);
- // Return 1 to decode next block
- return 1;
- }
-
- // 进度条函数
- byte loadNum = 6;
- void loading(byte delayTime) // 绘制进度条
- {
- clk.setColorDepth(8);
-
- clk.createSprite(200, 100); // 创建窗口
- clk.fillSprite(0x0000); // 填充率
-
- clk.drawRoundRect(0, 0, 200, 16, 8, 0xFFFF); // 空心圆角矩形
- clk.fillRoundRect(3, 3, loadNum, 10, 5, 0xFFFF); // 实心圆角矩形
- clk.setTextDatum(CC_DATUM); // 设置文本数据
- clk.setTextColor(TFT_GREEN, 0x0000);
- clk.drawString("Connecting to WiFi......", 100, 40, 2);
- clk.setTextColor(TFT_WHITE, 0x0000);
- clk.drawRightString(Version, 180, 60, 2);
- clk.pushSprite(20, 120); // 窗口位置
-
- // clk.setTextDatum(CC_DATUM);
- // clk.setTextColor(TFT_WHITE, 0x0000);
- // clk.pushSprite(130,180);
-
- clk.deleteSprite();
- loadNum += 1;
- delay(delayTime);
- }
-
- // 湿度图标显示函数
- void humidityWin()
- {
- clk.setColorDepth(8);
-
- huminum = huminum / 2;
- clk.createSprite(52, 6); // 创建窗口
- clk.fillSprite(0x0000); // 填充率
- clk.drawRoundRect(0, 0, 52, 6, 3, 0xFFFF); // 空心圆角矩形 起始位x,y,长度,宽度,圆弧半径,颜色
- clk.fillRoundRect(1, 1, huminum, 4, 2, humicol); // 实心圆角矩形
- clk.pushSprite(45, 222); // 窗口位置
- clk.deleteSprite();
- }
-
- // 温度图标显示函数
- void tempWin()
- {
- clk.setColorDepth(8);
-
- clk.createSprite(52, 6); // 创建窗口
- clk.fillSprite(0x0000); // 填充率
- clk.drawRoundRect(0, 0, 52, 6, 3, 0xFFFF); // 空心圆角矩形 起始位x,y,长度,宽度,圆弧半径,颜色
- clk.fillRoundRect(1, 1, tempnum, 4, 2, tempcol); // 实心圆角矩形
- clk.pushSprite(45, 192); // 窗口位置
- clk.deleteSprite();
- }
-
- #if WM_EN
- // WEB配网LCD显示函数
- void Web_win()
- {
- clk.setColorDepth(8);
-
- clk.createSprite(200, 60); // 创建窗口
- clk.fillSprite(0x0000); // 填充率
-
- clk.setTextDatum(CC_DATUM); // 设置文本数据
- clk.setTextColor(TFT_GREEN, 0x0000);
- clk.drawString("WiFi Connect Fail!", 100, 10, 2);
- clk.drawString("SSID:", 45, 40, 2);
- clk.setTextColor(TFT_WHITE, 0x0000);
- clk.drawString("AutoConnectAP", 125, 40, 2);
- clk.pushSprite(20, 50); // 窗口位置
-
- clk.deleteSprite();
-
- }
-
- // WEB配网函数
- void Webconfig()
- {
- WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP
-
- delay(3000);
- wm.resetSettings(); // wipe settings
-
- // add a custom input field
- // int customFieldLength = 40;
-
- // new (&custom_field) WiFiManagerParameter("customfieldid", "Custom Field Label", "Custom Field Value", customFieldLength,"placeholder=\"Custom Field Placeholder\"");
-
- // test custom html input type(checkbox)
- // new (&custom_field) WiFiManagerParameter("customfieldid", "Custom Field Label", "Custom Field Value", customFieldLength,"placeholder=\"Custom Field Placeholder\" type=\"checkbox\""); // custom html type
-
- // test custom html(radio)
- // const char* custom_radio_str = "
One
Two
Three"; - // new (&custom_field) WiFiManagerParameter(custom_radio_str); // custom html input
-
- const char *set_rotation = "
\ - USB接口朝下
\ - USB接口朝右
\ - USB接口朝上
\ - USB接口朝左
"; - WiFiManagerParameter custom_rot(set_rotation); // custom html input
- WiFiManagerParameter custom_bl("LCDBL", "屏幕亮度(1-100)", "10", 3);
- #if DHT_EN
- WiFiManagerParameter custom_DHT11_en("DHT11_en", "Enable DHT11 sensor", "0", 1);
- #endif
- WiFiManagerParameter custom_weatertime("WeaterUpdateTime", "天气刷新时间(分钟)", "10", 3);
- WiFiManagerParameter custom_cc("CityCode", "城市代码", "0", 9);
- WiFiManagerParameter custom_bir("birthday", "生日", "0", 8);
- WiFiManagerParameter p_lineBreak_notext("");
-
- // wm.addParameter(&p_lineBreak_notext);
- // wm.addParameter(&custom_field);
- wm.addParameter(&p_lineBreak_notext);
- wm.addParameter(&custom_cc);
- wm.addParameter(&p_lineBreak_notext);
- wm.addParameter(&custom_bl);
- wm.addParameter(&p_lineBreak_notext);
- wm.addParameter(&custom_weatertime);
- wm.addParameter(&p_lineBreak_notext);
- wm.addParameter(&custom_rot);
- wm.addParameter(&p_lineBreak_notext);
- wm.addParameter(&custom_bir);
- #if DHT_EN
- wm.addParameter(&p_lineBreak_notext);
- wm.addParameter(&custom_DHT11_en);
- #endif
- wm.setSaveParamsCallback(saveParamCallback);
-
- // custom menu via array or vector
- //
- // menu tokens, "wifi","wifinoscan","info","param","close","sep","erase","restart","exit" (sep is seperator) (if param is in menu, params will not show up in wifi page!)
- // const char* menu[] = {"wifi","info","param","sep","restart","exit"};
- // wm.setMenu(menu,6);
- std::vector<const char *> menu = {"wifi", "restart"};
- wm.setMenu(menu);
-
- // set dark theme
- wm.setClass("invert");
-
- // set static ip
- // wm.setSTAStaticIPConfig(IPAddress(10,0,1,99), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); // set static ip,gw,sn
- // wm.setShowStaticFields(true); // force show static ip fields
- // wm.setShowDnsFields(true); // force show dns field always
-
- // wm.setConnectTimeout(20); // how long to try to connect for before continuing
- // wm.setConfigPortalTimeout(30); // auto close configportal after n seconds
- // wm.setCaptivePortalEnable(false); // disable captive portal redirection
- // wm.setAPClientCheck(true); // avoid timeout if client connected to softap
-
- // wifi scan settings
- // wm.setRemoveDuplicateAPs(false); // do not remove duplicate ap names (true)
- wm.setMinimumSignalQuality(20); // set min RSSI (percentage) to show in scans, null = 8%
- // wm.setShowInfoErase(false); // do not show erase button on info page
- // wm.setScanDispPerc(true); // show RSSI as percentage not graph icons
-
- // wm.setBreakAfterConfig(true); // always exit configportal even if wifi save fails
-
- bool res;
- // res = wm.autoConnect(); // auto generated AP name from chipid
- res = wm.autoConnect("AutoConnectAP"); // anonymous ap
- // res = wm.autoConnect("AutoConnectAP","password"); // password protected ap
-
- while (!res)
- ;
- }
-
- String getParam(String name)
- {
- // read parameter from server, for customhmtl input
- String value;
- if (wm.server->hasArg(name))
- {
- value = wm.server->arg(name);
- }
- return value;
- }
-
- // 删除原有eeprom中的信息
- void deletewificonfig()
- {
- config_type deletewifi = {{""}, {""}};
- uint8_t *p = (uint8_t *)(&deletewifi);
- for (unsigned int i = 0; i < sizeof(deletewifi); i++)
- {
- EEPROM.write(i + wifi_addr, *(p + i)); // 在闪存内模拟写入
- }
- delay(10);
- EEPROM.commit(); // 执行写入ROM
- delay(10);
- }
-
- // 从eeprom读取WiFi信息ssid,psw
- void readwificonfig()
- {
- uint8_t *p = (uint8_t *)(&wificonf);
- for (unsigned int i = 0; i < sizeof(wificonf); i++)
- {
- *(p + i) = EEPROM.read(i + wifi_addr);
- }
- // EEPROM.commit();
- // ssid = wificonf.stassid;
- // pass = wificonf.stapsw;
- Serial.printf("Read WiFi Config.....\r\n");
- Serial.printf("SSID:%s\r\n", wificonf.stassid);
- Serial.printf("PSW:%s\r\n", wificonf.stapsw);
- Serial.printf("Connecting.....\r\n");
- }
-
- void saveParamCallback()
- {
- int CCODE = 0, cc;
-
- Serial.println("[CALLBACK] saveParamCallback fired");
- // Serial.println("PARAM customfieldid = " + getParam("customfieldid"));
- // Serial.println("PARAM CityCode = " + getParam("CityCode"));
- // Serial.println("PARAM LCD BackLight = " + getParam("LCDBL"));
- // Serial.println("PARAM WeaterUpdateTime = " + getParam("WeaterUpdateTime"));
- // Serial.println("PARAM Rotation = " + getParam("set_rotation"));
- // Serial.println("PARAM DHT11_en = " + getParam("DHT11_en"));
- // 将从页面中获取的数据保存
-
- updateweater_time = getParam("WeaterUpdateTime").toInt();
- cc = getParam("CityCode").toInt();
- LCD_Rotation = getParam("set_rotation").toInt();
- LCD_BL_PWM = getParam("LCDBL").toInt();
-
- // 对获取的数据进行处理
- // 城市代码
- Serial.print("CityCode = ");
- Serial.println(cc);
- if (((cc >= 101000000) && (cc <= 102000000)) || (cc == 0))
- {
- for (int cnum = 0; cnum < 5; cnum++)
- {
- EEPROM.write(CC_addr + cnum, cc % 100); // 城市地址写入城市代码
- EEPROM.commit(); // 保存更改的数据
- cc = cc / 100;
- delay(5);
- }
- for (int cnum = 5; cnum > 0; cnum--)
- {
- CCODE = CCODE * 100;
- CCODE += EEPROM.read(CC_addr + cnum - 1);
- delay(5);
- }
- cityCode = CCODE;
- }
- // 屏幕方向
- Serial.print("LCD_Rotation = ");
- Serial.println(LCD_Rotation);
- if (EEPROM.read(Ro_addr) != LCD_Rotation)
- {
- EEPROM.write(Ro_addr, LCD_Rotation);
- EEPROM.commit();
- delay(5);
- }
- tft.setRotation(LCD_Rotation);
- tft.fillScreen(0x0000);
- Web_win();
- loadNum--;
- loading(1);
- if (EEPROM.read(BL_addr) != LCD_BL_PWM)
- {
- EEPROM.write(BL_addr, LCD_BL_PWM);
- EEPROM.commit();
- delay(5);
- }
- // 屏幕亮度
- Serial.printf("亮度调整为:");
- analogWrite(LCD_BL_PIN, 1023 - (LCD_BL_PWM * 10));
- Serial.println(LCD_BL_PWM);
- // 天气更新时间
- Serial.printf("天气更新时间调整为:");
- Serial.println(updateweater_time);
- }
- #endif
-
- // 发送HTTP请求并且将服务器响应通过串口输出
- void getCityCode()
- {
- String URL = "http://wgeo.weather.com.cn/ip/?_=" + String(now());
- // 创建 HTTPClient 对象
- HTTPClient httpClient;
-
- // 配置请求地址。此处也可以不使用端口号和PATH而单纯的
- httpClient.begin(wificlient, URL);
-
- // 设置请求头中的User-Agent
- httpClient.setUserAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1");
- httpClient.addHeader("Referer", "http://www.weather.com.cn/");
-
- // 启动连接并发送HTTP请求
- int httpCode = httpClient.GET();
- Serial.print("Send GET request to URL: ");
- Serial.println(URL);
-
- // 如果服务器响应OK则从服务器获取响应体信息并通过串口输出
- if (httpCode == HTTP_CODE_OK)
- {
- String str = httpClient.getString();
-
- int aa = str.indexOf("id=");
- if (aa > -1)
- {
- // cityCode = str.substring(aa+4,aa+4+9).toInt();
- cityCode = str.substring(aa + 4, aa + 4 + 9);
- Serial.println(cityCode);
- getCityWeater();
- }
- else
- {
- Serial.println("获取城市代码失败");
- }
- }
- else
- {
- Serial.println("请求城市代码错误:");
- Serial.println(httpCode);
- }
-
- // 关闭ESP8266与服务器连接
- httpClient.end();
- }
-
- // 获取城市天气
- void getCityWeater()
- {
- // String URL = "http://d1.weather.com.cn/dingzhi/" + cityCode + ".html?_="+String(now());//新
- String URL = "http://d1.weather.com.cn/weather_index/" + cityCode + ".html?_=" + String(now()); // 原来
- // 创建 HTTPClient 对象
- HTTPClient httpClient;
-
- // httpClient.begin(URL);
- httpClient.begin(wificlient, URL); // 使用新方法
-
- // 设置请求头中的User-Agent
- httpClient.setUserAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1");
- httpClient.addHeader("Referer", "http://www.weather.com.cn/");
-
- // 启动连接并发送HTTP请求
- int httpCode = httpClient.GET();
- Serial.println("正在获取天气数据");
- Serial.println(URL);
-
- // 如果服务器响应OK则从服务器获取响应体信息并通过串口输出
- if (httpCode == HTTP_CODE_OK)
- {
-
- String str = httpClient.getString();
- // Serial.println("httpdata=" + str);
- int indexStart = str.indexOf("weatherinfo\":");
- int indexEnd = str.indexOf("};var alarmDZ");
-
- weather_msg.cityDZ = str.substring(indexStart + 13, indexEnd);
- // Serial.println(jsonCityDZ);
-
- indexStart = str.indexOf("dataSK =");
- indexEnd = str.indexOf(";var dataZS");
- weather_msg.dataSK = str.substring(indexStart + 8, indexEnd);
- // Serial.println(jsonDataSK);
-
- indexStart = str.indexOf("\"f\":[");
- indexEnd = str.indexOf(",{\"fa");
- weather_msg.dataFC = str.substring(indexStart + 5, indexEnd);
- // Serial.println(jsonFC);
-
- // weaterData(&jsonCityDZ, &jsonDataSK, &jsonFC);
- weaterData(&(weather_msg.cityDZ), &(weather_msg.dataSK), &(weather_msg.dataFC));
- Serial.println("获取成功");
- }
- else
- {
- Serial.println("请求城市天气错误:");
- Serial.print(httpCode);
- }
-
- // 关闭ESP8266与服务器连接
- httpClient.end();
- }
-
- String scrollText[7];
- // int scrollTextWidth = 0;
-
- // 天气信息写到屏幕上
- void weaterData(String *cityDZ, String *dataSK, String *dataFC)
- {
- // 解析第一段JSON
- DynamicJsonDocument doc(1024);
- deserializeJson(doc, *dataSK);
- JsonObject sk = doc.as
(); -
- // TFT_eSprite clkb = TFT_eSprite(&tft);
- String temperature = sk["temp"].as
(); - /***绘制相关文字***/
- // if (xSemaphoreTake(xMutex, portMAX_DELAY))
- // {
- // clk.setColorDepth(8);
- // clk.loadFont(ZdyLwFont_20);
-
- // // 温度
- // clk.createSprite(58, 24);
- // clk.fillSprite(bgColor);
- // clk.setTextDatum(CC_DATUM);
- // clk.setTextColor(TFT_WHITE, bgColor);
- // clk.drawString(sk["temp"].as
() + "℃", 28, 13); - // clk.pushSprite(100, 184);
- // clk.deleteSprite();
- // xSemaphoreGive(xMutex);
- // }
- tempnum = sk["temp"].as<int>();
- tempnum = tempnum + 10;
- if (tempnum < 10)
- tempcol = 0x00FF;
- else if (tempnum < 28)
- tempcol = 0x0AFF;
- else if (tempnum < 34)
- tempcol = 0x0F0F;
- else if (tempnum < 41)
- tempcol = 0xFF0F;
- else if (tempnum < 49)
- tempcol = 0xF00F;
- else
- {
- tempcol = 0xF00F;
- tempnum = 50;
- }
- // if (xSemaphoreTake(xMutex, portMAX_DELAY))
- // {
- // tempWin();
-
- // // 湿度
- // clk.createSprite(58, 24);
- // clk.fillSprite(bgColor);
- // clk.setTextDatum(CC_DATUM);
- // clk.setTextColor(TFT_WHITE, bgColor);
- // clk.drawString(sk["SD"].as
(), 28, 13); -
- // // clk.drawString("100%",28,13);
- // clk.pushSprite(100, 214);
- // clk.deleteSprite();
- // xSemaphoreGive(xMutex);
- // }
- // String A = sk["SD"].as
(); - String huminit = sk["SD"].as
(); - huminum = atoi((sk["SD"].as
()).substring(0, 2).c_str()); -
- if (huminum > 90)
- humicol = 0x00FF;
- else if (huminum > 70)
- humicol = 0x0AFF;
- else if (huminum > 40)
- humicol = 0x0F0F;
- else if (huminum > 20)
- humicol = 0xFF0F;
- else
- humicol = 0xF00F;
- // if (xSemaphoreTake(xMutex, portMAX_DELAY))
- // {
- // humidityWin();
-
- // // 城市名称
- // clk.createSprite(94, 30);
- // clk.fillSprite(bgColor);
- // clk.setTextDatum(CC_DATUM);
- // clk.setTextColor(TFT_WHITE, bgColor);
- // clk.drawString(sk["cityname"].as
(), 44, 16); - // clk.pushSprite(15, 15);
- // clk.deleteSprite();
- // xSemaphoreGive(xMutex);
- // }
- // PM2.5空气指数
- String cityname = sk["cityname"].as
(); - uint16_t pm25BgColor = tft.color565(156, 202, 127); // 优
- String aqiTxt = "优";
- int pm25V = sk["aqi"];
- if (pm25V > 200)
- {
- pm25BgColor = tft.color565(136, 11, 32); // 重度
- aqiTxt = "重度";
- }
- else if (pm25V > 150)
- {
- pm25BgColor = tft.color565(186, 55, 121); // 中度
- aqiTxt = "中度";
- }
- else if (pm25V > 100)
- {
- pm25BgColor = tft.color565(242, 159, 57); // 轻
- aqiTxt = "轻度";
- }
- else if (pm25V > 50)
- {
- pm25BgColor = tft.color565(247, 219, 100); // 良
- aqiTxt = "良";
- }
-
- scrollText[0] = "实时天气 " + sk["weather"].as
(); - scrollText[1] = "空气质量 " + aqiTxt;
- scrollText[2] = "风向 " + sk["WD"].as
() + sk["WS"].as(); -
-
- // 左上角滚动字幕
- // 解析第二段JSON
- deserializeJson(doc, *cityDZ);
- JsonObject dz = doc.as
(); - // Serial.println(sk["ws"].as
()); - // 横向滚动方式
- // String aa = "今日天气:" + dz["weather"].as
() + ",温度:最低" + dz["tempn"].as() + ",最高" + dz["temp"].as() + " 空气质量:" + aqiTxt + ",风向:" + dz["wd"].as() + dz["ws"].as(); - // scrollTextWidth = clk.textWidth(scrollText);
- // Serial.println(aa);
- scrollText[3] = "今日" + dz["weather"].as
(); -
- deserializeJson(doc, *dataFC);
- JsonObject fc = doc.as
(); -
- scrollText[4] = "最低温度" + fc["fd"].as
() + "℃"; - scrollText[5] = "最高温度" + fc["fc"].as
() + "℃"; -
- if (xSemaphoreTake(xMutex, portMAX_DELAY))
- {
- clk.setColorDepth(8);
- clk.loadFont(ZdyLwFont_20);
-
- // 温度
- clk.createSprite(58, 24);
- clk.fillSprite(bgColor);
- clk.setTextDatum(CC_DATUM);
- clk.setTextColor(TFT_WHITE, bgColor);
- clk.drawString(temperature + "℃", 28, 13);
- clk.pushSprite(100, 184);
- clk.deleteSprite();
- tempWin();
- // 湿度
- clk.createSprite(58, 24);
- clk.fillSprite(bgColor);
- clk.setTextDatum(CC_DATUM);
- clk.setTextColor(TFT_WHITE, bgColor);
- clk.drawString(huminit, 28, 13);
- // clk.drawString("100%",28,13);
- clk.pushSprite(100, 214);
- clk.deleteSprite();
- humidityWin();
- // 城市名称
- clk.createSprite(94, 30);
- clk.fillSprite(bgColor);
- clk.setTextDatum(CC_DATUM);
- clk.setTextColor(TFT_WHITE, bgColor);
- clk.drawString(cityname, 44, 16);
- clk.pushSprite(15, 15);
- clk.deleteSprite();
-
- clk.createSprite(56, 24);
- clk.fillSprite(bgColor);
- clk.fillRoundRect(0, 0, 50, 24, 4, pm25BgColor);
- clk.setTextDatum(CC_DATUM);
- clk.setTextColor(0x0000);
- clk.drawString(aqiTxt, 25, 13);
- clk.pushSprite(104, 18);
- clk.deleteSprite();
- // 天气图标
- wrat.printfweather(170, 15, atoi((sk["weathercode"].as
()).substring(1, 3).c_str())); - clk.unloadFont();
- xSemaphoreGive(xMutex);
- }
- }
-
- int currentIndex = 0;
- TFT_eSprite clkb = TFT_eSprite(&tft);
-
- void scrollBanner()
- {
- // if(millis() - prevTime > 2333) //3秒切换一次
- // if(second()%2 ==0&& prevTime == 0)
- // {
- if (scrollText[currentIndex])
- {
-
- if (xSemaphoreTake(xMutex, portMAX_DELAY))
- {
- clkb.setColorDepth(8);
- clkb.loadFont(ZdyLwFont_20);
- clkb.createSprite(150, 30);
- clkb.fillSprite(bgColor);
- clkb.setTextWrap(false);
- clkb.setTextDatum(CC_DATUM);
- clkb.setTextColor(TFT_WHITE, bgColor);
- clkb.drawString(scrollText[currentIndex], 74, 16);
- clkb.pushSprite(10, 45);
-
- clkb.deleteSprite();
- clkb.unloadFont();
- xSemaphoreGive(xMutex);
- }
- if (currentIndex >= 5)
- currentIndex = 0; // 回第一个
- else
- currentIndex += 1; // 准备切换到下一个
- }
- prevTime = 1;
- // }
- }
- // 用快速线方法绘制数字
- void drawLineFont(uint32_t _x, uint32_t _y, uint32_t _num, uint32_t _size, uint32_t _color)
- {
- uint32_t fontSize;
- const LineAtom *fontOne;
- // 小号(9*14)
- if (_size == 1)
- {
- fontOne = smallLineFont[_num];
- fontSize = smallLineFont_size[_num];
- // 绘制前清理字体绘制区域
- tft.fillRect(_x, _y, 9, 14, TFT_BLACK);
- }
- // 中号(18*30)
- else if (_size == 2)
- {
- fontOne = middleLineFont[_num];
- fontSize = middleLineFont_size[_num];
- // 绘制前清理字体绘制区域
- tft.fillRect(_x, _y, 18, 30, TFT_BLACK);
- }
- // 大号(36*90)
- else if (_size == 3)
- {
- fontOne = largeLineFont[_num];
- fontSize = largeLineFont_size[_num];
- // 绘制前清理字体绘制区域
- tft.fillRect(_x, _y, 36, 90, TFT_BLACK);
- }
- else
- return;
-
- for (uint32_t i = 0; i < fontSize; i++)
- {
- tft.drawFastHLine(fontOne[i].xValue + _x, fontOne[i].yValue + _y, fontOne[i].lValue, _color);
- }
- }
-
- int Hour_sign = 60;
- int Minute_sign = 60;
- int Second_sign = 60;
- // 日期刷新
- void digitalClockDisplay(int reflash_en = 0)
- {
- // 时钟刷新,输入1强制刷新
- int now_hour = hour(); // 获取小时
- int now_minute = minute(); // 获取分钟
- int now_second = second(); // 获取秒针
- // 小时刷新
- if ((now_hour != Hour_sign) || (reflash_en == 1))
- {
- if (xSemaphoreTake(xMutex, portMAX_DELAY))
- {
- drawLineFont(20, timeY, now_hour / 10, 3, SD_FONT_WHITE);
- drawLineFont(60, timeY, now_hour % 10, 3, SD_FONT_WHITE);
- Hour_sign = now_hour;
- xSemaphoreGive(xMutex);
- }
- }
- // 分钟刷新
- if ((now_minute != Minute_sign) || (reflash_en == 1))
- {
- if (xSemaphoreTake(xMutex, portMAX_DELAY))
- {
- drawLineFont(101, timeY, now_minute / 10, 3, SD_FONT_YELLOW);
- drawLineFont(141, timeY, now_minute % 10, 3, SD_FONT_YELLOW);
- Minute_sign = now_minute;
- xSemaphoreGive(xMutex);
- }
- }
- // 秒针刷新
- if ((now_second != Second_sign) || (reflash_en == 1)) // 分钟刷新
- {
-
- if (xSemaphoreTake(xMutex, portMAX_DELAY))
- {
- drawLineFont(182, timeY + 30, now_second / 10, 2, SD_FONT_WHITE);
- drawLineFont(202, timeY + 30, now_second % 10, 2, SD_FONT_WHITE);
- Second_sign = now_second;
- xSemaphoreGive(xMutex);
- }
- }
-
- if (reflash_en == 1)
- reflash_en = 0;
- /***日期****/
- if (xSemaphoreTake(xMutex, portMAX_DELAY))
- {
- clk.setColorDepth(8);
- clk.loadFont(ZdyLwFont_20);
-
- // 星期
- clk.createSprite(58, 30);
- clk.fillSprite(bgColor);
- clk.setTextDatum(CC_DATUM);
- clk.setTextColor(TFT_WHITE, bgColor);
- clk.drawString(week(), 29, 16);
- clk.pushSprite(102, 150);
- clk.deleteSprite();
-
- // 月日
- clk.createSprite(95, 30);
- clk.fillSprite(bgColor);
- clk.setTextDatum(CC_DATUM);
- clk.setTextColor(TFT_WHITE, bgColor);
- clk.drawString(monthDay(), 49, 16);
- clk.pushSprite(5, 150);
- clk.deleteSprite();
-
- clk.unloadFont();
- xSemaphoreGive(xMutex);
- }
- }
-
- /*-------- NTP code ----------*/
-
- const int NTP_PACKET_SIZE = 48; // NTP时间在消息的前48字节中
- byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming & outgoing packets
-
- time_t getNtpTime()
- {
- IPAddress ntpServerIP; // NTP server's ip address
-
- while (Udp.parsePacket() > 0)
- ;
- // discard any previously received packets
- // Serial.println("Transmit NTP Request");
- // get a random server from the pool
- WiFi.hostByName(ntpServerName, ntpServerIP);
- // Serial.print(ntpServerName);
- // Serial.print(": ");
- // Serial.println(ntpServerIP);
-
- sendNTPpacket(ntpServerIP);
-
- uint32_t beginWait = millis();
- while (millis() - beginWait < 1500)
- {
- int size = Udp.parsePacket();
-
- if (size >= NTP_PACKET_SIZE)
- {
- Serial.println("Receive NTP Response");
- Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
- unsigned long secsSince1900;
- // convert four bytes starting at location 40 to a long integer
- secsSince1900 = (unsigned long)packetBuffer[40] << 24;
- secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
- secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
- secsSince1900 |= (unsigned long)packetBuffer[43];
- // Serial.println(secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR);
- return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
- }
- }
- Serial.println("No NTP Response :-(");
- return 0; // 无法获取时间时返回0
- }
-
- // 向NTP服务器发送请求
- void sendNTPpacket(IPAddress & address)
- {
- // set all bytes in the buffer to 0
- memset(packetBuffer, 0, NTP_PACKET_SIZE);
- // Initialize values needed to form NTP request
- // (see URL above for details on the packets)
- packetBuffer[0] = 0b11100011; // LI, Version, Mode
- packetBuffer[1] = 0; // Stratum, or type of clock
- packetBuffer[2] = 6; // Polling Interval
- packetBuffer[3] = 0xEC; // Peer Clock Precision
- // 8 bytes of zero for Root Delay & Root Dispersion
- packetBuffer[12] = 49;
- packetBuffer[13] = 0x4E;
- packetBuffer[14] = 49;
- packetBuffer[15] = 52;
- // all NTP fields have been given values, now
- // you can send a packet requesting a timestamp:
- Udp.beginPacket(address, 123); // NTP requests are to port 123
- Udp.write(packetBuffer, NTP_PACKET_SIZE);
- Udp.endPacket();
- }
-
- void esp_reset(Button2 & btn)
- {
- ESP.restart();
- }
-
- void wifi_reset(Button2 & btn)
- {
- wm.resetSettings();
- deletewificonfig();
- delay(10);
- Serial.println("重置WiFi成功");
- ESP.restart();
- }
-
- // 更新时间
- void reflashTime()
- {
- prevDisplay = now();
- // timeClockDisplay(1);
- digitalClockDisplay();
- prevTime = 0;
- }
-
- // 切换天气 or 空气质量
- void reflashBanner()
- {
- scrollBanner();
- }
-
- // 打开WIFI
- void openWifi()
- {
- Serial.println("WIFI reset......");
- // WiFi.forceSleepWake(); // wifi on
- Wifi_en = 1;
- }
-
- // 强制屏幕刷新
- void LCD_reflash()
- {
- reflashTime();
- reflashBanner();
- openWifi();
- }
-
- // 清空屏幕
- void clear_screen()
- {
- tft.fillScreen(bgColor);
- }
-
- void currentWeather(void *param)
- {
- Serial.println("weather");
- while (1)
- {
- getCityWeater();
- vTaskDelay(1000 * 60 * 5);
- }
- }
-
- const uint8_t *Animate_value; // 指向关键帧的指针
- uint32_t Animate_size; // 指向关键帧大小的指针
- int Animate_key = -1;
- void refresh_AnimatedImage(void *)
- {
- while (1)
- {
- if (millis() - Amimate_reflash_Time > 100) // x ms切换一次
- {
- Animate_key++;
- Amimate_reflash_Time = millis();
- Animate_value = hutao[Animate_key];
- Animate_size = hutao_size[Animate_key];
- if (xSemaphoreTake(xMutex, portMAX_DELAY))
- {
- // Serial.println("xSemaphoreTake in");
- TJpgDec.drawJpg(160, 160, Animate_value, Animate_size);
- xSemaphoreGive(xMutex);
- // Serial.println("xSemaphoreTake out");
- }
- if (Animate_key >= 31)
- {
- Animate_key = -1;
- }
- vTaskDelay(pdMS_TO_TICKS(100));
- }
- }
- }
- void buttonLoop(void *param)
- {
- Serial.println("button");
- while (1)
- {
- Button_sw1.loop();
- vTaskDelay(pdMS_TO_TICKS(500));
- }
- }
- // 切换天气 or 空气质量
- void reflashBanner(void *param)
- {
- Serial.println("scroller");
- while (1)
- {
-
- scrollBanner();
- vTaskDelay(pdMS_TO_TICKS(5000));
- }
- }
- void currentTime(void *pvParameters)
- {
- Serial.println("time");
- while (1)
- {
- digitalClockDisplay();
- vTaskDelay(pdMS_TO_TICKS(100));
- }
- }
- // void syncTime(void *param)
- // {
-
- // while (1)
- // {
- // // if (!getLocalTime(&timeinfo))
- // // {
- // // Serial.println("Failed to obtain time");
- // // return;
- // // }
- // // setTime(timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, timeinfo.tm_mday, timeinfo.tm_mon + 1, timeinfo.tm_year + 1900);
- // //getNtpTime();
- // setSyncProvider(getNtpTime);
- // vTaskDelay(pdMS_TO_TICKS(1000 * 60 * 4));
- // }
- // }
- void setup()
- {
- xMutex = xSemaphoreCreateMutex();
- Button_sw1.setLongClickHandler(wifi_reset);
- // 设置消抖时间
-
- Serial.begin(115200);
- EEPROM.begin(1024);
-
- // WiFi.forceSleepWake();
- // wm.resetSettings(); //在初始化中使wifi重置,需重新配置WiFi
-
- // 从eeprom读取背光亮度设置
- if (EEPROM.read(BL_addr) > 0 && EEPROM.read(BL_addr) < 100)
- LCD_BL_PWM = EEPROM.read(BL_addr);
- // 从eeprom读取屏幕方向设置
- if (EEPROM.read(Ro_addr) >= 0 && EEPROM.read(Ro_addr) <= 3)
- LCD_Rotation = EEPROM.read(Ro_addr);
-
- pinMode(LCD_BL_PIN, OUTPUT);
- analogWrite(LCD_BL_PIN, 1023 - (LCD_BL_PWM * 10));
-
- tft.begin(); /* TFT init */
- tft.invertDisplay(1); // 反转所有显示颜色:1反转,0正常
- tft.setRotation(LCD_Rotation);
- tft.fillScreen(0x0000);
- tft.setTextColor(TFT_BLACK, bgColor);
-
- targetTime = millis() + 1000;
- readwificonfig(); // 读取存储的wifi信息
- Serial.print("正在连接WIFI ");
- Serial.println(wificonf.stassid);
- WiFi.begin(wificonf.stassid, wificonf.stapsw);
-
- TJpgDec.setJpgScale(1);
- TJpgDec.setSwapBytes(true);
- TJpgDec.setCallback(tft_output);
-
- while (WiFi.status() != WL_CONNECTED)
- {
- loading(30);
-
- if (loadNum >= 194)
- {
- // 使能web配网后自动将smartconfig配网失效
- #if WM_EN
- Web_win();
- Webconfig();
- #endif
-
- #if !WM_EN
- SmartConfig();
- #endif
- break;
- }
- }
- delay(10);
- while (loadNum < 194) // 让动画走完
- {
- loading(1);
- }
-
- if (WiFi.status() == WL_CONNECTED)
- {
- Serial.print("SSID:");
- Serial.println(WiFi.SSID().c_str());
- Serial.print("PSW:");
- Serial.println(WiFi.psk().c_str());
- strcpy(wificonf.stassid, WiFi.SSID().c_str()); // 名称复制
- strcpy(wificonf.stapsw, WiFi.psk().c_str()); // 密码复制
- savewificonfig();
- readwificonfig();
- }
-
- Serial.print("本地IP: ");
- Serial.println(WiFi.localIP());
- Serial.println("启动UDP");
- Udp.begin(localPort);
- Serial.println("等待同步...");
- setSyncProvider(getNtpTime);
- setSyncInterval(300);
- //getNtpTime();
- //configTime(gmtOffset_sec, daylightOffset_sec, ntpServerName);
- TJpgDec.setJpgScale(1);
- TJpgDec.setSwapBytes(true);
- TJpgDec.setCallback(tft_output);
-
- int CityCODE = 0;
- for (int cnum = 5; cnum > 0; cnum--)
- {
- CityCODE = CityCODE * 100;
- CityCODE += EEPROM.read(CC_addr + cnum - 1);
- delay(5);
- }
- if (CityCODE >= 101000000 && CityCODE <= 102000000)
- cityCode = CityCODE;
- else
- getCityCode(); // 获取城市代码
-
- tft.fillScreen(TFT_BLACK); // 清屏
- TJpgDec.drawJpg(15, 183, temperature, sizeof(temperature)); // 温度图标
- TJpgDec.drawJpg(15, 213, humidity, sizeof(humidity)); // 湿度图标
-
- getCityWeater();
-
- // WiFi.forceSleepBegin(); // wifi off
- Serial.println("WIFI休眠......");
- Wifi_en = 0;
-
- xTaskCreatePinnedToCore(currentWeather, "weather", 8192, NULL, 1, NULL, 1);
- xTaskCreatePinnedToCore(refresh_AnimatedImage, "Animate", 2048, NULL, 2, NULL, 1);
- xTaskCreatePinnedToCore(buttonLoop, "button", 2048, NULL, 1, NULL, 1);
- xTaskCreatePinnedToCore(reflashBanner, "scroller", 2048, NULL, 1, NULL, 1);
- xTaskCreatePinnedToCore(currentTime, "timer", 2048, NULL, 3, NULL, 1);
- //xTaskCreatePinnedToCore(syncTime, "syncTime", 2048, NULL, 1, NULL, 1);
- }
-
- void loop()
- {
-
- }
显示效果如下
参考:指针阿飞