【问题标题】:ESP8266 resets after some time of normal running while getting data from OpenWeatherMapESP8266 在从 OpenWeatherMap 获取数据时正常运行一段时间后重置
【发布时间】:2020-07-22 23:06:00
【问题描述】:

首先,如果有什么没有得到很好的解释,很抱歉;这是我第一次在 Stack Overflow 上寻求帮助。 我有一个连接到 DHT11 温度/湿度传感器和 ILI9341 TFT-LCD 屏幕的 ESP8266 来显示我从 NTP 服务器和 OpenWeatherMap 接收到的数据。我注意到,在正常运行一段时间后,由于我认为内存不足(由 OpenWeatherMap 引起),它会重置。我尝试检查它在重置时给出的错误,它与 ESP8266 的“恐慌”模式有关,尽管我从未设法得到它吐出的内容的副本。

我问这个问题是因为我计划添加一个天气预报部分,但是当我尝试添加获取预测数据所需的代码时,它每次打开时都会立即崩溃。

下面是供您检查的代码,以防 Json 部分有任何问题,我认为这是罪魁祸首,因为我是使用 ArduinoJson 库的新手,尽管我已经明白了它。

#include <DHT.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ILI9341esp.h>
#include <ESP8266WiFi.h>
#include <time.h>
#include <Adafruit_GFX.h>
#include <ArduinoJson.h>

#define TFT_MISO D6
//#define TFT_LED 3.3V (change to IO pin if you want the screen to be toggled on/off)
#define TFT_SCK D5
#define TFT_MOSI D7
#define TFT_DC D2
#define TFT_RESET D3
#define TFT_CS D8
#define DHTPIN D1
#define DHTTYPE DHT11
#define WIFI_SSID "MY_SSID"
#define WIFI_PASS "MY_PASS"
#define TX_LED D0

WiFiClient client;
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
DHT dht(DHTPIN, DHTTYPE);

int wifitries = 0;
int timezone = 2 * 3600; //when time changes change this from 2 to 1
int dst = 0;
float t = 0.0;
float h = 0.0;
const long interval = 15000;
int elapsed_t = 0;
String APIKEY = "someapikey";
String CityID = "somecityid";
char servername[] = "api.openweathermap.org";
String result;
String weatherDescription = "";
String weatherDesc;
String weatherID;
int Temperature;
int Humidity;
char* tem = "  ";
char* hum = "  ";
char* temp = "  ";
char* humi = "  ";

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(TX_LED, OUTPUT);
  digitalWrite(TX_LED, HIGH);
  digitalWrite(LED_BUILTIN, HIGH);

  Serial.begin(115200);
  tft.begin();
  configTime(timezone, dst, "pool.ntp.org", "it.pool.ntp.org");
  dht.begin();

  WiFi.disconnect();
  delay (3000);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  Serial.println();
  Serial.println ("Connecting to TP-LINK_DD1E61");

  tft.setRotation(3);
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextSize(2);
  tft.println("Connecting to ");
  tft.println("TP-LINK_DD1E61");
  while ((!(WiFi.status() == WL_CONNECTED))) {
    Serial.print(".");
    wifitries++;
    tft.setTextSize(1);
    tft.print(".");
    delay(300);
  }
  if (wifitries = 15) {
    wifitries = 0;
    WiFi.disconnect();
    delay (3000);
    WiFi.begin(WIFI_SSID, WIFI_PASS);
    while ((!(WiFi.status() == WL_CONNECTED))) {
      Serial.print(".");
      wifitries++;
      tft.setTextSize(1);
      tft.print(".");
      delay(300);
    }
  }
  if (WiFi.status() == WL_CONNECTED) {
    tft.setTextSize(2);
    tft.println();
    tft.println("Connected to ");
    tft.println("TP-LINK_DD1E61");
    delay(500);
    tft.fillScreen(ILI9341_BLACK);
  }

  while (!time(nullptr)) {
    Serial.print("*");
    delay(300);
  }

  tft.drawLine(0, 18, 320, 18, ILI9341_WHITE);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
  tft.setCursor(0, 135);
  tft.print("TEMPO");
  tft.setCursor(20, 25);
  tft.println("TEMPERATURA");
  tft.println();
  tft.println();
  tft.setCursor(215, 25);
  tft.println("UMIDITA'");
  tft.setTextSize(1);
  tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
  tft.setCursor(0, 52);
  tft.print("INTERNO");
  tft.setCursor(0, 87);
  tft.print("ESTERNO");

  delay(1000);
  DHT_read();
  getWeatherData();
  displayConditions(Temperature, Humidity, weatherDescription);
}

