ESP32提交Web参数后WiFi关闭触发LoadProhibited重启问题
ESP32 AsyncWebServer关闭WiFi后触发LoadProhibited重启问题解决
问题现象
提交Web服务器参数后,WiFi成功关闭,但随即触发Guru Meditation Error: Core 0 panic'ed (LoadProhibited)未处理异常,导致ESP32重启并从头执行程序。
问题分析
从错误栈回溯可以明确,异常发生在AsyncTCP的异步接收任务中,核心原因是关闭WiFi的时机错误:在POST请求的回调函数里直接调用disableWifi()时,AsyncWebServer尚未完成HTTP响应的完整发送流程,TCP连接的底层资源仍在被使用。此时强制关闭WiFi会导致TCP栈尝试访问已释放的WiFi相关内存,触发非法内存访问错误。
同时代码存在几个隐性隐患:
- 在异步请求回调中直接修改全局状态并操作硬件资源,违背异步服务器的事件处理逻辑
wifiResult()函数每次loop循环都重复执行pinMode(TOUCH_PIN,INPUT_PULLUP),属于冗余操作- 多次启动WiFi时可能重复初始化AsyncWebServer,引发资源冲突
解决方案
核心修复思路
确保HTTP响应完全发送完成后,再停止AsyncWebServer并关闭WiFi,通过延迟执行或标志位触发的方式,避免底层资源冲突。
具体代码修改
1. 调整POST回调的WiFi关闭逻辑
移除回调中直接关闭WiFi的代码,改为设置延迟关闭标志,确保响应发送完成:
// 在wifiModule.cpp中新增全局变量 bool needDisableWifi = false; unsigned long disableWifiDelay = 0; const unsigned long waitResponseTime = 1000; // 预留1秒确保响应发送完成 void ESPAsyncWebServer() { server.on("/submit", HTTP_POST, [](AsyncWebServerRequest *request) { String dateTime="", timezone=""; if (request->hasParam("time", true) && request->hasParam("timezone", true)) { dateTime = request->getParam("time", true)->value(); timezone = request->getParam("timezone", true)->value(); globalDateTime= dateTime; globalTimezone= timezone; Serial.print("Date & Time: "); Serial.println(globalDateTime); Serial.print("Timezone: "); Serial.println(globalTimezone); int year,month, day, hour, minute,second; parseDateTime(year,month,day, hour, minute, second); } request->send(200, "text/plain", "Submitted! Date & Time: " + dateTime + " Timezone: " + timezone); // 设置延迟关闭标志,不在回调中直接操作硬件 needDisableWifi = true; disableWifiDelay = millis(); }); server.begin(); Serial.println("Wi-Fi enabled and AP started."); }
2. 在Loop中处理延迟关闭逻辑
新增专门的检查函数,在主循环中处理WiFi关闭:
// 在wifiModule.cpp中新增处理函数 void checkWifiDisable() { if (needDisableWifi && millis() - disableWifiDelay >= waitResponseTime) { server.end(); // 先停止AsyncWebServer,释放TCP资源 disableWifi(); wifiEnabled = false; needDisableWifi = false; Serial.println("Wi-Fi disabled after waiting for response completion."); } } // 修改main.cpp中的loop函数,新增检查调用 void loop() { Serial.print("Free heap memory: "); Serial.println(ESP.getFreeHeap()); wifiResult(); checkWifiDisable(); // 新增延迟关闭检查 spa_result(); delay(500); }
3. 修复冗余的Pin初始化
修改wifiResult(),将Pin模式初始化改为只执行一次:
void wifiResult() { static bool pinInitialized = false; if (!pinInitialized) { pinMode(TOUCH_PIN, INPUT_PULLUP); pinInitialized = true; } int buttonState = digitalRead(TOUCH_PIN); Serial.print("Button State: "); Serial.println(buttonState); if (buttonState != lastButtonState) { if(buttonState == LOW ) { if(millis()-lastDebounceTime > debounceDelay){ wifiEnabled = !wifiEnabled; if(wifiEnabled) { WifiStart(); Serial.println("Wi-Fi is ON"); } else{ server.end(); // 按钮关闭时先停止服务器 disableWifi(); Serial.println("Wi-Fi is OFF"); } lastDebounceTime=millis(); } } } lastButtonState=buttonState; }
4. 避免重复初始化服务器
修改WifiStart(),确保服务器只初始化一次:
void WifiStart() { if(wifiEnabled) { WiFi.softAPdisconnect(true); WiFi.mode(WIFI_AP); if (WiFi.softAP(ssid, password)) { IPAddress myIP = WiFi.softAPIP(); Serial.print("AP IP address: "); Serial.println(myIP); // 避免重复初始化服务器 static bool serverInitialized = false; if (!serverInitialized) { ESPAsyncWebServer(); serverInitialized = true; } else { server.begin(); // 若之前停止过,重新启动服务器 } } else { Serial.println("Failed to start AP"); } } else{ server.end(); disableWifi(); } }
验证效果
修改后,提交参数后服务器会先完成响应发送,等待1秒确保TCP连接资源释放后,再停止服务器并关闭WiFi,不会再触发LoadProhibited异常,同时时间设置逻辑可正常运行。
内容的提问来源于stack exchange,提问作者Charan kalidindi
相关产品推荐
相关产品推荐

