• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Как записать строку в EEPROM на ESP8266?

vidok

Member
Ну или...
Код:
  EEPROM.begin(Количество зарезирвированных байт);
  EEPROM.put(adress,String);  //запись в буфер
  EEPROM.commit();            // физическая запись содержимого буфера
 

nikolz

Well-known member
У ESP8266 есть внешняя flash
и внутренняя RAM RTC, которая не сбрасывается в режиме sleep
обращение к RAM RTC либо на СИ (см док по SDK) либо в дурине функциями system_rtc_mem_write / system_rtc_mem_read
 

danmov26

New member
Ну или...
Код:
  EEPROM.begin(Количество зарезирвированных байт);
  EEPROM.put(adress,String);  //запись в буфер
  EEPROM.commit();            // физическая запись содержимого буфера
Спасибо Вам большое. Но как мне сохранить строку навсегда, то есть после перезапуска получить сохранённую строку?
 

vidok

Member
Спасибо Вам большое. Но как мне сохранить строку навсегда, то есть после перезапуска получить сохранённую строку?
Данный код записывает в внешний флеш (энергонезависимый) (под eeprom там выделенно 512 байт) естественно должа быть подключена библиотека EEPROM.h
и да, чтение обратно EEPROM.get (adress, data)

советовал бы вместо епром использовать файловую систему FS.h и хранить все данные в файле например в виде json
 

svs2007m

Active member
Не самое лучшее решение, но самое простое через структуру и "EEPROMAnything.h"
 

mitgo

New member
Коллеги выручайте, у меня похожая проблема.
Для хранения настроек в EEPROM сделал структуры:
Код:
struct intcfg {
  int val;
  int addr;
};

struct stringcfg{
  String val;
  int addr;
};

struct boolcfg{
  bool val;
  int addr;
};

struct bytecfg{
  byte val;
  int addr;
};
На на их основании создаю переменные и тут же инициализирую их дефолтными значениями.
Код:
boolcfg     STAen={true,1};           //Подключаемся к роутеру (1) или делаем точку (0)
stringcfg   ssid={defSsid,STAen.addr+sizeof(bool)};         //SSID роутера
stringcfg   pass={defPasswd,ssid.addr+sizeof(String)};       //Пароль роутера
intcfg      tries={15,pass.addr+sizeof(String)};             //Сколько ожидать подключения
stringcfg   webuser={"admin",tries.addr+sizeof(int)};
stringcfg   webpass={"admin",webuser.addr+sizeof(String)};
intcfg   websessionperiod={300,webpass.addr+sizeof(String)};
Проблем с нестроковыми переменными нет. А вот при работе со строками - не сохраняются, точнее не заменяются инициализированные дефолтные значения (хотя длинна строки соответствует ранее сохраненной).
Для сохранения использую следующие функции
Код:
bool saveAllConfig() {
  EEPROM.begin(eepromsize);
  delay(500);
  EEPROM.put(STAen.addr, STAen.val);
  EEPROM.put(ssid.addr, ssid.val);
  EEPROM.put(pass.addr, pass.val);
  EEPROM.put(tries.addr, tries.val);
  EEPROM.put(webuser.addr, webuser.val);
  EEPROM.put(webpass.addr, webpass.val);
  EEPROM.put(websessionperiod.addr, websessionperiod.val);
  EEPROM.put(mqttserver.addr, mqttserver.val);
  EEPROM.put(mqttport.addr, mqttport.val);
  EEPROM.put(mqttperiod.addr, mqttperiod.val);
  EEPROM.commit();
  EEPROM.end();
  delay(500);
}
void loadConfig() {
  EEPROM.begin(eepromsize);
  delay(500);
  EEPROM.get(STAen.addr, STAen.val);
  EEPROM.get(ssid.addr, ssidtmp);
  Serial.println("Int "+ssidtmp);
  EEPROM.get(pass.addr, pass.val);
  EEPROM.get(tries.addr, tries.val);
  EEPROM.get(webuser.addr, webuser.val);
  EEPROM.get(webpass.addr, webpass.val);
  EEPROM.get(websessionperiod.addr, websessionperiod.val);
  EEPROM.get(mqttserver.addr, mqttserver.val);
  EEPROM.get(mqttport.addr, mqttport.val);
  EEPROM.get(mqttperiod.addr, mqttperiod.val);
  EEPROM.end();
}

Код:
void setup() {
  EEPROM.begin(eepromsize);
  delay(500);
  #if (USE_SERIAL == 1)
    Serial.begin(115200);
    Serial.println();
  #endif
  byte cfgver=0;
  EEPROM.get(0,cfgver);
  EEPROM.end();
  if (cfgver != 1) {   // первый запуск
    EEPROM.begin(eepromsize);
    EEPROM.put(0, 1);
    delay(100);
    EEPROM.commit();
    EEPROM.end();
    saveAllConfig();
  }
  loadConfig();
}
Всю голову уже сломал...
 

vidok

