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
相关产品推荐
相关产品推荐

