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

ESP8266将字符串首字符替换为逗号并存入EEPROM的技术问询

合理性验证与优化建议

合理性验证

你的实现已经完成了核心功能:通过WiFiManager获取用户配置参数、写入EEPROM并读取,且首次配置和后续WiFi重连后的读写逻辑都能正常工作,拆分参数的方式也可行。但存在一些潜在问题,会影响代码的稳定性、可读性和硬件寿命,具体如下:

  • loop中重复初始化WiFiManager实例,造成资源浪费
  • 每次WiFi连接时都执行EEPROM写入,频繁操作会缩短模拟EEPROM的寿命(ESP8266的模拟EEPROM约10万次写入上限)
  • 字符串处理逻辑不符合需求:当前是直接在字符串末尾加逗号,而非首字符替换为逗号
  • 读取EEPROM时固定读取32字节,未处理字符串结束符,导致串口输出出现乱码(那些⸮字符)
  • 变量命名模糊(如uuu、www、vvv),降低代码可读性
  • WiFi重连时使用delay(60000)阻塞程序,期间无法处理其他任务

优化建议

1. 全局复用WiFiManager实例,优化重连逻辑

不要在loop中重复创建WiFiManager对象,全局声明一次;重连时避免使用长delay,改用非阻塞的时间判断:

#include <ESP8266WiFi.h>
#include <WiFiManager.h>
#include <EEPROM.h>

// 全局变量
WiFiManager wifiManager;
char authorizationKey[32] = "";
char apiKey[32] = "";
char userNameKey[32] = "";
unsigned long lastReconnectAttempt = 0;
const unsigned long reconnectInterval = 60000;

void setup() {
  Serial.begin(115200);
  
  WiFiManagerParameter customAPIKey("authorizationKey", "Authorization Code", authorizationKey, 32);
  WiFiManagerParameter customAPIKey2("apiKey", "Time Zone #", apiKey, 32);
  WiFiManagerParameter customAPIKey3("userNameKey", "User Name", userNameKey, 32);

  wifiManager.addParameter(&customAPIKey);
  wifiManager.addParameter(&customAPIKey2);
  wifiManager.addParameter(&customAPIKey3); 

  // 首次配置或WiFi失败时启动配网
  if (!wifiManager.autoConnect("FloWT3")) {
    Serial.println("配网超时,重启设备");
    ESP.restart();
    delay(1000);
  }
  
  // 更新参数到全局变量
  strcpy(authorizationKey, customAPIKey.getValue());
  strcpy(apiKey, customAPIKey2.getValue());
  strcpy(userNameKey, customAPIKey3.getValue());
  
  // 仅在参数更新时写入EEPROM
  saveParamsToEEPROM();
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    unsigned long currentMillis = millis();
    if (currentMillis - lastReconnectAttempt >= reconnectInterval) {
      lastReconnectAttempt = currentMillis;
      Serial.println("尝试重连WiFi...");
      if (wifiManager.autoConnect("FloWT3")) {
        Serial.println("重连成功,更新参数");
        strcpy(authorizationKey, wifiManager.getParameter("authorizationKey")->getValue());
        strcpy(apiKey, wifiManager.getParameter("apiKey")->getValue());
        strcpy(userNameKey, wifiManager.getParameter("userNameKey")->getValue());
        saveParamsToEEPROM();
      }
    }
  } else {
    // 连接成功后的业务逻辑,避免频繁读取可调整间隔
    readParamsFromEEPROM();
    delay(5000);
  }
}

2. 修正首字符替换逻辑,规范变量命名

原代码是在字符串末尾加逗号,不符合“首字符替换为逗号”的需求,修正如下:

// 处理首字符替换为逗号的逻辑
String processParam(String param) {
  if (param.length() == 0) return "";
  param[0] = ',';
  return param;
}

3. 优化EEPROM读写,减少写入次数

封装读写函数,仅在参数更新时写入;写入时添加字符串结束符,读取时读到结束符停止,避免乱码:

// EEPROM地址宏定义,便于维护
#define AUTH_KEY_ADDR 0x0F
#define API_KEY_ADDR 0x50
#define USER_NAME_ADDR 0x90
#define MAX_PARAM_LEN 32

void saveParamsToEEPROM() {
  EEPROM.begin(512);
  
  // 写入authorizationKey(无需替换首字符)
  for (int i = 0; i < strlen(authorizationKey); i++) {
    EEPROM.write(AUTH_KEY_ADDR + i, authorizationKey[i]);
  }
  EEPROM.write(AUTH_KEY_ADDR + strlen(authorizationKey), '\0'); // 添加结束符
  
  // 写入处理后的apiKey
  String processedApiKey = processParam(String(apiKey));
  for (int i = 0; i < processedApiKey.length(); i++) {
    EEPROM.write(API_KEY_ADDR + i, processedApiKey[i]);
  }
  EEPROM.write(API_KEY_ADDR + processedApiKey.length(), '\0');
  
  // 写入处理后的userNameKey
  String processedUserName = processParam(String(userNameKey));
  for (int i = 0; i < processedUserName.length(); i++) {
    EEPROM.write(USER_NAME_ADDR + i, processedUserName[i]);
  }
  EEPROM.write(USER_NAME_ADDR + processedUserName.length(), '\0');
  
  EEPROM.commit();
  EEPROM.end(); // 释放资源
}

void readParamsFromEEPROM() {
  EEPROM.begin(512);
  
  String authKey;
  for (int i = 0; i < MAX_PARAM_LEN; i++) {
    char c = EEPROM.read(AUTH_KEY_ADDR + i);
    if (c == '\0') break;
    authKey += c;
  }
  
  String apiKey;
  for (int i = 0; i < MAX_PARAM_LEN; i++) {
    char c = EEPROM.read(API_KEY_ADDR + i);
    if (c == '\0') break;
    apiKey += c;
  }
  
  String userName;
  for (int i = 0; i < MAX_PARAM_LEN; i++) {
    char c = EEPROM.read(USER_NAME_ADDR + i);
    if (c == '\0') break;
    userName += c;
  }
  
  EEPROM.end();
  
  // 打印读取结果
  Serial.println("读取EEPROM参数:");
  Serial.print("Authorization Key: ");
  Serial.println(authKey);
  Serial.print("Processed API Key: ");
  Serial.println(apiKey);
  Serial.print("Processed User Name: ");
  Serial.println(userName);
}

4. 初始化EEPROM空白区域

首次烧录时,可初始化EEPROM未使用区域为0,避免脏数据:

void initEEPROM() {
  EEPROM.begin(512);
  for (int i = 0; i < 512; i++) {
    if (EEPROM.read(i) != 0) {
      EEPROM.write(i, 0);
    }
  }
  EEPROM.commit();
  EEPROM.end();
}
// 在setup()开头调用(可通过标记位判断是否仅首次执行)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 22:31:16