Member
если addr+sizeof(int) , addr+sizeof(bool) размер занимаемый переменной понятен (он всегда один и тот же ( int зависит от разрядности процессора), то откуда известен размер addr+sizeof(String) ?
хотя я возможно чего то не понимаю.
 

edw

New member
Каким образом определяется дырка в EEPROM? Достаточно ли записать - считать и сравнить?
 

vidok

Member
Каким образом определяется дырка в EEPROM? Достаточно ли записать - считать и сравнить?
Обычно недостаточно, наверное хватило бы - считать байт , инвертировать его, записать обратно ,сравнить его с инвертированным результатом.
C++:
int adress=0;
byte testbyte=EEPROM.read(adress);
testbyte=~testbyte;
EEPROM.write(adress,testbyte);
Serial.print ( adress);
if (EEPROM.read(adress)==testbyte) Serial.prinln ("-true") else Serial.prinln ("-false")
примерно так, теоретически
 

mitgo

New member
если addr+sizeof(int) , addr+sizeof(bool) размер занимаемый переменной понятен (он всегда один и тот же ( int зависит от разрядности процессора), то откуда известен размер addr+sizeof(String) ?
хотя я возможно чего то не понимаю.
Дак странность то в том, что после считывания настроек длинна переменной (например SSID) становится равной длинне сохраненной в EEPROM переменной, а вот значение равняется инициализированному в коде.
Приведу пример.
При инициализации SSID.val="Some"
Сохраненное значение в EEPROm - "Something"
После чтения настроек из EEPROM SSID.val="Some%%%%%", где % - это пробелы (движок форума почему-то режет последовательные пробелы)
Самое что интересное, данные, хранящиеся в EEPROM за этой переменной и не являющиеся String считываются нормально, следовательно адреса определяются верно. (это я про sizeof(String)).
 

vidok

Member
я к чему писал то - конструкцией addr+sizeof(String) вы не сможете вычислить смещение для хранения следующей переменной
-String по сути это динамический массив, в отличии от bool который занимает 1 байт или int равный 4 байтам (у esp8266, esp32), пустой без символов String занимает незнамо чего.
sizeof(bool) - будет равен 1,
sizeof(int) - равен 4 ,
sizeof(String("это массив символов ,по сути обертка char[ ]") - равен N+1 (лень считать буковы.)
sizeof(String) - равен ??????
edw выше например написал что :
У меня sizeof для String всегда выдает 12
как то так мне кажется -,но я не гуру могу и ошибаться⚠
 

mitgo

New member
Serial.println("Размер String="+String(sizeof(String)));
Serial.println("Hello world="+String(sizeof(String("Hello world"))));
Serial.println("Размер строки 'это массив символов ,по сути обертка char[ ]'="+String(sizeof(String("это массив символов ,по сути обертка char[ ]"))));


Размер String=12
Hello world=12
Размер строки 'это массив символов ,по сути обертка char[ ]'=12

Адреса расчитываются правильно....
 

vidok

Member
Почти всегда пользовался char , там sizeof выдает именно длину массива символов в байтах.
String мало пользовался sizeof(String) возможно выдает размер служебных данных ( указатель на строку, переменная длины строки и пр.) видать они и занимают 12 байт, НО точно не объем строки в байтах. Поэтому мне кажется адреса рассчитываются не совсем верно.
Согласитесь не может строка всегда занимать 12 б.
 

vidok

Member
опыта маловато у меня попробуйте вместо addr+sizeof(String) вставить фиксированное максимально возможное значение -например: addr+20 .
может поможет. возможно я чего то не понял не выспавшись , да и опыта с знаниями в этой среде маловато. может помогут более маститые .
 

mitgo

New member
Ну вот Int занимает 4 байта без разницы это 1 или 2^16 (количество знакомест разное) а памяти жрет одинаково. Думаю у строки так же, берется максимальная длина строки и на основании этого выдается ее размер.
По поводу Char - не совсем удобно (по крайней мере мне так кажется) потому что при изменении длинны сохраняемого пароля или ssid придется переписывать все параметры конфигурации в EEPROM.
Но спасибо за идею - попробую.
Опять же - все адреса расчитываются на основе предыдущих sizeof, соответственно еще много данных типа int лежат за этими строками и загружаются нормально.
 

vidok

Member
int числовой параметр , а не текстовый , там нет знакомест ,там может храниться число от -2,147,483,648 до 2,147,483,647 которое занимает максимум 32 бит (4 байта).
String текстовый параметр ,каждый символ занимает 1 байт (8 бит), и ужимать строку в 30 символов до 12 байт не будет, sizeof(String) указывает на размер тех. данных строки вообще , в тех 12 байтах хранятся указатель на строку, переменная длины строки и пр. а не сам текст.
Опять же - все адреса рассчитываются на основе предыдущих sizeof, соответственно еще много данных типа int лежат за этими строками и загружаются нормально.
И почему бы им не хранится нормально они на своих местах своего размера, просто затирают предыдущую область( если там хранилась строка)- все ,что больше 12 байт.
 

nikolz

Well-known member
Ну вот Int занимает 4 байта без разницы это 1 или 2^16 (количество знакомест разное) а памяти жрет одинаково. Думаю у строки так же, берется максимальная длина строки и на основании этого выдается ее размер.
По поводу Char - не совсем удобно (по крайней мере мне так кажется) потому что при изменении длинны сохраняемого пароля или ssid придется переписывать все параметры конфигурации в EEPROM.
Но спасибо за идею - попробую.
Опять же - все адреса расчитываются на основе предыдущих sizeof, соответственно еще много данных типа int лежат за этими строками и загружаются нормально.
рекомендую читать учебники прежде чем думать.
Теперь поясняю:
В вычислительной технике уж так повелось (еще тогда, когда вас не было и некому было посоветовать как надо)
что система счисления двоичная, цифра занимает один бит, минимальная не делимая хранимая величина - байт(8 бит)
числа хранятся в формате либо целых чисел либо с плавающей точкой
основная длина целого числа равна разрядности арифметическо-логического устройства, для ESP - это 32 бита или 4 байта
а вот текст хранится в формате ASCIIZ https://ru.wikipedia.org/wiki/Нуль-терминированная_строка
Т е текст - это последовательность байт, в которой байт равный нулю определяет конец текста.
Минимальная длина текста - 1 байт.
---------------
Поэтому в программе для перезаписи чисел можно просто присваивать
А для перезаписи текста надо присваивать в цикле байт за байтом до байта равного нулю
 
Сверху Снизу