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

Отрицательное число int в EEPROM

Vypra

Member
суть предложения следующая.
можно проверять на совпадение вместо задержки и вместо записи
алгоритм такой
ставите цикл пока не совпадает - пишите
или условный если не совпадает то пишите
Идея хорошая. До записи нужно организовать чтение нормальное. Для начала мне нужно разобраться почему когда я вставил этот блок в большой код - WD сработал.
Код очень большой, загромождать не буду, но смысл такой: инициализируются датчики и remoteXY, потом нужно с памяти считать параметры для будильника:

Код:
   EEPROM_read_int(132, 135, interval);
   Serial.print("interval=");
   Serial.println(interval);

  EEPROM_read_int(136, 139, alarm_flag);
   Serial.print("alarm_flag=");
   Serial.println(alarm_flag);

  EEPROM_read_int(140, 143, next_alarm);
  Serial.print("next_alarm=");
  Serial.println(next_alarm);
interval читается, выдает в монитор порта 1 как должно.
alarm_flag уже хрень читает, выдает 1926 вместо 1.
На next_alarm срабатывает WD. Вечный ребут.
Интересно то, что код выполняется последовательно и обращаемся к одной и той же функции чтения.
Думал что в памяти значения не числовые до этого записаны и int не может прочитать. Переписал в эти ячейки 0. Но история повторилась. Может не успевает прочитать?
 

nikolz

Well-known member
Идея хорошая. До записи нужно организовать чтение нормальное. Для начала мне нужно разобраться почему когда я вставил этот блок в большой код - WD сработал.
Код очень большой, загромождать не буду, но смысл такой: инициализируются датчики и remoteXY, потом нужно с памяти считать параметры для будильника:

Код:
   EEPROM_read_int(132, 135, interval);
   Serial.print("interval=");
   Serial.println(interval);

  EEPROM_read_int(136, 139, alarm_flag);
   Serial.print("alarm_flag=");
   Serial.println(alarm_flag);

  EEPROM_read_int(140, 143, next_alarm);
  Serial.print("next_alarm=");
  Serial.println(next_alarm);
interval читается, выдает в монитор порта 1 как должно.
alarm_flag уже хрень читает, выдает 1926 вместо 1.
На next_alarm срабатывает WD. Вечный ребут.
Интересно то, что код выполняется последовательно и обращаемся к одной и той же функции чтения.
Думал что в памяти значения не числовые до этого записаны и int не может прочитать. Переписал в эти ячейки 0. Но история повторилась. Может не успевает прочитать?
Вы же пишите либо в RTC ибо во флеш
попробуйте посмотреть описание SDK
На самом деле если писать на Си то все гораздо проще и нет надобности в задержках.
При записи во флеш на старое место надо стирать блоки
Поэтому писать во флеш не рекомендуется. Возможно вам вполне хватит памяти RTC
 

Vypra

Member
Возможно вам вполне хватит памяти RTC
Дело в том, что мне в любом случае нужно во флеш писать. У меня кроме будильника есть еще записанные логины, пароли к емейлам, телефон и другие базовые настройки. Только RTC не обойтись.

При записи во флеш на старое место надо стирать блоки
Может поэтому не работает. До этого я NodeMCU использовал под другие скетчи. Может что-то и осталось в области до 512. Я по аналогии с EEPROM Arduino прогнал циклом запись 0 в каждую ячейку. Но я так понял что неправильно. С ESP8266 мой первый опыт. Как стереть все? И как организовать предварительное стирание до записи новых данных?
 

Vypra

Member
Для интереса взял и просто от фанаря поменял в вышеуказанном работающем коде адреса чтения вместо 4, 7 на 250, 253:

Код:
EEPROM_readAnything(250, 253, data_from_eeprom2); //читаем
Результат:
my_data:-1000
my_data2:20000
data_from_eeprom:-1000
data_from_eeprom2:-1
data_from_eeprom - Ok
data_from_eeprom2 - Ok

Странно что "data_from_eeprom2 - Ok" при том, что data_from_eeprom2:-1

И в то же время ребуты:
ets Jan 8 2013,rst cause:4, boot mode:(3,6)

wdt reset
load 0x4010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
v0fd86a07
~ld

Ересь какая-то.
 

Vypra

Member
Что-то не получается у меня с записью во флеш NodeMCU ничего.
Смотрю в интернете, в RTC 3231 установлена AT24CO2N. Нужно дома посмотреть.
У нее 2кбита памяти. Если некоторые настройки убрать, памяти должно хватить.
Как писать в память RTC ?
 

nikolz

Well-known member
Что-то не получается у меня с записью во флеш NodeMCU ничего.
Смотрю в интернете, в RTC 3231 установлена AT24CO2N. Нужно дома посмотреть.
У нее 2кбита памяти. Если некоторые настройки убрать, памяти должно хватить.
Как писать в память RTC ?
RTC Memory ESP8266 12-E read an write
 

CodeNameHawk

