ESP32主Loop挂起问题:启用NOAuth变量后触发条件即卡顿
ESP32 Loop挂起问题(NOAuth赋值后阻塞)
我在ESP32的loop函数里用LoRa SX1278模块收消息,这部分功能正常。最初用定时器倒计时30秒关继电器,能工作但会阻塞主循环,导致30秒内发不了在线状态更新。
改用millis()做非阻塞延时后,只要取消注释NOAuth = 1这行,满足对应if条件时主Loop就会挂起,问题位置已在代码里标记。试过把NOAuth改成bool类型,问题依旧。用t0++的定时器能正常工作,但会阻塞主循环和在线状态发送。另外说明:继电器是DRV8210驱动的锁存继电器,只要发脉冲改状态,不用长时间通电。
原代码:
void loop() { int packetSize = LoRa.parsePacket(); if (forceConfig) { Serial.println("Config Mode initiated"); Serial.println("Turning the HotSpot On"); launchWeb(); startAP(); // Set up HotSpot } while ((WiFi.status() != WL_CONNECTED)) { Serial.print("."); delay(100); } float output_current = abs((return_current_value(OUTPUT_CURRENT_SENSE_PIN))) ; AN_Pot1_Raw = analogRead(OUTPUT_CURRENT_SENSE_PIN); AN_Pot1_Filtered = readADC_Avg(output_current); delay(10); // SYNC States with on line if (digitalRead(LED) == 1) { digitalWrite(OUTPUT_PIN, HIGH); } else { digitalWrite(OUTPUT_PIN, LOW); } // System Working-flash green light digitalWrite(LED2, HIGH); delay(500); if ((millis() - oldMillis) > flashgreenled2) { oldMillis = millis(); digitalWrite(LED2, LOW); } // check for incoming msgs from LoRa if (output1 == "") { Online(); } // check for incoming msgs if (output1 == tag1 || output1 == tag2) { output1 = "user"; t0 = 0; Serial.println (" Turning on power user"); Serial.println (" Turning on LED"); digitalWrite(LED, HIGH); // for testing RelayON(); sendUpdate(); output1 = ""; // clear the output string so no match found } // check for incoming msgs if (output1 == ctag1) { output1 = "user1"; t0 = 0; Serial.println (" Turning on power for user1"); Serial.println (" Turning on LED"); digitalWrite(LED, HIGH); // for testing RelayON(); sendUpdate(); output1 = ""; // clear the output string so no match found } // check for incoming msgs if (output1 == "NoAuth" && NOAuth == 0) { OffMillis = millis(); NOAuth = 1; //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< IF THIS ISN'T COMMENTED OUT, IT STOPS output1 = ""; Serial.println("***************************************Initiated power off Timer"); infoln(t0); } // Poweroff if ((millis() - OffMillis) == 1000) { Serial.println (" Turning off power"); Serial.println (" Turning off LED"); digitalWrite(LED, LOW); RelayOFF(); output1 = ""; digitalWrite(OUTPUT_PIN, LOW); NOAuth == 0; } drd->loop(); }
问题定位与修复
致命错误:赋值写成比较
关继电器的分支里,NOAuth == 0是比较操作,不是赋值,应该改成NOAuth = 0。这会导致NOAuth一直保持1,后续逻辑无法正常重置,加上精确时间匹配的问题,直接导致这个分支永远不执行,NOAuth永远无法复位,进而引发逻辑异常。精确时间匹配不可靠
(millis() - OffMillis) == 1000这种写法完全依赖loop刚好在millis()等于OffMillis+1000时执行到这行,概率极低,大概率永远触发不了。必须改成>= 1000,确保时间到了就执行。其他阻塞点优化
delay(500)会直接卡主循环半秒,严重影响实时性,改成用millis()实现非阻塞闪烁。while ((WiFi.status() != WL_CONNECTED))是死循环,WiFi断了就彻底卡死loop,改成单次判断+短延时,不要死等。
修改后的代码
void loop() { int packetSize = LoRa.parsePacket(); if (forceConfig) { Serial.println("Config Mode initiated"); Serial.println("Turning the HotSpot On"); launchWeb(); startAP(); // Set up HotSpot } // 非阻塞检查WiFi,避免死循环 if (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(100); // 尽量换成millis()控制打印频率,这里先保留短延时 } float output_current = abs(return_current_value(OUTPUT_CURRENT_SENSE_PIN)); AN_Pot1_Raw = analogRead(OUTPUT_CURRENT_SENSE_PIN); AN_Pot1_Filtered = readADC_Avg(output_current); delay(10); // 能去掉最好,或者用非阻塞ADC读取逻辑 // 简化状态同步代码 digitalWrite(OUTPUT_PIN, digitalRead(LED)); // 非阻塞实现LED2闪烁 unsigned long currentMillis = millis(); if (currentMillis - oldMillis >= flashgreenled2) { oldMillis = currentMillis; digitalWrite(LED2, !digitalRead(LED2)); // 翻转状态,替代固定亮500ms } // 发送在线状态 if (output1 == "") { Online(); } // 处理用户1/2的开机指令 if (output1 == tag1 || output1 == tag2) { output1 = "user"; t0 = 0; Serial.println (" Turning on power user"); Serial.println (" Turning on LED"); digitalWrite(LED, HIGH); RelayON(); sendUpdate(); output1 = ""; } // 处理user1的开机指令 if (output1 == ctag1) { output1 = "user1"; t0 = 0; Serial.println (" Turning on power for user1"); Serial.println (" Turning on LED"); digitalWrite(LED, HIGH); RelayON(); sendUpdate(); output1 = ""; } // 启动断电定时器 if (output1 == "NoAuth" && NOAuth == 0) { OffMillis = millis(); NOAuth = 1; output1 = ""; Serial.println("***************************************Initiated power off Timer"); infoln(t0); } // 执行断电逻辑 - 修复时间判断和赋值错误 if (NOAuth == 1 && (millis() - OffMillis) >= 1000) { Serial.println (" Turning off power"); Serial.println (" Turning off LED"); digitalWrite(LED, LOW); RelayOFF(); output1 = ""; digitalWrite(OUTPUT_PIN, LOW); NOAuth = 0; // 这里是赋值,不是比较 } drd->loop(); }
额外优化建议
- 把所有
delay()都换成millis()实现非阻塞逻辑,确保loop能快速循环,不耽误LoRa接收、在线状态发送。 - WiFi连接检查可以加超时,比如尝试10秒连不上就启动AP,不要一直打印点。
- 把
NOAuth改成bool类型,比如叫isPowerOffTimerRunning,代码可读性更高。
内容的提问来源于stack exchange,提问作者hatzo
相关产品推荐
相关产品推荐

