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

