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

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();
}

问题定位与修复

  1. 致命错误:赋值写成比较
    关继电器的分支里,NOAuth == 0是比较操作,不是赋值,应该改成NOAuth = 0。这会导致NOAuth一直保持1,后续逻辑无法正常重置,加上精确时间匹配的问题,直接导致这个分支永远不执行,NOAuth永远无法复位,进而引发逻辑异常。

  2. 精确时间匹配不可靠
    (millis() - OffMillis) == 1000这种写法完全依赖loop刚好在millis()等于OffMillis+1000时执行到这行,概率极低,大概率永远触发不了。必须改成>= 1000,确保时间到了就执行。

  3. 其他阻塞点优化

    • 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 16:54:55