Arduino Metro M4控制器EEPROM函数无法保存数据求助
解决Adafruit Metro M4(SAMD51)上EEPROM数据不持久的问题
核心问题分析
Metro M4基于SAMD51芯片,Arduino核心对其EEPROM的实现是Flash模拟,和AVR(如Uno)的硬件EEPROM机制完全不同。你的代码缺少关键的初始化步骤,同时存在字符串存储的细节问题,导致数据无法正确保留。
具体修复步骤
1. 必须初始化EEPROM模拟存储空间
SAMD系列芯片需要在setup()中显式调用EEPROM.begin(size)来初始化模拟EEPROM的缓存和Flash分区,size是你需要使用的存储大小(比如512字节,根据数据量调整),这是你代码里最关键的遗漏项。
2. 修正字符串存储的结束符问题
你的readString直接读取16个字符但未处理字符串结束符,会导致读取到垃圾数据;saveString需要在字符串末尾写入'\0'标记结束位置。
3. 优化Flash写入频率
每次调用EEPROM.commit()都会把整个缓存写入Flash,频繁调用会加速Flash磨损,建议批量操作完成后统一执行commit。
4. 验证地址范围
确保所有ADDR_*宏定义的地址不超过你初始化的EEPROM大小(比如初始化512字节的话,地址必须在0~511之间)。
修改后的完整代码片段
// 定义所需的EEPROM存储大小,根据实际数据量调整 #define EEPROM_SIZE 512 // 示例地址宏定义(请根据你的实际定义替换) #define ADDR_MAGIC_NUMBER 0 #define ADDR_AVERAGE_DAYS 1 #define ADDR_LOGGED_COUNT 2 #define ADDR_PERIOD_STATE 3 #define ADDR_START_TIME {4, 8, 12, 16, 20} #define ADDR_END_TIME {24, 28, 32, 36, 40} #define ADDR_SYMPTOMS {{44,54,64,74,84}, {94,104,114,124,134}, {144,154,164,174,184}, {194,204,214,224,234}, {244,254,264,274,284}} void setup() { Serial.begin(9600); // 关键:初始化EEPROM模拟空间 EEPROM.begin(EEPROM_SIZE); checkResetEEPROM(); readAllConfiguration(); } void readAllConfiguration() { readLogs(); AveragePeriodDuration = EEPROM.read(ADDR_AVERAGE_DAYS); LogId = EEPROM.read(ADDR_LOGGED_COUNT); Serial.print("Log ID mem: "); Serial.println(LogId); if(LogId > 100) LogId = 0; if (AveragePeriodDuration > 100) AveragePeriodDuration = 28; } bool checkResetEEPROM() { uint8_t number = EEPROM.read(ADDR_MAGIC_NUMBER); Serial.print("Magic number: "); Serial.println(number); if (number != MAGIC_NUMBER) { for (uint8_t i=0; i<5; i++) { saveLong(ADDR_START_TIME[i], 0); saveLong(ADDR_END_TIME[i], 0); for(uint8_t x=0; x<5; x++) saveString(ADDR_SYMPTOMS[i][x], ""); } EEPROM.write(ADDR_PERIOD_STATE, 0); EEPROM.write(ADDR_AVERAGE_DAYS, 28); EEPROM.write(ADDR_MAGIC_NUMBER, MAGIC_NUMBER); EEPROM.commit(); // 统一执行一次写入 Serial.println(EEPROM.read(ADDR_MAGIC_NUMBER)); return true; } return false; } void readLogs() { if (LogId == 0) return; for (uint8_t i=0; i<5; i++) { LogCycle[i].StartTime = readLong(ADDR_START_TIME[i]); LogCycle[i].EndTime = readLong(ADDR_END_TIME[i]); for (uint8_t x=0; x<5; x++) LogCycle[i].symptoms[x] = readString(ADDR_SYMPTOMS[i][x]); } } // 修正字符串存储:添加结束符 void saveString(int addr, const String &strToWrite) { byte len = strToWrite.length(); // 限制长度不超过15,留一个字节存结束符 if (len > 15) len = 15; for (int i = 0; i < len; i++){ EEPROM.update(addr + i, strToWrite[i]); } // 写入字符串结束标记 EEPROM.update(addr + len, '\0'); } // 修正字符串读取:读到结束符停止 String readString(int addr) { char read_data[16]; int i = 0; while (i < 15) { read_data[i] = EEPROM.read(addr + i); if (read_data[i] == '\0') break; i++; } read_data[i] = '\0'; // 确保字符串正确结束 return String(read_data); } uint32_t readLong(int addr) { long Byte4 = EEPROM.read(addr); long Byte3 = EEPROM.read(addr + 1); long Byte2 = EEPROM.read(addr + 2); long Byte1 = EEPROM.read(addr + 3); return ((Byte4 << 0) & 0xFF) + ((Byte3 << 8) & 0xFFFF) + ((Byte2 << 16) & 0xFFFFFF) + ((Byte1 << 24) & 0xFFFFFFFF); } // 移除内部commit,交给上层批量处理 void saveLong(int addr, uint32_t val) { byte Byte4 = ((val >> 0) & 0xFF); byte Byte3 = ((val >> 8) & 0xFF); byte Byte2 = ((val >> 16) & 0xFF); byte Byte1 = ((val >> 24) & 0xFF); EEPROM.write(addr, Byte4); EEPROM.write(addr + 1, Byte3); EEPROM.write(addr + 2, Byte2); EEPROM.write(addr + 3, Byte1); } void saveOneCycle(uint8_t i) { saveLong(ADDR_START_TIME[i], LogCycle[i].StartTime); saveLong(ADDR_END_TIME[i], LogCycle[i].EndTime); for(uint8_t x=0; x<5; x++) saveString(ADDR_SYMPTOMS[i][x], LogCycle[i].symptoms[x]); EEPROM.commit(); // 批量写入后统一提交 } void saveAllCycles() { for(uint8_t i=0; i<5; i++) { saveLong(ADDR_START_TIME[i], LogCycle[i].StartTime); saveLong(ADDR_END_TIME[i], LogCycle[i].EndTime); for(uint8_t x=0; x<5; x++) saveString(ADDR_SYMPTOMS[i][x], LogCycle[i].symptoms[x]); } EEPROM.commit(); // 统一提交所有更改 }
额外注意事项
- SAMD芯片的模拟EEPROM存储在Flash中,写入次数有限(约10万次),避免高频次写入操作。
- 如果你已经配备了SD卡,也可以考虑将配置和日志数据写入SD卡,比模拟EEPROM更适合存储大量数据。
内容的提问来源于stack exchange,提问作者user15881691
相关产品推荐
相关产品推荐

