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

ESP32保存时间至SPIFFS时触发重启的问题求助

ESP32点击网页按钮触发重启(LoadProhibited Guru Meditation Error)

我尝试通过ESP32托管的网页将当前时间与日期保存至SPIFFS,但点击按钮 <button type="button" onclick="sendTime()">Record Time&Date</button> 时,ESP32会立即触发重启,串口输出Guru Meditation Error(LoadProhibited)。


前端JavaScript代码

<script>
function sendTime() {
  // 获取当前时间和日期
  const now = new Date();
  const dateStr = now.toLocaleDateString();
  const timeStr = now.toLocaleTimeString();

  // 创建请求体
  const body = {
    date: dateStr,
    time: timeStr
  };

  // 向服务器发送HTTP POST请求
  fetch('/save-time', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(body)
  })
  .then(response => {
    if (!response.ok) {
      throw new Error('Error saving time to server');
    }
  })
  .catch(error => {
    console.error(error);
  });
}
</script>

ESP32服务端代码

使用的库:WiFi.h、FS.h、SPIFFS.h、Arduino.h、ArduinoJson.h 和 ESPAsyncWebServer.h

setup()代码片段

// 初始化SPIFFS
if (!SPIFFS.begin(true)) {
  Serial.println("Failed to mount file system");
  return;
}
Serial.println("SPIFFS mounted");

// 设置路由
server.on("/save-time", HTTP_POST, [](AsyncWebServerRequest *request){
  // 获取请求体字符串
  String body = request->getParam("plain")->value();

  // 解析JSON格式的请求体
  DynamicJsonDocument doc(1024);
  deserializeJson(doc, body);

  // 从请求体中获取日期和时间
  String dateStr = doc["date"].as<String>();
  String timeStr = doc["time"].as<String>();

  // 用日期创建文件名
  String fileName = "/watering-" + dateStr + ".txt";

  // 打开文件用于写入
  File file = SPIFFS.open(fileName, FILE_APPEND);
  if (!file) {
    Serial.println("Failed to open file for writing");
    request->send(500, "text/plain", "Failed to open file for writing");
    return;
  }

  // 写入时间到文件
  file.print(timeStr);
  file.print("\n");

  // 关闭文件
  file.close();

  // 返回成功响应
  request->send(200, "text/plain", "Time saved successfully");
});
// 获取浇水时间记录的路由
server.on("/watering-times", HTTP_GET, [](AsyncWebServerRequest *request){
  String response = "";

  // 获取根目录下的所有文件
  File root = SPIFFS.open("/");
  File file = root.openNextFile();
  while(file){
    // 检查文件名是否以"watering-"开头
    String fileName = file.name();
    if (fileName.startsWith("/watering-")) {
      // 读取文件内容并添加到响应字符串中
      response += fileName.substring(10, 20) + " " + file.readString() + "<br>";
    }
    file = root.openNextFile();
  }

  // 返回包含浇水时间记录的响应
  request->send(200, "text/html", response);
});

// 启动服务器
server.begin();

串口错误输出

Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0x400dec30  PS      : 0x00060e30  A0      : 0x800dec6e  A1      : 0x3ffd2280  
A2      : 0x3ffd230c  A3      : 0x00000010  A4      : 0x00000005  A5      : 0x0000ff00  
A6      : 0x00ff0000  A7      : 0xff000000  A8      : 0x800de95c  A9      : 0x3ffd2260  
A10     : 0x00000010  A11     : 0x00000000  A12     : 0x00000006  A13     : 0x3ffce334  
A14     : 0x00ff0000  A15     : 0x00000002  SAR     : 0x0000001b  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x0000001f  LBEG    : 0x40089db9  LEND    : 0x40089dc9  LCOUNT  : 0xfffffffe  


Backtrace: 0x400dec2d:0x3ffd2280 0x400dec6b:0x3ffd22a0 0x400d45a2:0x3ffd22c0 0x400d48a5:0x3ffd2390 0x400dbbf9:0x3ffd23b0 0x400d9fbd:0x3ffd2400 0x400da02d:0x3ffd2450 0x400dcca5:0x3ffd2470 0x400dcd21:0x3ffd24a0 0x400dd32a:0x3ffd24c0




ELF file SHA256: 78ff020431f74c0c

Rebooting...

问题原因及修复方案

核心问题

request->getParam("plain")->value() 直接访问了可能为空的指针。当请求为JSON格式时,plain 参数不一定存在,直接调用 ->value() 会触发空指针引用,导致LoadProhibited错误(访问无效内存地址)。

修复后的/save-time路由代码

server.on("/save-time", HTTP_POST, [](AsyncWebServerRequest *request){
  // 检查plain参数是否存在
  AsyncWebParameter* param = request->getParam("plain");
  if (!param) {
    Serial.println("No request body received");
    request->send(400, "text/plain", "Missing request body");
    return;
  }

  // 获取请求体字符串
  String body = param->value();

  // 解析JSON并检查错误
  DynamicJsonDocument doc(1024);
  DeserializationError jsonError = deserializeJson(doc, body);
  if (jsonError) {
    Serial.print("JSON parse failed: ");
    Serial.println(jsonError.c_str());
    request->send(400, "text/plain", "Invalid JSON format");
    return;
  }

  // 提取并验证日期、时间字段
  String dateStr = doc["date"].as<String>();
  String timeStr = doc["time"].as<String>();
  if (dateStr.isEmpty() || timeStr.isEmpty()) {
    Serial.println("Missing date or time in request");
    request->send(400, "text/plain", "Missing date or time");
    return;
  }

  // 替换日期中的非法字符(避免SPIFFS路径错误)
  dateStr.replace("/", "-");
  String fileName = "/watering-" + dateStr + ".txt";

  // 打开文件并写入
  File file = SPIFFS.open(fileName, FILE_APPEND);
  if (!file) {
    Serial.println("Failed to open file for writing");
    request->send(500, "text/plain", "Failed to open file for writing");
    return;
  }
  file.print(timeStr);
  file.print("\n");
  file.close();

  request->send(200, "text/plain", "Time saved successfully");
});

额外优化说明

  1. 空指针检查:先判断plain参数是否存在,避免直接访问空指针
  2. JSON解析校验:添加DeserializationError检查,处理无效JSON格式
  3. 文件名合法性:替换日期中的斜杠/为-,避免SPIFFS路径解析错误
  4. 参数有效性验证:确保日期和时间字段不为空

内容的提问来源于stack exchange,提问作者Svet GEoff

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 18:54:57