You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32 WebServer输入错误WiFi触发看门狗复位问题求助

ESP32 AP模式WiFi配置触发看门狗复位问题排查与解决

问题现象

使用ESP32开发板实现AP模式引导用户输入WiFi信息,配置完成后切换到STA模式启动WebServer。输入正确WiFi信息时设备可正常连接运行;但输入错误信息时,连接失败分支输出debug4后5秒触发看门狗复位,设备重启。

串口日志

19:18:44:830 -> Trying to connect...
19:18:45:330 -> Trying to connect...
19:18:45:332 -> debug
19:18:45:333 -> debug4
19:18:50:330 -> E (20302) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
19:18:50:339 -> E (20302) task_wdt:  - async_tcp (CPU 0/1)
19:18:50:343 -> E (20302) task_wdt: Tasks currently running:
19:18:50:347 -> E (20302) task_wdt: CPU 0: IDLE
19:18:50:350 -> E (20302) task_wdt: CPU 1: loopTask
19:18:50:353 -> E (20302) task_wdt: Aborting.
19:18:50:356 -> 
19:18:50:356 -> abort() was called at PC 0x400e8e95 on core 0
19:18:50:360 -> 
19:18:50:360 -> 
19:18:50:361 -> Backtrace: 0x4008389d:0x3ffbec3c |<-CORRUPTED
19:18:50:365 -> 
19:18:50:365 -> 
19:18:50:365 -> 
19:18:50:365 -> 
19:18:50:365 -> ELF file SHA256: 12c7e27a4eeae93f
19:18:50:368 -> 
19:18:50:846 -> Rebooting...
19:18:50:848 -> ets Jul 29 2019 12:21:46

现有代码

void startAPMode() {
    if (apmode == true) {
        WiFi.mode(WIFI_AP_STA);
        WiFi.softAP(apSSID, apPassword);

        apServer.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
            request->send(200, "text/html", ap_mode_html);
            });

        apServer.on("/setup", HTTP_GET, [](AsyncWebServerRequest* request) {
            if (request->hasParam("ssid") && request->hasParam("password")) {
                String ssid = request->getParam("ssid")->value();
                String password = request->getParam("password")->value();
                WiFi.begin(ssid.c_str(), password.c_str());

                unsigned long startTime = millis();
                bool connectionSuccessful = false;

                while (millis() - startTime < 10000) {
                    esp_task_wdt_reset(); // Reset Watchdog Timer
                    if (WiFi.status() == WL_CONNECTED) {
                        connectionSuccessful = true;
                        break;
                    }
                    delay(500);
                    Serial.println("Versuche zu verbinden...");
                }
                //esp_task_wdt_reset();
                Serial.println("debug");
                if (connectionSuccessful) {
                    IPAddress wifiIP = WiFi.localIP();
                    String response = R"html(
                            <!DOCTYPE html>
                            <html>
                            <head>
                                <title>Verbindung Erfolgreich</title>
                                <style>
                                    html, body { font-family: Arial, sans-serif; margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; flex-direction: column; }
                                    .container { padding: 20px; border: 1px solid #ddd; border-radius: 5px; background-color: #fff; box-shadow: 0 2px 4px rgba(0,0,0,0.1); max-width: 90%; }
                                    .ip-address { font-weight: bold; margin-top: 20px; padding: 10px; background-color: #e9ecef; border-radius: 5px; }
                                </style>
                            </head>
                            <body>
                                <div class='container'>
                                    Verbindung erfolgreich! Bitte diese IP Adresse aufschreiben oder merken. &Uuml;ber diese IP Adresse kann nun immer die Fenstersteuerung aufgerufen werden!
                                    <div class='ip-address'>Die IP Adresse f&uuml;r die Webseite ist: )html" + wifiIP.toString() + R"html(</div>
                                </div>
                            </body>
                            </html>
                            )html";
                    request->send(200, "text/html", response);
                    Serial.println("debug2");
                    setupWiFiAndWebServer();
                    Serial.println("debug3");
                }
                else {
                    esp_task_wdt_reset();
                    Serial.println("debug4");
                    //WiFi.disconnect(); // Optional: trennt die Verbindung, wenn nicht erfolgreich
                    String response = "Connection failed! <a href='/'>Try again</a>";
                    request->send(200, "text/html", response);
                    Serial.println("debug5");
                    startAPMode();
                }
            }
            else {
                esp_task_wdt_reset();
                request->send(200, "text/html", "Missing data! <a href='/'>Back</a>");
                startAPMode();
            }
            });

        apServer.begin();
        Serial.println("AP-Modus Webserver gestartet auf " + WiFi.softAPIP().toString());
    }
}