void DHT_read() {
  float newT = dht.readTemperature();
  if (isnan(newT)) {
    Serial.println("Failed to read from DHT sensor!");
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    tft.setCursor(109, 43);
    tft.print("!");
  }
  else {
    int t = newT;

    if (t >= 10) {
      char* temp = "  ";
      sprintf(temp, "%02d", t);
    }
    else {
      char* temp = "  ";
      sprintf(temp, "%01d", t);
      tft.setTextColor(ILI9341_BLACK);
      tft.setTextSize(2);
      tft.setCursor(79, 43);
      tft.print("0");
    }

    Serial.print("Temperature: ");
    Serial.print(temp);
    Serial.println();
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
    tft.setCursor(67, 43);
    tft.print(temp);
    tft.setCursor(92, 40);
    tft.setTextSize(1);
    tft.print("o");
    tft.setCursor(99, 43);
    tft.setTextSize(2);
    tft.print("C");
    tft.setTextColor(ILI9341_BLACK);
    tft.setCursor(109, 43);
    tft.print("!");
  }
  float newH = dht.readHumidity();
  if (isnan(newH)) {
    Serial.println("Failed to read from DHT sensor!");
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    tft.setCursor(287, 43);
    tft.print("!");
  }
  else {
    int h = newH;

    if (h >= 10 && h <= 99) {
      char* humi = "  ";
      sprintf(humi, "%02d", h);
      tft.setTextColor(ILI9341_BLACK);
      tft.setTextSize(2);
      tft.setCursor(261, 43);
      tft.print("0");
    }
    else if (h = 100) {
      char* humi = "  ";
      sprintf(humi, "%03d", h);
    }
    else {
      char* humi = "  ";
      sprintf(humi, "%01d", h);
      tft.setTextColor(ILI9341_BLACK);
      tft.setTextSize(2);
      tft.setCursor(261, 43);
      tft.print("0");
    }

    Serial.print("Humidity: ");
    Serial.print(humi);
    Serial.println();
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
    tft.setCursor(237, 43);
    tft.print(humi);
    tft.setCursor(277, 43);
    tft.print("%");
    tft.setTextColor(ILI9341_BLACK);
    tft.setCursor(287, 43);
    tft.print("!");
  }
}

void screen() {
  time_t now = time(nullptr);
  struct tm* p_tm = localtime(&now);

  char* day = "  ";
  sprintf(day, "%02d", p_tm->tm_mday);

  tft.setCursor(192, 0);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.print(day);

  tft.setCursor(217, 0);
  tft.print("/");

  char* month = "  ";
  sprintf(month, "%02d", p_tm->tm_mon + 1);

  tft.setCursor(231, 0);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.print(month);

  tft.setCursor(256, 0);
  tft.print("/");

  char* year = "    ";
  sprintf(year, "%04d", p_tm->tm_year + 1900);

  tft.setCursor(268, 0);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.print(year);

  char* hour = "  ";
  sprintf(hour, "%02d", p_tm->tm_hour);

  tft.setCursor(0, 0);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.print(hour);

  tft.setCursor(22, 0);
  tft.print(":");

  char* minute = "  ";
  sprintf(minute, "%02d", p_tm->tm_min);

  tft.setCursor(34, 0);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.print(hour);



}

