NodeMCU运行数秒后异常重启问题排查(附错误栈与代码)
NodeMCU重启循环问题排查与修复
问题现象
NodeMCU初始运行正常,数秒后进入重启循环。网页端和串口监视器能正常显示气象数据,但数据输出完成后会卡顿数秒随即重启。
解码后的错误栈
0x4020af5c: operator new (unsigned int) at /home/gonit/.arduino15/packages/esp8266 /hardware/esp8266/3.1.2/cores/esp8266/abi.cpp line 44 8x40208604: AsyncWebServer::on (char const*, unsigned char, std::function) at /home/gonit/Arduino/libraries/ESPAsyncWebServer/src/WebServer.cpp line 149 0x40214208: std::_Function_handler >::_M_manager(std::_Any_data &, const std::_Any_data &, std::_Manager_operation) at /home/gonit/.arduino15/packages /esp8266/tools/xtensa-lx106-elf-gcc/3.1.0-gcc10.3-e5f9fec/xtensa-1x106-elf/include /c++/10.3.0/bits/std_function.h line 268 8x402011f8: std:: Function_handler >::_M_invoke(const std::_Any_data &, AsyncWebServerRequest *&&) at /home/gonit/.arduino15/packages/esp8266/tools/xtensa- 1x106-elf-gcc/3.1.0-gcc10.3-e5f9fec/xtensa-1x106-elf/include/c++/18.3.0 /bits/std_function.h line 289 0x4020a38d: String::operator= (char const*) at /home/gonit/. arduino15/packages /esp8266/hardware/esp8266/3.1.2/cores/esp8266/WString.cpp line 319 8x482027b2: Loop() at /home/gonit/.arduino15/packages/esp8266/tools/xtensa-lx106- elf-gcc/3.1.0-gcc10.3-e5f9fec/xtensa-lx106-elf/include/c++/10.3.0 /bits/std_function.h line 303 0x402142d4: std:: Function_handler >::_M_manager(std::_Any_data &, const std::_Any_data &, std::_Manager_operation) at /home/gonit/.arduino15/packages /esp8266/tools/xtensa-lx106-elf-gcc/3.1.0-gcc10.3-e5f9fec/xtensa-lx106-elf/include /c++/10.3.0/bits/std_function.h line 268 0x402011a0: std::_Function_handler >::_M_invoke(const std::_Any_data &, AsyncWebServerRequest *&&) at /home/gonit/.arduino15/packages/esp8266/tools/xtensa- 1x106-elf-gcc/3.1.0-gcc10.3-e5f9fec/xtensa-lx106-elf/include/c++/10.3.0 /bits/std_function.h line 289 8x40202a77: ESP8266WiFiAPClass::softAPConfig(IPAddress, IPAddress, IPAddress) at /home/gonit/.arduino15/packages/esp8266/hardware/esp8266/3.1.2/libraries /ESP8266WiFi/src/ESP8266WiFiAP.cpp line 259 8x4820b2f8: Loop_wrapper() at /home/gonit/.arduino15/packages/esp8266/hardware /esp8266/3.1.2/cores/esp8266/core_esp8266_main.cpp line 258
原Arduino代码
// 导入所需库 #include <Arduino.h> #ifdef ESP32 #include <WiFi.h> #include <AsyncTCP.h> #elif defined(ESP8266) #include <ESP8266WiFi.h> #include <ESPAsyncTCP.h> #endif #include <ESPAsyncWebServer.h> #include <FS.h> #include <ArduinoJson.h> String temp = ""; String pressure = ""; int range; String rain = ""; float lux; String light = ""; /* 填写你的SSID和密码 */ const char* ssid = "Weather Station"; // 输入SSID const char* password = "12345678"; // 输入密码 /* IP地址设置 */ IPAddress local_ip (192,168,1,1); IPAddress gateway(192,168,1,1); IPAddress subnet(255,255,255,0); // 创建端口80的AsyncWebServer对象 AsyncWebServer server(80); String processor(const String& var){ //Serial.println(var); if(var == "TEMP"){ return temp; } else if(var == "PRESSURE"){ return pressure; } else if(var == "RAIN"){ return rain; } else if(var == "LIGHT"){ return light; } return String(); } void setup() { // 初始化串口 Serial.begin(9600); while (!Serial) continue; if(SPIFFS.begin()==true) { Serial.println("SPIFFS初始化成功"); } WiFi.softAP(ssid, password); WiFi.softAPConfig(local_ip, gateway, subnet); delay(100); } void loop() { const size_t capacity = JSON_OBJECT_SIZE(128); DynamicJsonDocument doc(capacity); DeserializationError error = deserializeJson(doc, Serial); if (error) { Serial.print(F("deserializeJson()失败: ")); Serial.println(error.c_str()); return; } //serializeJson(doc, Serial); Serial.print("空气温度: "); temp = String(doc["temperature"]); Serial.print(temp); Serial.println(" *C"); Serial.print("空气压力: "); pressure = String(doc["pressure"]); Serial.print(pressure); Serial.println(" hPa"); Serial.print("降雨量: "); range = doc["range"]; switch (range){ case 0: rain = "下雨"; break; case 1: rain = "降雨预警"; break; case 2: rain = "无雨"; break; } Serial.println(rain); Serial.print("光照度: "); lux = doc["lux"]; if(lux < 100){ light = "昏暗"; } else if(lux > 100){ light = "明亮"; } Serial.println(light); Serial.println("-----------------------------------------"); server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/index.html", "text/html"); }); server.on("/assets/css/foundation.css", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/assets/css/foundation.css", "text/css"); }); server.on("/assets/js/vendor.js", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/assets/js/vendor.js", "text/js"); }); server.on("/assets/js/foundation.js", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/assets/js/foundation.js", "text/js"); }); server.on("/temp", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/plain", temp.c_str()); }); server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/plain", pressure.c_str()); }); server.on("/rain", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/plain", rain.c_str()); }); server.on("/light", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/plain", light.c_str()); }); server.begin(); //end }
问题根源与修复
核心问题
所有server.on()路由注册和server.begin()都放在了loop()函数中,每次循环都会重复注册相同路由,持续占用内存,最终导致内存耗尽触发设备重启。
修复代码
将路由注册和服务器启动代码移至setup()函数(仅需执行一次):
// 导入所需库 #include <Arduino.h> #ifdef ESP32 #include <WiFi.h> #include <AsyncTCP.h> #elif defined(ESP8266) #include <ESP8266WiFi.h> #include <ESPAsyncTCP.h> #endif #include <ESPAsyncWebServer.h> #include <FS.h> #include <ArduinoJson.h> String temp = ""; String pressure = ""; int range; String rain = ""; float lux; String light = ""; /* 填写你的SSID和密码 */ const char* ssid = "Weather Station"; // 输入SSID const char* password = "12345678"; // 输入密码 /* IP地址设置 */ IPAddress local_ip (192,168,1,1); IPAddress gateway(192,168,1,1); IPAddress subnet(255,255,255,0); // 创建端口80的AsyncWebServer对象 AsyncWebServer server(80); String processor(const String& var){ //Serial.println(var); if(var == "TEMP"){ return temp; } else if(var == "PRESSURE"){ return pressure; } else if(var == "RAIN"){ return rain; } else if(var == "LIGHT"){ return light; } return String(); } void setup() { // 初始化串口 Serial.begin(9600); while (!Serial) continue; if(SPIFFS.begin()==true) { Serial.println("SPIFFS初始化成功"); } WiFi.softAP(ssid, password); WiFi.softAPConfig(local_ip, gateway, subnet); delay(100); // 注册所有路由,仅执行一次 server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/index.html", "text/html"); }); server.on("/assets/css/foundation.css", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/assets/css/foundation.css", "text/css"); }); server.on("/assets/js/vendor.js", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/assets/js/vendor.js", "text/js"); }); server.on("/assets/js/foundation.js", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/assets/js/foundation.js", "text/js"); }); server.on("/temp", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/plain", temp.c_str()); }); server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/plain", pressure.c_str()); }); server.on("/rain", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/plain", rain.c_str()); }); server.on("/light", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/plain", light.c_str()); }); // 启动服务器,仅执行一次 server.begin(); } void loop() { const size_t capacity = JSON_OBJECT_SIZE(128); DynamicJsonDocument doc(capacity); DeserializationError error = deserializeJson(doc, Serial); if (error) { Serial.print(F("deserializeJson()失败: ")); Serial.println(error.c_str()); return; } //serializeJson(doc, Serial); Serial.print("空气温度: "); temp = String(doc["temperature"]); Serial.print(temp); Serial.println(" *C"); Serial.print("空气压力: "); pressure = String(doc["pressure"]); Serial.print(pressure); Serial.println(" hPa"); Serial.print("降雨量: "); range = doc["range"]; switch (range){ case 0: rain = "下雨"; break; case 1: rain = "降雨预警"; break; case 2: rain = "无雨"; break; } Serial.println(rain); Serial.print("光照度: "); lux = doc["lux"]; if(lux < 100){ light = "昏暗"; } else if(lux > 100){ light = "明亮"; } Serial.println(light); Serial.println("-----------------------------------------"); }
额外优化建议
- 将
DynamicJsonDocument声明为全局变量或使用StaticJsonDocument,减少loop()中的内存分配,降低碎片化风险。 - 所有串口打印字符串用
F()宏包裹,将字符串存储在Flash而非RAM中,节省内存。
内容的提问来源于stack exchange,提问作者Bimo
相关产品推荐
相关产品推荐