问题根源

  1. 阻塞AsyncWebServer回调线程:在/setup的GET请求回调中,使用while循环等待WiFi连接,最长阻塞10秒。AsyncWebServer依赖async_tcp任务处理请求,长时间阻塞会导致该任务无法喂狗,触发看门狗超时。
  2. 递归调用startAPMode():连接失败或参数缺失时递归调用startAPMode(),会重复初始化AP和WebServer,导致任务调度混乱,同时可能造成栈溢出,进一步加剧看门狗触发风险。
  3. WiFi状态未清理:连接失败后未彻底断开WiFi,残留的连接状态可能干扰后续操作,延长任务阻塞时间。

解决方案

1. 改用非阻塞式WiFi连接(状态机管理)

将WiFi连接逻辑从请求回调中移出,放到loop()函数里用状态机管理,避免阻塞async_tcp任务:

// 定义全局状态变量
enum DeviceState {
    STATE_AP_WAIT_INPUT,
    STATE_WIFI_CONNECTING,
    STATE_WIFI_CONNECTED,
    STATE_WIFI_FAILED
};
DeviceState currentState = STATE_AP_WAIT_INPUT;
String targetSSID, targetPassword;
unsigned long connectStartTime;
bool apmode = false;
AsyncWebServer apServer(80);
const char* apSSID = "ESP32-Setup";
const char* apPassword = "12345678";
const char* ap_mode_html = "<html><body><form action='/setup' method='GET'>SSID: <input type='text' name='ssid'><br>Password: <input type='password' name='password'><br><input type='submit' value='Connect'></form></body></html>";

void setup() {
    Serial.begin(115200);
    startAPMode();
}

void loop() {
    switch(currentState) {
        case STATE_WIFI_CONNECTING:
            if(millis() - connectStartTime > 10000) {
                // 连接超时,标记失败
                currentState = STATE_WIFI_FAILED;
                WiFi.disconnect(true); // 彻底断开WiFi
                startAPMode(); // 回到AP模式
            } else if(WiFi.status() == WL_CONNECTED) {
                currentState = STATE_WIFI_CONNECTED;
                setupWiFiAndWebServer();
            }
            break;
        case STATE_WIFI_FAILED:
            // 无需额外操作,已回到AP模式等待用户重试
            break;
        default:
            break;
    }
}

void startAPMode() {
    apmode = true;
    WiFi.mode(WIFI_AP_STA);
    WiFi.softAP(apSSID, apPassword);

    apServer.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
        request->send(200, "text/html", ap_mode_html);
    });

    apServer.on("/setup", HTTP_GET, [](AsyncWebServerRequest* request) {
        if (request->hasParam("ssid") && request->hasParam("password")) {
            targetSSID = request->getParam("ssid")->value();
            targetPassword = request->getParam("password")->value();
            
            // 启动WiFi连接,切换状态
            currentState = STATE_WIFI_CONNECTING;
            connectStartTime = millis();
            WiFi.begin(targetSSID.c_str(), targetPassword.c_str());

            // 立即返回响应,不等待连接结果
            request->send(200, "text/html", "Connecting to WiFi... Please refresh later or check the device status.");
        } else {
            request->send(200, "text/html", "Missing data! <a href='/'>Back</a>");
        }
    });

    apServer.begin();
    Serial.println("AP-Modus Webserver gestartet auf " + WiFi.softAPIP().toString());
}

// 示例WebServer初始化函数
void setupWiFiAndWebServer() {
    apmode = false;
    apServer.end(); // 关闭AP模式的WebServer
    // 初始化STA模式下的WebServer逻辑
    Serial.println("STA WebServer initialized");
}

2. 移除递归调用,避免重复初始化

连接失败时直接切换状态回AP模式,无需重复调用startAPMode()。如果需要重置AP配置,可单独写一个重置函数,而非递归触发整个流程。

3. 彻底清理WiFi状态

连接失败时调用WiFi.disconnect(true),清除之前的连接信息,确保下次连接不受干扰。

4. 替代手动喂狗的根本方案

手动喂狗只是临时 workaround,正确的做法是不要在异步任务回调中执行阻塞操作。所有耗时操作(如WiFi连接、传感器读取)都应放到独立的FreeRTOS任务或loop()的非阻塞逻辑中,保证async_tcp等系统任务能正常调度,自然不会触发看门狗。

内容的提问来源于stack exchange,提问作者Friedrich Harald

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 16:24:58