void getWeatherData() {
  if (client.connect(servername, 80))
  { //starts client connection, checks for connection
    client.println("GET /data/2.5/weather?id=" + CityID + "&units=metric&APPID=" + APIKEY + "&lang=it");
    client.println("Host: api.openweathermap.org");
    client.println("User-Agent: ArduinoWiFi/1.1");
    client.println("Connection: close");
    client.println();
  }
  else {
    Serial.println("connection failed");        //error message if no client connect
    Serial.println();
    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    tft.setCursor(0, 220);
    tft.print("CONNESSIONE FALLITA");
  }

  while (client.connected() && !client.available())
    delay(1);                                          //waits for data
  while (client.connected() || client.available())
  { //connected or data available
    char c = client.read();                     //gets byte from ethernet buffer
    result = result + c;
  }

  client.stop();                                      //stop client
  result.replace('[', ' ');
  result.replace(']', ' ');
  Serial.print(result);
  Serial.println();
  char jsonArray [result.length() + 1];
  result.toCharArray(jsonArray, sizeof(jsonArray));
  jsonArray[result.length() + 1] = '\0';
  DynamicJsonBuffer json_buf(3584); //was 4096
  JsonObject &root = json_buf.parseObject(jsonArray); //

  if (!root.success())
  {
    Serial.println("parseObject() failed");
    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    tft.setCursor(109, 78);
    tft.print("!");
    tft.setCursor(287, 78);
    tft.print("!");

  }
  else {
    tft.setTextColor(ILI9341_BLACK);
    tft.setCursor(109, 78);
    tft.print("!");
    tft.setCursor(287, 78);
    tft.print("!");
  }

  float temperature = root["main"]["temp"];
  float humidity = root["main"]["humidity"];
  String weather = root["weather"]["main"];
  String description = root["weather"]["description"];
  String id = root["weather"]["id"];
  weatherDescription = description;
  Temperature = temperature;
  Humidity = humidity;
  weatherID = id;

  result = "";  //to clean memory and keep it from running out of space
}

void displayConditions(int Temperature, int Humidity, String weatherDescription) {
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);

  if (Temperature >= 10) {
    char* tem = "  ";
    sprintf(tem, "%02d", Temperature);
  }
  else {
    char* tem = "  ";
    sprintf(tem, "%01d", Temperature);
    tft.setTextColor(ILI9341_BLACK);
    tft.setTextSize(2);
    tft.setCursor(79, 78);
    tft.print("0");
  }

  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.setCursor(67, 78);
  tft.print(tem);
  tft.setCursor(92, 75);
  tft.setTextSize(1);
  tft.print("o");
  tft.setCursor(99, 78);
  tft.setTextSize(2);
  tft.print("C");

  if (Humidity >= 10 && Humidity <= 99) {
    char* hum = "  ";
    sprintf(hum, "%02d", Humidity);
    tft.setTextColor(ILI9341_BLACK);
    tft.setTextSize(2);
    tft.setCursor(261, 78);
    tft.print("0");
  }
  else if (Humidity = 100) {
    char* hum = "  ";
    sprintf(hum, "%03d", Humidity);
  }
  else {
    char* hum = "  ";
    sprintf(hum, "%01d", Humidity);
    tft.setTextColor(ILI9341_BLACK);
    tft.setTextSize(2);
    tft.setCursor(261, 78);
    tft.print("0");
  }

  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.setCursor(237, 78);
  tft.print(hum);
  tft.setCursor(277, 78);
  tft.print("%");

  if (weatherDesc != weatherDescription) {
    weatherDesc = weatherDescription;
    tft.fillRect(0, 150, 320, 240, ILI9341_BLACK);
    tft.setCursor(0, 150);
    tft.print(weatherDescription);
  }
  else {
    tft.setCursor(0, 150);
    tft.print(weatherDescription);
  }
}


void loop() {
  screen();
  if (millis() > elapsed_t + interval) {
    elapsed_t = millis();
    getWeatherData();
    DHT_read();
    displayConditions(Temperature, Humidity, weatherDescription);
    Serial.print("Free heap: ");
    Serial.print(ESP.getFreeHeap());
    Serial.println();
  }
  if (ESP.getFreeHeap() < 1000) {
    ESP.reset();
  }
}

