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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 21:25:19