Moderator
Команда форума
Я по аналогии с EEPROM Arduino прогнал циклом запись 0 в каждую ячейку. Но я так понял что неправильно. С ESP8266 мой первый опыт. Как стереть все?
Для начала используйте готовые примеры. esp8266/Arduino
Эти примеры есть в ардуиноиде, вот если они не будут работать...
 

Vypra

Member
Для начала используйте готовые примеры. esp8266/Arduino
Эти примеры есть в ардуиноиде, вот если они не будут работать...
Затер все нулями. Отдельным скетчем перечитал - во всей области до 512 все прописалось.
А теперь вопрос залу :
Код:
#include <EEPROM.h>
#include <Arduino.h>

void setup()
{
  Serial.begin (9600);

  int my_data = -1000;
  int my_data2 = 20000;

  EEPROM_writeAnything(0, 3, my_data); // записываем
  Serial.print ("my_data:");
  Serial.println(my_data);

  EEPROM_writeAnything(4, 7, my_data2);
  Serial.print ("my_data2:");
  Serial.println(my_data2);

  int data_from_eeprom;
  int data_from_eeprom2;

  EEPROM_readAnything(0, 3, data_from_eeprom); //читаем
  Serial.print ("data_from_eeprom:");
  Serial.println(data_from_eeprom);

  EEPROM_readAnything(50, 53, data_from_eeprom2); //читаем
  Serial.print ("data_from_eeprom2:");
  Serial.println(data_from_eeprom2);

  if (my_data = data_from_eeprom)
  {
    Serial.println ("data_from_eeprom - Ok");
  }
  else
  {
    Serial.println ("data_from_eeprom - Bad");
  }


  if (my_data2 = data_from_eeprom2)
  {
    Serial.println ("data_from_eeprom2 - Ok");
  }
  else
  {
    Serial.println ("data_from_eeprom2 - Bad");
  }
}



void loop()
{}

template <class T> int EEPROM_writeAnything(int ee1, int ee2, const T & value)
{
  const byte* p = (const byte*)(const void*)&value;
  unsigned int i;
  EEPROM.begin(512);
  for (i = 0; i < ee2 + 1; i++)
  {
    //EEPROM.write(ee1++, *p++);
    EEPROM.put(ee1++, *p++);
  }
  EEPROM.commit();
  delay(20);
  return i;
}


template <class T> int EEPROM_readAnything(int ee1, int ee2, T & value)
{
  {
    EEPROM.begin(512);
    byte* p = (byte*)(void*)&value;
    unsigned int i;
    for (i = 0; i < ee2 + 1; i++)
    {
       *p++ = EEPROM.read(ee1++);
      //*p++ = EEPROM.get(ee1++);
    }
    return i;
  }
}
Почему все же:

my_data:-1000
my_data2:20000
data_from_eeprom:-1000
data_from_eeprom2:0
data_from_eeprom - Bad
data_from_eeprom2 - Bad

Если
my_data равно data_from_eeprom,
а my_data2 не равно data_from_eeprom2 ??
И ребут?
 

Vypra

Member
это что?
И зачем вы испортили процедуру? Зачем вам три параметра?
Сергей, осознанно портил, пытаясь получить универсальную функцию, к которой можно обратиться и записать в строго определенные области памяти первоначальные настройки для запуска моего устройства.
 

Сергей_Ф

Moderator
Команда форума
@Vypra вы не ответили на вопрос, зачем вы проверяете успешность присвоения my_data = data_from_eeprom?
Я не заметил осознанности в ваших действиях. У вас была универсальная функция, которая пишет в строго определенную область памяти ЛЮБУЮ переменную и число записанных байт. Что вам надо ещё? Более того, она корректно вычисляла сколько памяти потребуется.
У вас мало того, что функция стала только для 4-байтового значения, да ещё EEPROM.put() работает совсем не так, как EEPROM.write(). put оперирует со структурой, а не с байтом. Вы зачем его в цикл вставили?
Вы явно действуете "методом тыка". Что вам мешает ознакомиться с исходниками?
 
Последнее редактирование:

Сергей_Ф

Moderator
Команда форума
@Vypra вам надо записать кучу своих настроек? Поместите их в свою структуру и запишите.
Код:
#include <EEPROM.h>
#include <Arduino.h>

struct MyStruct{
    int data;
    char string[10];
    float test;
  };

void PrintStruct(const char *t, const MyStruct s){
  Serial.print(t); Serial.println(": ");
  Serial.println(s.data);
  Serial.print('"');Serial.print( s.string);Serial.println( '"');
  Serial.println(int(s.test*1000));
 
};
void setup()
{
  Serial.begin (115200);
  const int eeprom_addr = 13;
  MyStruct data = { -343523, "test", 355.0/113.0 };
  EEPROM.begin(512);
  EEPROM.put(eeprom_addr, data);
  EEPROM.commit();
  PrintStruct("my_data", data);

  MyStruct eeprom;

  EEPROM.get(eeprom_addr, eeprom); //читаем
  PrintStruct("eeprom", eeprom);

}
void loop()
{}
 