EDIT这是我运行代码得到的有效载荷:

        {"coord":{"lon":longitude,"lat":latitude},
        "weather": {"id":800,"main":"Clear","description":"cielo sereno","icon":"01d"} ,"base":"stations",
    "main":{"temp":16.56,"feels_like":13.87,"temp_min":13.33,"temp_max":20,"pressure":1022,"humidity":38},
    "visibility":10000,
    "wind":{"speed":1.5,"deg":80},
    "clouds":{"all":0},"dt":1586590775,
"sys":{"type":1,"id":6776,"country":"IT","sunrise":1586579815,"sunset":1586627707},
    "timezone":7200,"id":city_id,"name":"city_name","cod":city_code}

【问题讨论】:

  • 你为DynamicJsonBuffer json_buf(3584)分配了很多,根据你使用的API发回的有效负载,json_buf只需要大约800字节。但是,它不是堆碎片的罪魁祸首。以后有时间我会解释为什么。
  • 真正从您的项目github.com/ThingPulse/esp8266-weather-station-color 中添加读取传感器数据到此项目,您就完成了;-) 至于处理 JSON,我建议您查看 github.com/squix78/json-streaming-parser。通过流式传输数据,您不必分配固定数量的内存。

标签: json arduino crash esp8266 openweathermap


【解决方案1】:

首先,您为DynamicJsonBuffer json_buf(3584) 过度分配了很多,根据您使用的API 发回的有效负载,json_buf 只需要不到800 个字节,所以DynamicJsonBuffer json_buf(800) 将绰绰有余。您可以使用ArduinoJson Assistant计算将json payload复制粘贴到页面输入框所需的缓冲区大小。

然而,过大的 ArduinoJson 缓冲区并不是您面临的堆碎片的罪魁祸首。 String 类导致堆碎片的问题之一来自 String 连接,这就是您的情况。字符串连接使 Arduino 用户能够像在 JavaScript 或 Pyhton 中一样将两个字符串放在一起,String temp = "Temperature=" + String(temperature)+" Celsius"。但是,即使您只需要最后一个,此语句也会生成 5 个堆分配(而不是 4 个)。

在您的代码中,您声明了一个全局变量result,并且您正在函数中进行字符串连接。

String result;

// later in your function

void getWeatherData() {

  // at part of your function

  while (client.connected() || client.available())
  { //connected or data available
    char c = client.read();                //gets byte from ethernet buffer
    result = result + c;
  }

  // at end of your function  

  result = "";  //to clean memory and keep it from running out of space
}

当你进行拼接时,原来为你的全局变量result分配的空间可能已经没有足够的空间给拼接的变量了,所以它会创建一个临时堆并进行拼接,然后最终将结果放回一个新的在堆上为result 分配内存,在堆上为原始result 变量留下一个洞。最糟糕的是,while 循环的每次迭代都会发生这种情况。这就是为什么即使一些堆分配在函数结束时也会被释放,它没有必要被重用(想想一块上面有很多洞的奶酪)。

顺便说一句,你的代码:

result = "";  //to clean memory and keep it from running out of space

永远不要真正释放内存分配。这是另一个常见的误解。

短期修复 - 在本地使用字符串

话虽如此,如果您知道发生了什么以及如何使用它,String 类并不总是邪恶的。解决您的问题的一种快速方法(因为我没有时间为您优化代码)是在函数中本地使用它,并且不要将全局变量用于String result;。我做了一个快速测试,通过删除全局变量 result 并在 getWeatherData() 函数中声明为“丢弃”局部变量,空闲堆内存稳定并且不再导致崩溃。当您在函数中使用 String 类时,它不会在整个堆空间中留下空洞,而是在函数结束时释放。

// String result; //comment the global variable out

void getWeatherData() {

  String result;    //declare it as a local variable

  while (client.connected() || client.available())
  { //connected or data available
    char c = client.read();           //gets byte from ethernet buffer
    result = result + c;
  }

  //result = "";  //this is not necessary and does not free up heap
}

