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

ESP8266 Flash内存读取失败求助:WeMos D1板SPIFFS读写异常

问题分析与解决方案

核心问题点

1. 数组退化为指针导致的长度错误

函数参数char ssid[]在函数内部会被解析为char*指针,因此sizeof(ssid)返回的是指针的字节数(ESP8266上为4字节),而非传入数组的实际长度。这会导致:

  • 写入的字节数远小于实际SSID/PWD的长度
  • 读取缓冲区ssidbuff、pwdbuff的大小被错误设置为4字节,无法容纳完整数据

2. Flash操作的对齐与长度限制

ESP8266的flashWrite和flashRead底层基于32位字操作,要求操作长度必须是4字节的整数倍。如果传入的长度不是4的倍数,会触发读取失败。

3. 地址区域可能存在冲突

你指定的0x3FA000~0x3FB000扇区,可能与系统预留区域、EEPROM分区或SPIFFS分区重叠,导致写入后无法正常读取。


修复后的代码示例

方案1:修正裸Flash操作的问题

// 传入字符串长度,避免指针退化问题
void writeToFlash(const char* ssid, const char* pwd) {
  // 选择未被系统占用的Flash扇区(建议查看开发板分区表确认)
  const uint32_t addrstart = 0x3E0000; 
  const uint32_t sector = addrstart >> 12; // 转换为扇区号

  // 擦除扇区
  if (!ESP.flashEraseSector(sector)) {
    Serial.println("\nErase error");
    return;
  }
  Serial.println("\nErase OK\n----------------");

  // 处理SSID:计算对齐后的长度(向上取整到4的倍数)
  size_t ssid_len = strlen(ssid) + 1; // 包含终止符
  size_t ssid_aligned_len = ((ssid_len + 3) / 4) * 4;
  uint32_t ssid_addr = addrstart;

  // 写入SSID
  if (!ESP.flashWrite(ssid_addr, (uint32_t*)ssid, ssid_aligned_len)) {
    Serial.printf("0: [error] write addr: %p\n", ssid_addr);
  } else {
    Serial.printf("0: addr: %p write [%s] OK\n", ssid_addr, ssid);
  }

  // 读取SSID到缓冲区
  char ssidbuff[64]; // 固定足够大的缓冲区
  memset(ssidbuff, '\0', sizeof(ssidbuff));
  if (!ESP.flashRead(ssid_addr, (uint32_t*)ssidbuff, ssid_aligned_len)) {
    Serial.printf("0: [error] read addr: %p\n", ssid_addr);
  } else {
    Serial.printf("0: addr: %p read [%s] OK\n", ssid_addr, ssidbuff);
  }

  // 对比数据
  if (strcmp(ssid, ssidbuff) != 0) {
    Serial.printf("0: addr: %p, In != Out\n", ssid_addr);
  } else {
    Serial.printf("0: addr: %p compare OK\n", ssid_addr);
  }
  Serial.print("读取记忆体的值: ");
  Serial.println(ssidbuff);

  // 同理处理PWD...
}

方案2:推荐使用SPIFFS文件系统(更安全可靠)

直接操作裸Flash容易踩分区冲突、对齐等坑,推荐使用官方SPIFFS库来存储数据:

#include <FS.h>

void setup() {
  Serial.begin(115200);
  if (!SPIFFS.begin()) {
    Serial.println("SPIFFS挂载失败");
    return;
  }

  // 写入数据
  File file = SPIFFS.open("/wifi.txt", "w");
  if (file) {
    file.println("Raden-External");
    file.println("+23277176+");
    file.close();
    Serial.println("写入成功");
  } else {
    Serial.println("写入失败");
  }

  // 读取数据
  file = SPIFFS.open("/wifi.txt", "r");
  if (file) {
    String ssid = file.readStringUntil('\n');
    String pwd = file.readStringUntil('\n');
    ssid.trim(); // 去除换行符
    pwd.trim();
    Serial.printf("读取SSID: %s, PWD: %s\n", ssid.c_str(), pwd.c_str());
    file.close();
  } else {
    Serial.println("读取失败");
  }
}

void loop() {}

关键注意事项

  • 避免直接操作裸Flash:ESP8266的Flash分区由系统管理,随意指定地址容易覆盖系统数据,推荐使用SPIFFS或EEPROM库。
  • 指针退化问题:函数参数中的数组会退化为指针,必须显式传入长度或用strlen获取字符串长度。
  • Flash操作对齐:所有flashWrite/flashRead的长度必须是4字节的整数倍,否则会触发操作失败。

内容的提问来源于stack exchange,提问作者Yao Chang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 03:57:45