Сергей_Ф

Moderator
Команда форума
@CodeNameHawk там немного данные устарели. Сейчас в библиотеке EEPROM уже входят аналоги EEPROM_writeAnything: put() и get(). Так что нет нужды "изобретать велосипед".
 

sasha294

Member
EEPROM
Эта библиотека немного отличается от стандартной Arduino EEPROM. Необходимо вызвать функцию EEPROM.begin(size) каждый раз перед началом чтения или записи, размер (указывается в байтах) соответствует размеру данных, которые вы намереваетесь использовать в EEPROM. Размер данных должен быть в диапазоне от 4 до 4096 байт.

Функция EEPROM.write не производит запись данных во флеш память немедленно, вы должны использовать функцию EEPROM.commit() каждый раз, когда вы хотите сохранить данные в память. Функция EEPROM.end() тоже производит запись данных, а также освобождает оперативную память от данных, запись которых произведена. Библиотека EEPROM использует один сектор во флеш памяти, начиная с адреса 0x7b000 для хранения данных. В поставку включено три примера работы с EEPROM.



// //Functionality to 'get' and 'put' objects to and from EEPROM.
// template< typename T > T &get( int idx, T &t ){
// EEPtr e = idx;
// uint8_t *ptr = (uint8_t*) &t;
// for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e;
// return t;
// }

// template< typename T > const T &put( int idx, const T &t ){
// EEPtr e = idx;
// const uint8_t *ptr = (const uint8_t*) &t;
// for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ );
// return t;
// }
 

Vypra

Member
Я не заметил осознанности в ваших действиях.
Давайте я попробую объяснить на примере что я хочу и что я не понимаю.
Под EEPROM мы выделяем необходимое количество байт (ну по максимуму 512 байт дали).
По адресам допустим 0 - 1 мы пишем число int.
Далее например 2-10 пишем String (емейл например хочу записать)
Далее 11-12 опять int.
С EEPROM.put(address, value) понятно - начиная с начального адреса, который мы указали, пишет значение пока не закончатся данные.
Я не понял как EEPROM.get(address, value) поймет что мне нужно прочесть String с 2-10, а не 2 по 11 или дальше?
Суть 3-х переданных значений в функцию была такова: адрес с, адрес по, и само значение. Допускаю что возможно неправильно думаю.
Вот запустится мой скетч, подгрузятся первоначальние настройки. Потом в Remote XY в поле ввода я захочу ввести новый емейл и сохраниться. Значит я должен буду переписать данные по адресам 2-10, не тронув 0-1 и от 11 и дальше.

Вы явно действуете "методом тыка". Что вам мешает ознакомиться с исходниками?
Угу. Поверьте, читаю и пытаюсь сам разобраться. Когда не нахожу ответ, именно так и действую, догадываясь потом по результату как работает механизм. Уж простите.
 

Сергей_Ф

Moderator
Команда форума
не понял как EEPROM.get(address, value) поймет что мне нужно прочесть String с 2-10, а не 2 по 11 или дальше?
Он поймет это по длиннее объявленной переменной. Таким образом String лучше не писать в EEPROM. Тем более это не тип данных, по большому счету.
Пишите массив char известной длинны. Так будет предсказуемый результат. Сколько надо максимум для e-mail? 20, 30, 40 - символов? Так и определите в программе. И тогда адрес по не нужен!
 

Vypra

Member
@Vypra вам надо записать кучу своих настроек? Поместите их в свою структуру и запишите.
Код:
#include <EEPROM.h>
#include <Arduino.h>

struct MyStruct{
    int data;
    char string[10];
    float test;
  };

void PrintStruct(const char *t, const MyStruct s){
  Serial.print(t); Serial.println(": ");
  Serial.println(s.data);
  Serial.print('"');Serial.print( s.string);Serial.println( '"');
  Serial.println(int(s.test*1000));
 
};
void setup()
{
  Serial.begin (115200);
  const int eeprom_addr = 13;
  MyStruct data = { -343523, "test", 355.0/113.0 };
  EEPROM.begin(512);
  EEPROM.put(eeprom_addr, data);
  EEPROM.commit();
  PrintStruct("my_data", data);

  MyStruct eeprom;

  EEPROM.get(eeprom_addr, eeprom); //читаем
  PrintStruct("eeprom", eeprom);

}
void loop()
{}

Хорошо. Согласен. char практичней в данном случае. Хотя я уже нашел способ писать String с адреса по адрес.
Возвращаемся к Вашему примеру. Мне нравится. Структурами небыло необходимости пока пользоваться. Нужно начинать изучать.
Я в примере вижу что создаем структуру из разных типов данных и дальше пишем значения для всей структуры.
В структурах есть возможность изменять только одно значение? В принципе как я понял нужно отсчитать адрес где начинается значение (для char string это будет 15 в примере), и по аналогии с PrintStruct записать EEPROM.put(eeprom_addr, s.data) ?
 
Сверху Снизу