长期修复 - 不要使用 String 类

为了更好的修复,不要在 while 循环中使用字符串连接。这是没有使用 String 类的版本,并且进行了相当多的清理以消除不必要的全局变量(还重构了一些重复的代码)。

#include <Arduino.h>
#include <DHT.h>
#include <ESP8266WiFi.h>
#include <time.h>
#include <ArduinoJson.h>
#include <Adafruit_Sensor.h>
// #include <Adafruit_ILI9341esp.h>
// #include <Adafruit_GFX.h>

#define TFT_MISO D6
//#define TFT_LED 3.3V (change to IO pin if you want the screen to be toggled on/off)
#define TFT_SCK D5
#define TFT_MOSI D7
#define TFT_DC D2
#define TFT_RESET D3
#define TFT_CS D8

#define DHTPIN D1
#define DHTTYPE DHT11

#define WIFI_SSID "wifi-ssid"
#define WIFI_PASS "wifi-password"
#define TX_LED D0

WiFiClient client;
// Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
DHT dht(DHTPIN, DHTTYPE);

int timezone = 2 * 3600; //when time changes change this from 2 to 1
int dst = 0;

const unsigned long interval = 15000;
unsigned long elapsed_t = 0;

const char APIKEY[] = "open-weather-api-key";  //replace with actual api-key
const char CityID[] = "cityID";  //replace with actual city ID
char servername[] = "api.openweathermap.org";

void displayConditions(int Temperature, int Humidity, char *weatherDescription) {
  // tft.setTextSize(2);
  // tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);

  char tem[3] = {0};
  if (Temperature >= 10) {
    sprintf(tem, "%02d", Temperature);
  }
  else {
    sprintf(tem, "%01d", Temperature);
    // tft.setTextColor(ILI9341_BLACK);
    // tft.setTextSize(2);
    // tft.setCursor(79, 78);
    // tft.print("0");
  }

  // tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  // tft.setCursor(67, 78);
  // tft.print(tem);
  // tft.setCursor(92, 75);
  // tft.setTextSize(1);
  // tft.print("o");
  // tft.setCursor(99, 78);
  // tft.setTextSize(2);
  // tft.print("C");

  char hum[4] = {0};
  if (Humidity >= 10 && Humidity <= 99) {
    sprintf(hum, "%02d", Humidity);
    // tft.setTextColor(ILI9341_BLACK);
    // tft.setTextSize(2);
    // tft.setCursor(261, 78);
    // tft.print("0");
  }
  else if (Humidity == 100) {
    sprintf(hum, "%03d", Humidity);
  }
  else {
    sprintf(hum, "%01d", Humidity);
    // tft.setTextColor(ILI9341_BLACK);
    // tft.setTextSize(2);
    // tft.setCursor(261, 78);
    // tft.print("0");
  }

  // tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  // tft.setCursor(237, 78);
  // tft.print(hum);
  // tft.setCursor(277, 78);
  // tft.print("%");

  static char weatherDesc[10];
  if (strcmp(weatherDesc, weatherDescription) != 0) {
    strcpy(weatherDesc, weatherDescription);
    // tft.fillRect(0, 150, 320, 240, ILI9341_BLACK);
    // tft.setCursor(0, 150);
    // tft.print(weatherDescription);
  }
  else {
    // tft.setCursor(0, 150);
    // tft.print(weatherDescription);
  }
}

void DHT_read() {

  float newT = dht.readTemperature();
  float newH = dht.readTemperature();
  if (isnan(newT) || isnan(newH)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    // tft.setTextSize(2);
    // tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    // tft.setCursor(109, 43);
    // tft.print("!");
    // tft.setCursor(287, 43);
    // tft.print("!");
    return;
  }
  char condition[] = "";
  displayConditions((int)newT, (int)newH, condition);
}

