• esp32 桌面小电视项目(基于freertos)(六)


    目录

    前言

    主要功能

    使用方法

    代码

    显示效果


    前言

    本文基于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自动重启开始联网。

    代码

    代码如下。

    1. /* *****************************************************************
    2. *
    3. *
    4. * 小型桌面显示器
    5. *
    6. * 现作者:大益
    7. * 原 作 者:指针阿飞
    8. *
    9. * 创 建 日 期:2024.4.22
    10. *
    11. *
    12. *
    13. *
    14. * *****************************************************************/
    15. /* *****************************************************************
    16. * 库文件、头文件
    17. * *****************************************************************/
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include //内存
    27. #include //按钮库
    28. #include
    29. #include
    30. #include "config.h" //配置文件
    31. #include "weatherNum/weatherNum.h" //天气图库
    32. #include "Animate/Animate.h" //动画模块
    33. #include "wifiReFlash/wifiReFlash.h" //WIFI功能模块
    34. #include "Animate/img/hutao.h"
    35. #define Version "v1.0.0"
    36. /* *****************************************************************
    37. * 配置使能位
    38. * *****************************************************************/
    39. #if WM_EN
    40. #include
    41. // WiFiManager 参数
    42. WiFiManager wm; // global wm instance
    43. // WiFiManagerParameter custom_field; // global param ( for non blocking w params )
    44. #endif
    45. // 定义按钮引脚
    46. Button2 Button_sw1 = Button2(15);
    47. /* *****************************************************************
    48. * 字库、图片库
    49. * *****************************************************************/
    50. #include "font/ZdyLwFont_20.h" //字体库
    51. #include "font/timeClockFont.h" //字体库
    52. #include "font/Chancery_L_20.h" //字体库
    53. #include "img/temperature.h" //温度图标
    54. #include "img/humidity.h" //湿度图标
    55. #include "font/KT_20.h"
    56. SemaphoreHandle_t xMutex; // 互斥锁句柄
    57. // struct tm timeinfo;
    58. // const long gmtOffset_sec = 8 * 3600;
    59. // const int daylightOffset_sec = 0;
    60. /* *****************************************************************
    61. * 函数声明
    62. * *****************************************************************/
    63. void sendNTPpacket(IPAddress &address); // 向NTP服务器发送请求
    64. time_t getNtpTime(); // 从NTP获取时间
    65. void digitalClockDisplay(int reflash_en);
    66. void printDigits(int digits);
    67. void LCD_reflash();
    68. void clear_screen();
    69. void savewificonfig(); // wifi ssid,psw保存到eeprom
    70. void readwificonfig(); // 从eeprom读取WiFi信息ssid,psw
    71. void deletewificonfig(); // 删除原有eeprom中的信息
    72. void getCityCode(); // 发送HTTP请求并且将服务器响应通过串口输出
    73. void getCityWeater(); // 获取城市天气
    74. void wifi_reset(Button2 &btn); // WIFI重设
    75. void saveParamCallback();
    76. void esp_reset(Button2 &btn);
    77. void scrollBanner();
    78. void weaterData(String *cityDZ, String *dataSK, String *dataFC); // 天气信息写到屏幕上
    79. /* *****************************************************************
    80. * 参数设置
    81. * *****************************************************************/
    82. struct config_type
    83. {
    84. char stassid[32]; // 定义配网得到的WIFI名长度(最大32字节)
    85. char stapsw[64]; // 定义配网得到的WIFI密码长度(最大64字节)
    86. };
    87. //---------------修改此处""内的信息--------------------
    88. // 如开启WEB配网则可不用设置这里的参数,前一个为wifi ssid,后一个为密码
    89. config_type wificonf = {{"WiFi名"}, {"密码"}};
    90. // 天气更新时间 X 分钟(默认3分钟)
    91. unsigned int updateweater_time = WEATHER_UPDATE_TIME;
    92. // 天气信息
    93. struct Weather_Msg
    94. {
    95. String cityDZ;
    96. String dataSK;
    97. String dataFC;
    98. };
    99. Weather_Msg weather_msg = {{""}, {""}, {""}};
    100. //----------------------------------------------------
    101. // LCD屏幕相关设置
    102. TFT_eSPI tft = TFT_eSPI(); // 引脚请自行配置tft_espi库中的 User_Setup.h文件
    103. TFT_eSprite clk = TFT_eSprite(&tft);
    104. #define LCD_BL_PIN 5 // LCD背光引脚
    105. uint16_t bgColor = 0x0000;
    106. uint16_t pinkColor = tft.color565(255, 174, 201);
    107. uint16_t zongseColor = tft.color565(128, 64, 64);
    108. uint16_t whiteColor = tft.color565(245, 246, 247);
    109. uint16_t fhColor = tft.color565(253, 99, 139);
    110. uint16_t blueColor = tft.color565(175, 221, 224);
    111. // 其余状态标志位
    112. int LCD_Rotation = 0; // LCD屏幕方向
    113. int LCD_BL_PWM = 50; // 屏幕亮度0-100,默认50
    114. uint8_t Wifi_en = 1; // WIFI模块启动 1:打开 0:关闭
    115. uint8_t UpdateWeater_en = 0; // 更新时间标志位
    116. int prevTime = 0; // 滚动显示更新标志位
    117. int DHT_img_flag = 0; // DHT传感器使用标志位
    118. // EEPROM参数存储地址位
    119. int BL_addr = 1; // 被写入数据的EEPROM地址编号 1亮度
    120. int Ro_addr = 2; // 被写入数据的EEPROM地址编号 2 旋转方向
    121. int DHT_addr = 3; // 3 DHT使能标志位
    122. int CC_addr = 10; // 被写入数据的EEPROM地址编号 10城市
    123. int wifi_addr = 30; // 被写入数据的EEPROM地址编号 20wifi-ssid-psw
    124. time_t prevDisplay = 0; // 显示时间显示记录
    125. int Amimate_reflash_Time = 0; // 更新时间记录
    126. int Amilove_reflash_Time = 0; // 更新时间记录
    127. /*** Component objects ***/
    128. WeatherNum wrat;
    129. uint32_t targetTime = 0;
    130. String cityCode = "101190402"; // 天气城市代码
    131. int tempnum = 0; // 温度百分比
    132. int huminum = 0; // 湿度百分比
    133. int tempcol = 0xffff; // 温度显示颜色
    134. int humicol = 0xffff; // 湿度显示颜色
    135. // NTP服务器参数
    136. static const char ntpServerName[] = "ntp3.aliyun.com";
    137. const int timeZone = 8; // 东八区
    138. // wifi连接UDP设置参数
    139. WiFiUDP Udp;
    140. WiFiClient wificlient;
    141. unsigned int localPort = 8000;
    142. float duty = 0;
    143. // 星期
    144. String week()
    145. {
    146. String wk[7] = {"日", "一", "二", "三", "四", "五", "六"};
    147. String s = "周" + wk[weekday() - 1];
    148. return s;
    149. }
    150. // 月日
    151. String monthDay()
    152. {
    153. String s = String(month());
    154. s = s + "月" + day() + "日";
    155. return s;
    156. }
    157. /* *****************************************************************
    158. * 函数
    159. * *****************************************************************/
    160. // wifi ssid,psw保存到eeprom
    161. void savewificonfig()
    162. {
    163. // 开始写入
    164. uint8_t *p = (uint8_t *)(&wificonf);
    165. for (unsigned int i = 0; i < sizeof(wificonf); i++)
    166. {
    167. EEPROM.write(i + wifi_addr, *(p + i)); // 在闪存内模拟写入
    168. }
    169. delay(10);
    170. EEPROM.commit(); // 执行写入ROM
    171. delay(10);
    172. }
    173. // TFT屏幕输出函数
    174. bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap)
    175. {
    176. if (y >= tft.height())
    177. return 0;
    178. tft.pushImage(x, y, w, h, bitmap);
    179. // Return 1 to decode next block
    180. return 1;
    181. }
    182. // 进度条函数
    183. byte loadNum = 6;
    184. void loading(byte delayTime) // 绘制进度条
    185. {
    186. clk.setColorDepth(8);
    187. clk.createSprite(200, 100); // 创建窗口
    188. clk.fillSprite(0x0000); // 填充率
    189. clk.drawRoundRect(0, 0, 200, 16, 8, 0xFFFF); // 空心圆角矩形
    190. clk.fillRoundRect(3, 3, loadNum, 10, 5, 0xFFFF); // 实心圆角矩形
    191. clk.setTextDatum(CC_DATUM); // 设置文本数据
    192. clk.setTextColor(TFT_GREEN, 0x0000);
    193. clk.drawString("Connecting to WiFi......", 100, 40, 2);
    194. clk.setTextColor(TFT_WHITE, 0x0000);
    195. clk.drawRightString(Version, 180, 60, 2);
    196. clk.pushSprite(20, 120); // 窗口位置
    197. // clk.setTextDatum(CC_DATUM);
    198. // clk.setTextColor(TFT_WHITE, 0x0000);
    199. // clk.pushSprite(130,180);
    200. clk.deleteSprite();
    201. loadNum += 1;
    202. delay(delayTime);
    203. }
    204. // 湿度图标显示函数
    205. void humidityWin()
    206. {
    207. clk.setColorDepth(8);
    208. huminum = huminum / 2;
    209. clk.createSprite(52, 6); // 创建窗口
    210. clk.fillSprite(0x0000); // 填充率
    211. clk.drawRoundRect(0, 0, 52, 6, 3, 0xFFFF); // 空心圆角矩形 起始位x,y,长度,宽度,圆弧半径,颜色
    212. clk.fillRoundRect(1, 1, huminum, 4, 2, humicol); // 实心圆角矩形
    213. clk.pushSprite(45, 222); // 窗口位置
    214. clk.deleteSprite();
    215. }
    216. // 温度图标显示函数
    217. void tempWin()
    218. {
    219. clk.setColorDepth(8);
    220. clk.createSprite(52, 6); // 创建窗口
    221. clk.fillSprite(0x0000); // 填充率
    222. clk.drawRoundRect(0, 0, 52, 6, 3, 0xFFFF); // 空心圆角矩形 起始位x,y,长度,宽度,圆弧半径,颜色
    223. clk.fillRoundRect(1, 1, tempnum, 4, 2, tempcol); // 实心圆角矩形
    224. clk.pushSprite(45, 192); // 窗口位置
    225. clk.deleteSprite();
    226. }
    227. #if WM_EN
    228. // WEB配网LCD显示函数
    229. void Web_win()
    230. {
    231. clk.setColorDepth(8);
    232. clk.createSprite(200, 60); // 创建窗口
    233. clk.fillSprite(0x0000); // 填充率
    234. clk.setTextDatum(CC_DATUM); // 设置文本数据
    235. clk.setTextColor(TFT_GREEN, 0x0000);
    236. clk.drawString("WiFi Connect Fail!", 100, 10, 2);
    237. clk.drawString("SSID:", 45, 40, 2);
    238. clk.setTextColor(TFT_WHITE, 0x0000);
    239. clk.drawString("AutoConnectAP", 125, 40, 2);
    240. clk.pushSprite(20, 50); // 窗口位置
    241. clk.deleteSprite();
    242. }
    243. // WEB配网函数
    244. void Webconfig()
    245. {
    246. WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP
    247. delay(3000);
    248. wm.resetSettings(); // wipe settings
    249. // add a custom input field
    250. // int customFieldLength = 40;
    251. // new (&custom_field) WiFiManagerParameter("customfieldid", "Custom Field Label", "Custom Field Value", customFieldLength,"placeholder=\"Custom Field Placeholder\"");
    252. // test custom html input type(checkbox)
    253. // new (&custom_field) WiFiManagerParameter("customfieldid", "Custom Field Label", "Custom Field Value", customFieldLength,"placeholder=\"Custom Field Placeholder\" type=\"checkbox\""); // custom html type
    254. // test custom html(radio)
    255. // const char* custom_radio_str = "
      One
      Two
      Three";
    256. // new (&custom_field) WiFiManagerParameter(custom_radio_str); // custom html input
    257. const char *set_rotation = "
      \
    258. USB接口朝下
      \
    259. USB接口朝右
      \
    260. USB接口朝上
      \
    261. USB接口朝左
      "
      ;
    262. WiFiManagerParameter custom_rot(set_rotation); // custom html input
    263. WiFiManagerParameter custom_bl("LCDBL", "屏幕亮度(1-100)", "10", 3);
    264. #if DHT_EN
    265. WiFiManagerParameter custom_DHT11_en("DHT11_en", "Enable DHT11 sensor", "0", 1);
    266. #endif
    267. WiFiManagerParameter custom_weatertime("WeaterUpdateTime", "天气刷新时间(分钟)", "10", 3);
    268. WiFiManagerParameter custom_cc("CityCode", "城市代码", "0", 9);
    269. WiFiManagerParameter custom_bir("birthday", "生日", "0", 8);
    270. WiFiManagerParameter p_lineBreak_notext("

      "
      )
      ;
    271. // wm.addParameter(&p_lineBreak_notext);
    272. // wm.addParameter(&custom_field);
    273. wm.addParameter(&p_lineBreak_notext);
    274. wm.addParameter(&custom_cc);
    275. wm.addParameter(&p_lineBreak_notext);
    276. wm.addParameter(&custom_bl);
    277. wm.addParameter(&p_lineBreak_notext);
    278. wm.addParameter(&custom_weatertime);
    279. wm.addParameter(&p_lineBreak_notext);
    280. wm.addParameter(&custom_rot);
    281. wm.addParameter(&p_lineBreak_notext);
    282. wm.addParameter(&custom_bir);
    283. #if DHT_EN
    284. wm.addParameter(&p_lineBreak_notext);
    285. wm.addParameter(&custom_DHT11_en);
    286. #endif
    287. wm.setSaveParamsCallback(saveParamCallback);
    288. // custom menu via array or vector
    289. //
    290. // 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!)
    291. // const char* menu[] = {"wifi","info","param","sep","restart","exit"};
    292. // wm.setMenu(menu,6);
    293. std::vector<const char *> menu = {"wifi", "restart"};
    294. wm.setMenu(menu);
    295. // set dark theme
    296. wm.setClass("invert");
    297. // set static ip
    298. // wm.setSTAStaticIPConfig(IPAddress(10,0,1,99), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); // set static ip,gw,sn
    299. // wm.setShowStaticFields(true); // force show static ip fields
    300. // wm.setShowDnsFields(true); // force show dns field always
    301. // wm.setConnectTimeout(20); // how long to try to connect for before continuing
    302. // wm.setConfigPortalTimeout(30); // auto close configportal after n seconds
    303. // wm.setCaptivePortalEnable(false); // disable captive portal redirection
    304. // wm.setAPClientCheck(true); // avoid timeout if client connected to softap
    305. // wifi scan settings
    306. // wm.setRemoveDuplicateAPs(false); // do not remove duplicate ap names (true)
    307. wm.setMinimumSignalQuality(20); // set min RSSI (percentage) to show in scans, null = 8%
    308. // wm.setShowInfoErase(false); // do not show erase button on info page
    309. // wm.setScanDispPerc(true); // show RSSI as percentage not graph icons
    310. // wm.setBreakAfterConfig(true); // always exit configportal even if wifi save fails
    311. bool res;
    312. // res = wm.autoConnect(); // auto generated AP name from chipid
    313. res = wm.autoConnect("AutoConnectAP"); // anonymous ap
    314. // res = wm.autoConnect("AutoConnectAP","password"); // password protected ap
    315. while (!res)
    316. ;
    317. }
    318. String getParam(String name)
    319. {
    320. // read parameter from server, for customhmtl input
    321. String value;
    322. if (wm.server->hasArg(name))
    323. {
    324. value = wm.server->arg(name);
    325. }
    326. return value;
    327. }
    328. // 删除原有eeprom中的信息
    329. void deletewificonfig()
    330. {
    331. config_type deletewifi = {{""}, {""}};
    332. uint8_t *p = (uint8_t *)(&deletewifi);
    333. for (unsigned int i = 0; i < sizeof(deletewifi); i++)
    334. {
    335. EEPROM.write(i + wifi_addr, *(p + i)); // 在闪存内模拟写入
    336. }
    337. delay(10);
    338. EEPROM.commit(); // 执行写入ROM
    339. delay(10);
    340. }
    341. // 从eeprom读取WiFi信息ssid,psw
    342. void readwificonfig()
    343. {
    344. uint8_t *p = (uint8_t *)(&wificonf);
    345. for (unsigned int i = 0; i < sizeof(wificonf); i++)
    346. {
    347. *(p + i) = EEPROM.read(i + wifi_addr);
    348. }
    349. // EEPROM.commit();
    350. // ssid = wificonf.stassid;
    351. // pass = wificonf.stapsw;
    352. Serial.printf("Read WiFi Config.....\r\n");
    353. Serial.printf("SSID:%s\r\n", wificonf.stassid);
    354. Serial.printf("PSW:%s\r\n", wificonf.stapsw);
    355. Serial.printf("Connecting.....\r\n");
    356. }
    357. void saveParamCallback()
    358. {
    359. int CCODE = 0, cc;
    360. Serial.println("[CALLBACK] saveParamCallback fired");
    361. // Serial.println("PARAM customfieldid = " + getParam("customfieldid"));
    362. // Serial.println("PARAM CityCode = " + getParam("CityCode"));
    363. // Serial.println("PARAM LCD BackLight = " + getParam("LCDBL"));
    364. // Serial.println("PARAM WeaterUpdateTime = " + getParam("WeaterUpdateTime"));
    365. // Serial.println("PARAM Rotation = " + getParam("set_rotation"));
    366. // Serial.println("PARAM DHT11_en = " + getParam("DHT11_en"));
    367. // 将从页面中获取的数据保存
    368. updateweater_time = getParam("WeaterUpdateTime").toInt();
    369. cc = getParam("CityCode").toInt();
    370. LCD_Rotation = getParam("set_rotation").toInt();
    371. LCD_BL_PWM = getParam("LCDBL").toInt();
    372. // 对获取的数据进行处理
    373. // 城市代码
    374. Serial.print("CityCode = ");
    375. Serial.println(cc);
    376. if (((cc >= 101000000) && (cc <= 102000000)) || (cc == 0))
    377. {
    378. for (int cnum = 0; cnum < 5; cnum++)
    379. {
    380. EEPROM.write(CC_addr + cnum, cc % 100); // 城市地址写入城市代码
    381. EEPROM.commit(); // 保存更改的数据
    382. cc = cc / 100;
    383. delay(5);
    384. }
    385. for (int cnum = 5; cnum > 0; cnum--)
    386. {
    387. CCODE = CCODE * 100;
    388. CCODE += EEPROM.read(CC_addr + cnum - 1);
    389. delay(5);
    390. }
    391. cityCode = CCODE;
    392. }
    393. // 屏幕方向
    394. Serial.print("LCD_Rotation = ");
    395. Serial.println(LCD_Rotation);
    396. if (EEPROM.read(Ro_addr) != LCD_Rotation)
    397. {
    398. EEPROM.write(Ro_addr, LCD_Rotation);
    399. EEPROM.commit();
    400. delay(5);
    401. }
    402. tft.setRotation(LCD_Rotation);
    403. tft.fillScreen(0x0000);
    404. Web_win();
    405. loadNum--;
    406. loading(1);
    407. if (EEPROM.read(BL_addr) != LCD_BL_PWM)
    408. {
    409. EEPROM.write(BL_addr, LCD_BL_PWM);
    410. EEPROM.commit();
    411. delay(5);
    412. }
    413. // 屏幕亮度
    414. Serial.printf("亮度调整为:");
    415. analogWrite(LCD_BL_PIN, 1023 - (LCD_BL_PWM * 10));
    416. Serial.println(LCD_BL_PWM);
    417. // 天气更新时间
    418. Serial.printf("天气更新时间调整为:");
    419. Serial.println(updateweater_time);
    420. }
    421. #endif
    422. // 发送HTTP请求并且将服务器响应通过串口输出
    423. void getCityCode()
    424. {
    425. String URL = "http://wgeo.weather.com.cn/ip/?_=" + String(now());
    426. // 创建 HTTPClient 对象
    427. HTTPClient httpClient;
    428. // 配置请求地址。此处也可以不使用端口号和PATH而单纯的
    429. httpClient.begin(wificlient, URL);
    430. // 设置请求头中的User-Agent
    431. 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");
    432. httpClient.addHeader("Referer", "http://www.weather.com.cn/");
    433. // 启动连接并发送HTTP请求
    434. int httpCode = httpClient.GET();
    435. Serial.print("Send GET request to URL: ");
    436. Serial.println(URL);
    437. // 如果服务器响应OK则从服务器获取响应体信息并通过串口输出
    438. if (httpCode == HTTP_CODE_OK)
    439. {
    440. String str = httpClient.getString();
    441. int aa = str.indexOf("id=");
    442. if (aa > -1)
    443. {
    444. // cityCode = str.substring(aa+4,aa+4+9).toInt();
    445. cityCode = str.substring(aa + 4, aa + 4 + 9);
    446. Serial.println(cityCode);
    447. getCityWeater();
    448. }
    449. else
    450. {
    451. Serial.println("获取城市代码失败");
    452. }
    453. }
    454. else
    455. {
    456. Serial.println("请求城市代码错误:");
    457. Serial.println(httpCode);
    458. }
    459. // 关闭ESP8266与服务器连接
    460. httpClient.end();
    461. }
    462. // 获取城市天气
    463. void getCityWeater()
    464. {
    465. // String URL = "http://d1.weather.com.cn/dingzhi/" + cityCode + ".html?_="+String(now());//新
    466. String URL = "http://d1.weather.com.cn/weather_index/" + cityCode + ".html?_=" + String(now()); // 原来
    467. // 创建 HTTPClient 对象
    468. HTTPClient httpClient;
    469. // httpClient.begin(URL);
    470. httpClient.begin(wificlient, URL); // 使用新方法
    471. // 设置请求头中的User-Agent
    472. 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");
    473. httpClient.addHeader("Referer", "http://www.weather.com.cn/");
    474. // 启动连接并发送HTTP请求
    475. int httpCode = httpClient.GET();
    476. Serial.println("正在获取天气数据");
    477. Serial.println(URL);
    478. // 如果服务器响应OK则从服务器获取响应体信息并通过串口输出
    479. if (httpCode == HTTP_CODE_OK)
    480. {
    481. String str = httpClient.getString();
    482. // Serial.println("httpdata=" + str);
    483. int indexStart = str.indexOf("weatherinfo\":");
    484. int indexEnd = str.indexOf("};var alarmDZ");
    485. weather_msg.cityDZ = str.substring(indexStart + 13, indexEnd);
    486. // Serial.println(jsonCityDZ);
    487. indexStart = str.indexOf("dataSK =");
    488. indexEnd = str.indexOf(";var dataZS");
    489. weather_msg.dataSK = str.substring(indexStart + 8, indexEnd);
    490. // Serial.println(jsonDataSK);
    491. indexStart = str.indexOf("\"f\":[");
    492. indexEnd = str.indexOf(",{\"fa");
    493. weather_msg.dataFC = str.substring(indexStart + 5, indexEnd);
    494. // Serial.println(jsonFC);
    495. // weaterData(&jsonCityDZ, &jsonDataSK, &jsonFC);
    496. weaterData(&(weather_msg.cityDZ), &(weather_msg.dataSK), &(weather_msg.dataFC));
    497. Serial.println("获取成功");
    498. }
    499. else
    500. {
    501. Serial.println("请求城市天气错误:");
    502. Serial.print(httpCode);
    503. }
    504. // 关闭ESP8266与服务器连接
    505. httpClient.end();
    506. }
    507. String scrollText[7];
    508. // int scrollTextWidth = 0;
    509. // 天气信息写到屏幕上
    510. void weaterData(String *cityDZ, String *dataSK, String *dataFC)
    511. {
    512. // 解析第一段JSON
    513. DynamicJsonDocument doc(1024);
    514. deserializeJson(doc, *dataSK);
    515. JsonObject sk = doc.as();
    516. // TFT_eSprite clkb = TFT_eSprite(&tft);
    517. String temperature = sk["temp"].as();
    518. /***绘制相关文字***/
    519. // if (xSemaphoreTake(xMutex, portMAX_DELAY))
    520. // {
    521. // clk.setColorDepth(8);
    522. // clk.loadFont(ZdyLwFont_20);
    523. // // 温度
    524. // clk.createSprite(58, 24);
    525. // clk.fillSprite(bgColor);
    526. // clk.setTextDatum(CC_DATUM);
    527. // clk.setTextColor(TFT_WHITE, bgColor);
    528. // clk.drawString(sk["temp"].as() + "℃", 28, 13);
    529. // clk.pushSprite(100, 184);
    530. // clk.deleteSprite();
    531. // xSemaphoreGive(xMutex);
    532. // }
    533. tempnum = sk["temp"].as<int>();
    534. tempnum = tempnum + 10;
    535. if (tempnum < 10)
    536. tempcol = 0x00FF;
    537. else if (tempnum < 28)
    538. tempcol = 0x0AFF;
    539. else if (tempnum < 34)
    540. tempcol = 0x0F0F;
    541. else if (tempnum < 41)
    542. tempcol = 0xFF0F;
    543. else if (tempnum < 49)
    544. tempcol = 0xF00F;
    545. else
    546. {
    547. tempcol = 0xF00F;
    548. tempnum = 50;
    549. }
    550. // if (xSemaphoreTake(xMutex, portMAX_DELAY))
    551. // {
    552. // tempWin();
    553. // // 湿度
    554. // clk.createSprite(58, 24);
    555. // clk.fillSprite(bgColor);
    556. // clk.setTextDatum(CC_DATUM);
    557. // clk.setTextColor(TFT_WHITE, bgColor);
    558. // clk.drawString(sk["SD"].as(), 28, 13);
    559. // // clk.drawString("100%",28,13);
    560. // clk.pushSprite(100, 214);
    561. // clk.deleteSprite();
    562. // xSemaphoreGive(xMutex);
    563. // }
    564. // String A = sk["SD"].as();
    565. String huminit = sk["SD"].as();
    566. huminum = atoi((sk["SD"].as()).substring(0, 2).c_str());
    567. if (huminum > 90)
    568. humicol = 0x00FF;
    569. else if (huminum > 70)
    570. humicol = 0x0AFF;
    571. else if (huminum > 40)
    572. humicol = 0x0F0F;
    573. else if (huminum > 20)
    574. humicol = 0xFF0F;
    575. else
    576. humicol = 0xF00F;
    577. // if (xSemaphoreTake(xMutex, portMAX_DELAY))
    578. // {
    579. // humidityWin();
    580. // // 城市名称
    581. // clk.createSprite(94, 30);
    582. // clk.fillSprite(bgColor);
    583. // clk.setTextDatum(CC_DATUM);
    584. // clk.setTextColor(TFT_WHITE, bgColor);
    585. // clk.drawString(sk["cityname"].as(), 44, 16);
    586. // clk.pushSprite(15, 15);
    587. // clk.deleteSprite();
    588. // xSemaphoreGive(xMutex);
    589. // }
    590. // PM2.5空气指数
    591. String cityname = sk["cityname"].as();
    592. uint16_t pm25BgColor = tft.color565(156, 202, 127); // 优
    593. String aqiTxt = "优";
    594. int pm25V = sk["aqi"];
    595. if (pm25V > 200)
    596. {
    597. pm25BgColor = tft.color565(136, 11, 32); // 重度
    598. aqiTxt = "重度";
    599. }
    600. else if (pm25V > 150)
    601. {
    602. pm25BgColor = tft.color565(186, 55, 121); // 中度
    603. aqiTxt = "中度";
    604. }
    605. else if (pm25V > 100)
    606. {
    607. pm25BgColor = tft.color565(242, 159, 57); // 轻
    608. aqiTxt = "轻度";
    609. }
    610. else if (pm25V > 50)
    611. {
    612. pm25BgColor = tft.color565(247, 219, 100); // 良
    613. aqiTxt = "良";
    614. }
    615. scrollText[0] = "实时天气 " + sk["weather"].as();
    616. scrollText[1] = "空气质量 " + aqiTxt;
    617. scrollText[2] = "风向 " + sk["WD"].as() + sk["WS"].as();
    618. // 左上角滚动字幕
    619. // 解析第二段JSON
    620. deserializeJson(doc, *cityDZ);
    621. JsonObject dz = doc.as();
    622. // Serial.println(sk["ws"].as());
    623. // 横向滚动方式
    624. // String aa = "今日天气:" + dz["weather"].as() + ",温度:最低" + dz["tempn"].as() + ",最高" + dz["temp"].as() + " 空气质量:" + aqiTxt + ",风向:" + dz["wd"].as() + dz["ws"].as();
    625. // scrollTextWidth = clk.textWidth(scrollText);
    626. // Serial.println(aa);
    627. scrollText[3] = "今日" + dz["weather"].as();
    628. deserializeJson(doc, *dataFC);
    629. JsonObject fc = doc.as();
    630. scrollText[4] = "最低温度" + fc["fd"].as() + "℃";
    631. scrollText[5] = "最高温度" + fc["fc"].as() + "℃";
    632. if (xSemaphoreTake(xMutex, portMAX_DELAY))
    633. {
    634. clk.setColorDepth(8);
    635. clk.loadFont(ZdyLwFont_20);
    636. // 温度
    637. clk.createSprite(58, 24);
    638. clk.fillSprite(bgColor);
    639. clk.setTextDatum(CC_DATUM);
    640. clk.setTextColor(TFT_WHITE, bgColor);
    641. clk.drawString(temperature + "℃", 28, 13);
    642. clk.pushSprite(100, 184);
    643. clk.deleteSprite();
    644. tempWin();
    645. // 湿度
    646. clk.createSprite(58, 24);
    647. clk.fillSprite(bgColor);
    648. clk.setTextDatum(CC_DATUM);
    649. clk.setTextColor(TFT_WHITE, bgColor);
    650. clk.drawString(huminit, 28, 13);
    651. // clk.drawString("100%",28,13);
    652. clk.pushSprite(100, 214);
    653. clk.deleteSprite();
    654. humidityWin();
    655. // 城市名称
    656. clk.createSprite(94, 30);
    657. clk.fillSprite(bgColor);
    658. clk.setTextDatum(CC_DATUM);
    659. clk.setTextColor(TFT_WHITE, bgColor);
    660. clk.drawString(cityname, 44, 16);
    661. clk.pushSprite(15, 15);
    662. clk.deleteSprite();
    663. clk.createSprite(56, 24);
    664. clk.fillSprite(bgColor);
    665. clk.fillRoundRect(0, 0, 50, 24, 4, pm25BgColor);
    666. clk.setTextDatum(CC_DATUM);
    667. clk.setTextColor(0x0000);
    668. clk.drawString(aqiTxt, 25, 13);
    669. clk.pushSprite(104, 18);
    670. clk.deleteSprite();
    671. // 天气图标
    672. wrat.printfweather(170, 15, atoi((sk["weathercode"].as()).substring(1, 3).c_str()));
    673. clk.unloadFont();
    674. xSemaphoreGive(xMutex);
    675. }
    676. }
    677. int currentIndex = 0;
    678. TFT_eSprite clkb = TFT_eSprite(&tft);
    679. void scrollBanner()
    680. {
    681. // if(millis() - prevTime > 2333) //3秒切换一次
    682. // if(second()%2 ==0&& prevTime == 0)
    683. // {
    684. if (scrollText[currentIndex])
    685. {
    686. if (xSemaphoreTake(xMutex, portMAX_DELAY))
    687. {
    688. clkb.setColorDepth(8);
    689. clkb.loadFont(ZdyLwFont_20);
    690. clkb.createSprite(150, 30);
    691. clkb.fillSprite(bgColor);
    692. clkb.setTextWrap(false);
    693. clkb.setTextDatum(CC_DATUM);
    694. clkb.setTextColor(TFT_WHITE, bgColor);
    695. clkb.drawString(scrollText[currentIndex], 74, 16);
    696. clkb.pushSprite(10, 45);
    697. clkb.deleteSprite();
    698. clkb.unloadFont();
    699. xSemaphoreGive(xMutex);
    700. }
    701. if (currentIndex >= 5)
    702. currentIndex = 0; // 回第一个
    703. else
    704. currentIndex += 1; // 准备切换到下一个
    705. }
    706. prevTime = 1;
    707. // }
    708. }
    709. // 用快速线方法绘制数字
    710. void drawLineFont(uint32_t _x, uint32_t _y, uint32_t _num, uint32_t _size, uint32_t _color)
    711. {
    712. uint32_t fontSize;
    713. const LineAtom *fontOne;
    714. // 小号(9*14)
    715. if (_size == 1)
    716. {
    717. fontOne = smallLineFont[_num];
    718. fontSize = smallLineFont_size[_num];
    719. // 绘制前清理字体绘制区域
    720. tft.fillRect(_x, _y, 9, 14, TFT_BLACK);
    721. }
    722. // 中号(18*30)
    723. else if (_size == 2)
    724. {
    725. fontOne = middleLineFont[_num];
    726. fontSize = middleLineFont_size[_num];
    727. // 绘制前清理字体绘制区域
    728. tft.fillRect(_x, _y, 18, 30, TFT_BLACK);
    729. }
    730. // 大号(36*90)
    731. else if (_size == 3)
    732. {
    733. fontOne = largeLineFont[_num];
    734. fontSize = largeLineFont_size[_num];
    735. // 绘制前清理字体绘制区域
    736. tft.fillRect(_x, _y, 36, 90, TFT_BLACK);
    737. }
    738. else
    739. return;
    740. for (uint32_t i = 0; i < fontSize; i++)
    741. {
    742. tft.drawFastHLine(fontOne[i].xValue + _x, fontOne[i].yValue + _y, fontOne[i].lValue, _color);
    743. }
    744. }
    745. int Hour_sign = 60;
    746. int Minute_sign = 60;
    747. int Second_sign = 60;
    748. // 日期刷新
    749. void digitalClockDisplay(int reflash_en = 0)
    750. {
    751. // 时钟刷新,输入1强制刷新
    752. int now_hour = hour(); // 获取小时
    753. int now_minute = minute(); // 获取分钟
    754. int now_second = second(); // 获取秒针
    755. // 小时刷新
    756. if ((now_hour != Hour_sign) || (reflash_en == 1))
    757. {
    758. if (xSemaphoreTake(xMutex, portMAX_DELAY))
    759. {
    760. drawLineFont(20, timeY, now_hour / 10, 3, SD_FONT_WHITE);
    761. drawLineFont(60, timeY, now_hour % 10, 3, SD_FONT_WHITE);
    762. Hour_sign = now_hour;
    763. xSemaphoreGive(xMutex);
    764. }
    765. }
    766. // 分钟刷新
    767. if ((now_minute != Minute_sign) || (reflash_en == 1))
    768. {
    769. if (xSemaphoreTake(xMutex, portMAX_DELAY))
    770. {
    771. drawLineFont(101, timeY, now_minute / 10, 3, SD_FONT_YELLOW);
    772. drawLineFont(141, timeY, now_minute % 10, 3, SD_FONT_YELLOW);
    773. Minute_sign = now_minute;
    774. xSemaphoreGive(xMutex);
    775. }
    776. }
    777. // 秒针刷新
    778. if ((now_second != Second_sign) || (reflash_en == 1)) // 分钟刷新
    779. {
    780. if (xSemaphoreTake(xMutex, portMAX_DELAY))
    781. {
    782. drawLineFont(182, timeY + 30, now_second / 10, 2, SD_FONT_WHITE);
    783. drawLineFont(202, timeY + 30, now_second % 10, 2, SD_FONT_WHITE);
    784. Second_sign = now_second;
    785. xSemaphoreGive(xMutex);
    786. }
    787. }
    788. if (reflash_en == 1)
    789. reflash_en = 0;
    790. /***日期****/
    791. if (xSemaphoreTake(xMutex, portMAX_DELAY))
    792. {
    793. clk.setColorDepth(8);
    794. clk.loadFont(ZdyLwFont_20);
    795. // 星期
    796. clk.createSprite(58, 30);
    797. clk.fillSprite(bgColor);
    798. clk.setTextDatum(CC_DATUM);
    799. clk.setTextColor(TFT_WHITE, bgColor);
    800. clk.drawString(week(), 29, 16);
    801. clk.pushSprite(102, 150);
    802. clk.deleteSprite();
    803. // 月日
    804. clk.createSprite(95, 30);
    805. clk.fillSprite(bgColor);
    806. clk.setTextDatum(CC_DATUM);
    807. clk.setTextColor(TFT_WHITE, bgColor);
    808. clk.drawString(monthDay(), 49, 16);
    809. clk.pushSprite(5, 150);
    810. clk.deleteSprite();
    811. clk.unloadFont();
    812. xSemaphoreGive(xMutex);
    813. }
    814. }
    815. /*-------- NTP code ----------*/
    816. const int NTP_PACKET_SIZE = 48; // NTP时间在消息的前48字节中
    817. byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming & outgoing packets
    818. time_t getNtpTime()
    819. {
    820. IPAddress ntpServerIP; // NTP server's ip address
    821. while (Udp.parsePacket() > 0)
    822. ;
    823. // discard any previously received packets
    824. // Serial.println("Transmit NTP Request");
    825. // get a random server from the pool
    826. WiFi.hostByName(ntpServerName, ntpServerIP);
    827. // Serial.print(ntpServerName);
    828. // Serial.print(": ");
    829. // Serial.println(ntpServerIP);
    830. sendNTPpacket(ntpServerIP);
    831. uint32_t beginWait = millis();
    832. while (millis() - beginWait < 1500)
    833. {
    834. int size = Udp.parsePacket();
    835. if (size >= NTP_PACKET_SIZE)
    836. {
    837. Serial.println("Receive NTP Response");
    838. Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
    839. unsigned long secsSince1900;
    840. // convert four bytes starting at location 40 to a long integer
    841. secsSince1900 = (unsigned long)packetBuffer[40] << 24;
    842. secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
    843. secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
    844. secsSince1900 |= (unsigned long)packetBuffer[43];
    845. // Serial.println(secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR);
    846. return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    847. }
    848. }
    849. Serial.println("No NTP Response :-(");
    850. return 0; // 无法获取时间时返回0
    851. }
    852. // 向NTP服务器发送请求
    853. void sendNTPpacket(IPAddress & address)
    854. {
    855. // set all bytes in the buffer to 0
    856. memset(packetBuffer, 0, NTP_PACKET_SIZE);
    857. // Initialize values needed to form NTP request
    858. // (see URL above for details on the packets)
    859. packetBuffer[0] = 0b11100011; // LI, Version, Mode
    860. packetBuffer[1] = 0; // Stratum, or type of clock
    861. packetBuffer[2] = 6; // Polling Interval
    862. packetBuffer[3] = 0xEC; // Peer Clock Precision
    863. // 8 bytes of zero for Root Delay & Root Dispersion
    864. packetBuffer[12] = 49;
    865. packetBuffer[13] = 0x4E;
    866. packetBuffer[14] = 49;
    867. packetBuffer[15] = 52;
    868. // all NTP fields have been given values, now
    869. // you can send a packet requesting a timestamp:
    870. Udp.beginPacket(address, 123); // NTP requests are to port 123
    871. Udp.write(packetBuffer, NTP_PACKET_SIZE);
    872. Udp.endPacket();
    873. }
    874. void esp_reset(Button2 & btn)
    875. {
    876. ESP.restart();
    877. }
    878. void wifi_reset(Button2 & btn)
    879. {
    880. wm.resetSettings();
    881. deletewificonfig();
    882. delay(10);
    883. Serial.println("重置WiFi成功");
    884. ESP.restart();
    885. }
    886. // 更新时间
    887. void reflashTime()
    888. {
    889. prevDisplay = now();
    890. // timeClockDisplay(1);
    891. digitalClockDisplay();
    892. prevTime = 0;
    893. }
    894. // 切换天气 or 空气质量
    895. void reflashBanner()
    896. {
    897. scrollBanner();
    898. }
    899. // 打开WIFI
    900. void openWifi()
    901. {
    902. Serial.println("WIFI reset......");
    903. // WiFi.forceSleepWake(); // wifi on
    904. Wifi_en = 1;
    905. }
    906. // 强制屏幕刷新
    907. void LCD_reflash()
    908. {
    909. reflashTime();
    910. reflashBanner();
    911. openWifi();
    912. }
    913. // 清空屏幕
    914. void clear_screen()
    915. {
    916. tft.fillScreen(bgColor);
    917. }
    918. void currentWeather(void *param)
    919. {
    920. Serial.println("weather");
    921. while (1)
    922. {
    923. getCityWeater();
    924. vTaskDelay(1000 * 60 * 5);
    925. }
    926. }
    927. const uint8_t *Animate_value; // 指向关键帧的指针
    928. uint32_t Animate_size; // 指向关键帧大小的指针
    929. int Animate_key = -1;
    930. void refresh_AnimatedImage(void *)
    931. {
    932. while (1)
    933. {
    934. if (millis() - Amimate_reflash_Time > 100) // x ms切换一次
    935. {
    936. Animate_key++;
    937. Amimate_reflash_Time = millis();
    938. Animate_value = hutao[Animate_key];
    939. Animate_size = hutao_size[Animate_key];
    940. if (xSemaphoreTake(xMutex, portMAX_DELAY))
    941. {
    942. // Serial.println("xSemaphoreTake in");
    943. TJpgDec.drawJpg(160, 160, Animate_value, Animate_size);
    944. xSemaphoreGive(xMutex);
    945. // Serial.println("xSemaphoreTake out");
    946. }
    947. if (Animate_key >= 31)
    948. {
    949. Animate_key = -1;
    950. }
    951. vTaskDelay(pdMS_TO_TICKS(100));
    952. }
    953. }
    954. }
    955. void buttonLoop(void *param)
    956. {
    957. Serial.println("button");
    958. while (1)
    959. {
    960. Button_sw1.loop();
    961. vTaskDelay(pdMS_TO_TICKS(500));
    962. }
    963. }
    964. // 切换天气 or 空气质量
    965. void reflashBanner(void *param)
    966. {
    967. Serial.println("scroller");
    968. while (1)
    969. {
    970. scrollBanner();
    971. vTaskDelay(pdMS_TO_TICKS(5000));
    972. }
    973. }
    974. void currentTime(void *pvParameters)
    975. {
    976. Serial.println("time");
    977. while (1)
    978. {
    979. digitalClockDisplay();
    980. vTaskDelay(pdMS_TO_TICKS(100));
    981. }
    982. }
    983. // void syncTime(void *param)
    984. // {
    985. // while (1)
    986. // {
    987. // // if (!getLocalTime(&timeinfo))
    988. // // {
    989. // // Serial.println("Failed to obtain time");
    990. // // return;
    991. // // }
    992. // // setTime(timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, timeinfo.tm_mday, timeinfo.tm_mon + 1, timeinfo.tm_year + 1900);
    993. // //getNtpTime();
    994. // setSyncProvider(getNtpTime);
    995. // vTaskDelay(pdMS_TO_TICKS(1000 * 60 * 4));
    996. // }
    997. // }
    998. void setup()
    999. {
    1000. xMutex = xSemaphoreCreateMutex();
    1001. Button_sw1.setLongClickHandler(wifi_reset);
    1002. // 设置消抖时间
    1003. Serial.begin(115200);
    1004. EEPROM.begin(1024);
    1005. // WiFi.forceSleepWake();
    1006. // wm.resetSettings(); //在初始化中使wifi重置,需重新配置WiFi
    1007. // 从eeprom读取背光亮度设置
    1008. if (EEPROM.read(BL_addr) > 0 && EEPROM.read(BL_addr) < 100)
    1009. LCD_BL_PWM = EEPROM.read(BL_addr);
    1010. // 从eeprom读取屏幕方向设置
    1011. if (EEPROM.read(Ro_addr) >= 0 && EEPROM.read(Ro_addr) <= 3)
    1012. LCD_Rotation = EEPROM.read(Ro_addr);
    1013. pinMode(LCD_BL_PIN, OUTPUT);
    1014. analogWrite(LCD_BL_PIN, 1023 - (LCD_BL_PWM * 10));
    1015. tft.begin(); /* TFT init */
    1016. tft.invertDisplay(1); // 反转所有显示颜色:1反转,0正常
    1017. tft.setRotation(LCD_Rotation);
    1018. tft.fillScreen(0x0000);
    1019. tft.setTextColor(TFT_BLACK, bgColor);
    1020. targetTime = millis() + 1000;
    1021. readwificonfig(); // 读取存储的wifi信息
    1022. Serial.print("正在连接WIFI ");
    1023. Serial.println(wificonf.stassid);
    1024. WiFi.begin(wificonf.stassid, wificonf.stapsw);
    1025. TJpgDec.setJpgScale(1);
    1026. TJpgDec.setSwapBytes(true);
    1027. TJpgDec.setCallback(tft_output);
    1028. while (WiFi.status() != WL_CONNECTED)
    1029. {
    1030. loading(30);
    1031. if (loadNum >= 194)
    1032. {
    1033. // 使能web配网后自动将smartconfig配网失效
    1034. #if WM_EN
    1035. Web_win();
    1036. Webconfig();
    1037. #endif
    1038. #if !WM_EN
    1039. SmartConfig();
    1040. #endif
    1041. break;
    1042. }
    1043. }
    1044. delay(10);
    1045. while (loadNum < 194) // 让动画走完
    1046. {
    1047. loading(1);
    1048. }
    1049. if (WiFi.status() == WL_CONNECTED)
    1050. {
    1051. Serial.print("SSID:");
    1052. Serial.println(WiFi.SSID().c_str());
    1053. Serial.print("PSW:");
    1054. Serial.println(WiFi.psk().c_str());
    1055. strcpy(wificonf.stassid, WiFi.SSID().c_str()); // 名称复制
    1056. strcpy(wificonf.stapsw, WiFi.psk().c_str()); // 密码复制
    1057. savewificonfig();
    1058. readwificonfig();
    1059. }
    1060. Serial.print("本地IP: ");
    1061. Serial.println(WiFi.localIP());
    1062. Serial.println("启动UDP");
    1063. Udp.begin(localPort);
    1064. Serial.println("等待同步...");
    1065. setSyncProvider(getNtpTime);
    1066. setSyncInterval(300);
    1067. //getNtpTime();
    1068. //configTime(gmtOffset_sec, daylightOffset_sec, ntpServerName);
    1069. TJpgDec.setJpgScale(1);
    1070. TJpgDec.setSwapBytes(true);
    1071. TJpgDec.setCallback(tft_output);
    1072. int CityCODE = 0;
    1073. for (int cnum = 5; cnum > 0; cnum--)
    1074. {
    1075. CityCODE = CityCODE * 100;
    1076. CityCODE += EEPROM.read(CC_addr + cnum - 1);
    1077. delay(5);
    1078. }
    1079. if (CityCODE >= 101000000 && CityCODE <= 102000000)
    1080. cityCode = CityCODE;
    1081. else
    1082. getCityCode(); // 获取城市代码
    1083. tft.fillScreen(TFT_BLACK); // 清屏
    1084. TJpgDec.drawJpg(15, 183, temperature, sizeof(temperature)); // 温度图标
    1085. TJpgDec.drawJpg(15, 213, humidity, sizeof(humidity)); // 湿度图标
    1086. getCityWeater();
    1087. // WiFi.forceSleepBegin(); // wifi off
    1088. Serial.println("WIFI休眠......");
    1089. Wifi_en = 0;
    1090. xTaskCreatePinnedToCore(currentWeather, "weather", 8192, NULL, 1, NULL, 1);
    1091. xTaskCreatePinnedToCore(refresh_AnimatedImage, "Animate", 2048, NULL, 2, NULL, 1);
    1092. xTaskCreatePinnedToCore(buttonLoop, "button", 2048, NULL, 1, NULL, 1);
    1093. xTaskCreatePinnedToCore(reflashBanner, "scroller", 2048, NULL, 1, NULL, 1);
    1094. xTaskCreatePinnedToCore(currentTime, "timer", 2048, NULL, 3, NULL, 1);
    1095. //xTaskCreatePinnedToCore(syncTime, "syncTime", 2048, NULL, 1, NULL, 1);
    1096. }
    1097. void loop()
    1098. {
    1099. }

    显示效果

    显示效果如下

    参考:指针阿飞

  • 相关阅读:
    SQL--DDL数据定义语言(Oracle)
    OSPF的LSA优化
    http网站升级为https网站,证书、http-flv视频显示处理
    指针和数组笔试题的透析
    免费api接口集合分享,再也不怕找不到免费api了
    极速Go语言入门(超全超详细)-基础篇2
    maven的下载和安装教程
    立体库核心干货|智能自动化立体库高承载高强耐受力高效率专用托盘
    基于两种算法的无线信道“指纹”特征识别(Matlab代码实现)
    Python 代码智能感知 —— 类型标注与特殊的注释(献给所有的Python人)
  • 原文地址:https://blog.csdn.net/qq_30347421/article/details/138167456