void screen() {
  char timeNow[20];
  time_t now = time(nullptr);
  struct tm* p_tm = localtime(&now);

  strftime(timeNow, 20, "%H:%M  %d:%m:%Y", p_tm);
  Serial.println(timeNow);
  // tft.setCursor(0, 0);
  // tft.setTextSize(2);
  // tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  // tft.print(timeNow);
}

void getWeatherData() {

  if (client.connect(servername, 80))
  { //starts client connection, checks for connection
    char buff[110];
    char getString[] = "GET /data/2.5/weather?id=%s&units=metric&APPID=%s&lang=it";
    sprintf(buff, getString, CityID, APIKEY);
    client.println(buff);
    client.println(F("Host: api.openweathermap.org"));
    client.println(F("User-Agent: ArduinoWiFi/1.1"));
    client.println(F("Connection: close"));
    client.println();
  }
  else {
    Serial.println(F("connection failed"));        //error message if no client connect
    Serial.println();
    // tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    // tft.setCursor(0, 220);
    // tft.print(F("CONNESSIONE FALLITA"));
    return;
  }

  while (client.connected() && !client.available())
    delay(1);                                          //waits for data

  char result[800];
  int i = 0;
  while (client.connected() || client.available())
  { //connected or data available
    result[i++] = (char)client.read();
  }

  client.stop();                                      //stop client
  result[strlen(result) + 1] = '\0';
  Serial.println(result);

  DynamicJsonBuffer json_buf(800); //was 4096
  JsonObject &root = json_buf.parseObject(result); //

  if (!root.success())
  {
    Serial.println(F("parseObject() failed"));
    // tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    // tft.setCursor(109, 78);
    // tft.print("!");
    // tft.setCursor(287, 78);
    // tft.print("!");
    return;
  }

  // tft.setTextColor(ILI9341_BLACK);
  // tft.setCursor(109, 78);
  // tft.print("!");
  // tft.setCursor(287, 78);
  // tft.print("!");

  char weatherDescription[10] = {0};
  strcpy(weatherDescription, (const char*)root["weather"][0]["main"]);
  weatherDescription[strlen(weatherDescription) + 1] = '\0';

  int temperature = (int)root["main"]["temp"];
  int humidity = (int)root["main"]["humidity"];
  int weatherID = root["weather"][0]["id"];    //this was not used anywhere in the program

  displayConditions(temperature, humidity, weatherDescription);
}



void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(TX_LED, OUTPUT);
  digitalWrite(TX_LED, HIGH);
  digitalWrite(LED_BUILTIN, HIGH);

  Serial.begin(115200);
  // tft.begin();
  // dht.begin();

  WiFi.begin(WIFI_SSID, WIFI_PASS);
  Serial.println (F("Connecting to TP-LINK_DD1E61"));

  // tft.setRotation(3);
  // tft.fillScreen(ILI9341_BLACK);
  // tft.setTextSize(2);
  // tft.println(F("Connecting to "));
  // tft.println(F("TP-LINK_DD1E61"));
  while (WiFi.status() != WL_CONNECTED) {
   Serial.print(".");
   // tft.setTextSize(1);
   // tft.print(".");
   delay(300);
  }

  // query the ntp should be only after the establish of wifi connection
  configTime(timezone, dst, "pool.ntp.org", "it.pool.ntp.org");
  while (!time(nullptr)) {
   Serial.print("*");
   delay(300);
  }

  Serial.println(F("Connceted"));
  // tft.setTextSize(2);
  // tft.println();
  // tft.println(F("Connected to "));
  // tft.println(F("TP-LINK_DD1E61"));
  // delay(500);
  // tft.fillScreen(ILI9341_BLACK);

  // tft.drawLine(0, 18, 320, 18, ILI9341_WHITE);
  // tft.setTextSize(2);
  // tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
  // tft.setCursor(0, 135);
  // tft.print("TEMPO");
  // tft.setCursor(20, 25);
  // tft.println(F("TEMPERATURA"));
  // tft.println();
  // tft.println();
  // tft.setCursor(215, 25);
  // tft.println(F("UMIDITA'"));
  // tft.setTextSize(1);
  // tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
  // tft.setCursor(0, 52);
  // tft.print(F("INTERNO"));
  // tft.setCursor(0, 87);
  // tft.print(F("ESTERNO"));

}

void loop() {
  screen();
  if (millis() > elapsed_t + interval) {
    elapsed_t = millis();
    getWeatherData();
    DHT_read();
    // displayConditions(Temperature, Humidity, weatherDescription);
    Serial.print("Free heap: ");
    Serial.print(ESP.getFreeHeap());
    Serial.println();
  }
  delay(1000);  // only update the time once per second
 }

您可以详细了解“The Evils of Arduino Strings”。我希望我的示例能帮助您了解如何管理内存并避免使用 String 类。

【讨论】:

  • 好的,我首先完全删除 APIKEY 和 CityID 字符串变量:我只调用了一次,所以我宁愿直接在 getWeatherData() 函数中输入它们。我实际上完全无法理解的是关于让结果是数组(result[i++] = c;) 的部分。无论如何,我尝试在 getWeatherData() 函数中声明结果,所以它变成了一个局部变量。我会告诉你它是怎么回事,现在谢谢。
  • 我通过发布版本来更新我的答案,而不使用 String 类供您参考。我做了一些重写/重构来清理代码。代码在一夜之间运行良好,没有任何崩溃或过度使用堆。顺便说一句,我没有 tft display,所以大部分 tft display 的代码都被注释掉了。希望你能从代码中学到一些东西。祝你好运,玩得开心。
  • 顺便说一句,我相信ntp和open weather server都缓存了请求,所以这么频繁(15s)查询服务器没有意义,也许你应该把它改成1分钟(以及更新时间)每 1 秒)。
【解决方案2】:

您对 Json 部分是正确的,但在此之前有一些提示:

  • 切勿发布您的登录名/api 密钥/密码 - 我已从代码中删除了它们
  • 替换

    if (millis() > elapsed_t + 间隔) {

with(做同样的事情,但可以安全翻转)

if (millis() - elapsed_t > interval) {

现在到 oArduinoJson——这个库是供你使用的“臃肿”尝试手动解析字符串——如果你发布一个真正的字符串我可以告诉你如何去做。并摆脱 String 类

  String APIKEY = "someapikey";
  String CityID = "somecityid";
  char servername[] = "api.openweathermap.org"; // GOOD example of how to avoid String class
  String result;
  String weatherDescription = "";
  String weatherDesc;
  String weatherID;

String 类会破坏堆,通常会导致 esp8266/esp32 在一段时间后崩溃。空闲堆检查无济于事 - 有足够的堆,但其断裂的如此长的字符串无法正确处理。微控制器上没有垃圾收集来解决这个问题。

【讨论】:

  • 首先,感谢您删除我的私人数据,我真的没想过这样做。非常感谢。我会尝试millis的东西,但至于我应该发布的字符串,我应该发布什么字符串?我从 OpenWeatherMap 获得的数据?
  • 是的,您使用 ArduinoJson 解码的 json(在发布个人数据检查之前,如果用相同类型的其他字符覆盖它)
  • 这是我运行代码得到的有效载荷:{"coord":{"lon":longitude,"lat":latitude},"weather": {"id":800,"main":"Clear","description":"cielo sereno","icon":"01d"} ,"base":"stations","main":{"temp":16.56,"feels_like":13.87,"temp_min":13.33,"temp_max":20,"pressure":1022,"humidity":38},"visibility":10000,"wind":{"speed":1.5,"deg":80},"clouds":{"all":0},"dt":1586590775,"sys":{"type":1,"id":6776,"country":"IT","sunrise":1586579815,"sunset":1586627707},"timezone":7200,"id":city_id,"name":"city_name","cod":city_code}
猜你喜欢
  • 2016-12-05
  • 2021-04-09
  • 2021-09-12
  • 1970-01-01
  • 1970-01-01
  • 2017-03-11
  • 1970-01-01
  • 1970-01-01
  • 2021-05-05
相关资源
最近更新 更多