Andrey L
Member
С одной стороны хочу поделиться своим "опытом", а с другой стороны, может быть у меня есть ошибка, которую я не заметил, хоть скетч и работает.
Так что если у меня появится ошибка, то прошу мне на неё указать. В этом случае я исправлю это первое сообщение, так что в последствии коментарии могут указывать на уже исправленные ошибки.
Зачем надо использовать RTC?
ESP8266 выходит из режима "глубокого сна" путём "перезагрузки", а следовательно код выполняется заного, да и старые значения переменых теряются, даже внутренние счётчики millis() и micros() сбрасываются.
Для хранения некоторых данных можно воспользоваться RTC памятью, но надо помнить, что и эта память сбрасывается, когда ESP будет полностью отключена от сети.
Так же размер RTC-памяти окраничена 512 байтами и советуется объявлять там типы по 4 байт. (Это я не полностью понимаю, поскольку с переменной типа bite это тоже работает.)
Что надо дополнительно учитывать при работе с RTC?
При подачи питания на модуль, нельзя рассчитывать, что в RTC будет хранится одни "нули", старых данных там тоже не будет. А следовательно надо научиться определять хранятся ли там наши данные или какие-то случайные "шумы".
Для этого используется дополнительная функция для подчёта проверочной суммы. Но и это магическое число для проверки тоже будет храниться в RTC памяти. В примере эта функция называется calculateCRC32().
Структура для RTC
Как я понимаю, отдельные переменные можно хранить в RTC-памяти, но для этого надо строго следить за тем какие данные по какому адресу хранятся, а так же чтобы они не пересекались.
Чтобы об этом не заботиться, мы создадим свою структуру для этого. Главное, чтобы эта структура не занимала больше 512 байт в памяти.
Код
Вкатце что делает программа
Альтернатива RTC
Внутренняя файловая система, работать можно через библиотеку "FS.h" (SPIFFS). Эта система как код скетча энергонезависимая, где можно хранить данные и без питания. Но для неё надо отдельно выделять память от 4МБ модуля.
Так что если у меня появится ошибка, то прошу мне на неё указать. В этом случае я исправлю это первое сообщение, так что в последствии коментарии могут указывать на уже исправленные ошибки.
Зачем надо использовать RTC?
ESP8266 выходит из режима "глубокого сна" путём "перезагрузки", а следовательно код выполняется заного, да и старые значения переменых теряются, даже внутренние счётчики millis() и micros() сбрасываются.
Для хранения некоторых данных можно воспользоваться RTC памятью, но надо помнить, что и эта память сбрасывается, когда ESP будет полностью отключена от сети.
Так же размер RTC-памяти окраничена 512 байтами и советуется объявлять там типы по 4 байт. (Это я не полностью понимаю, поскольку с переменной типа bite это тоже работает.)
Что надо дополнительно учитывать при работе с RTC?
При подачи питания на модуль, нельзя рассчитывать, что в RTC будет хранится одни "нули", старых данных там тоже не будет. А следовательно надо научиться определять хранятся ли там наши данные или какие-то случайные "шумы".
Для этого используется дополнительная функция для подчёта проверочной суммы. Но и это магическое число для проверки тоже будет храниться в RTC памяти. В примере эта функция называется calculateCRC32().
Структура для RTC
Как я понимаю, отдельные переменные можно хранить в RTC-памяти, но для этого надо строго следить за тем какие данные по какому адресу хранятся, а так же чтобы они не пересекались.
Чтобы об этом не заботиться, мы создадим свою структуру для этого. Главное, чтобы эта структура не занимала больше 512 байт в памяти.
Код
Код:
/**
* Структура, которая будет хранится в RTC-памяти.
* byte counter - счётчик запусков программы
* unsigned long RunningTime - счётчик примерного времени в миллисекундах
*
* uint32_t crc32 - хранилище проверочной суммы, ОБЯЗАТЕЛЬНО должно стоять вконце структуры (ограничение моей функции по проверке этой суммы).
*
* Так же следим за общим размером структуры, её размер не должен превышать 512 байт. (Физический размер RTC-памяти.)
*/
struct {
byte counter; // 1 byte
unsigned long RunningTime; // 4 byte
uint32_t crc32; // 4 byte
} rtcData;
// Время в микросекундах, на которое мы отправляем наш модуль "спать".
// 1e6=10^6 - мультипликатор, который превращает секунды в микросекунды.
#define sleepTime 10*1e6
// Мультипликатор, который переводит микросекунды в миллисекунды
#define mikroToMillis 1/1e3
void setup() {
// Без "большого серийного брата" во время тестов никак нельзя.
Serial.begin(115200);
Serial.println(""); // Первая строчка вывода - абра-кадабра
Serial.println("Hallo!!!"); // Привет-привет
// Считываем данные из RTC-памяти.
if (ESP.rtcUserMemoryRead(0, (uint32_t*) &rtcData, sizeof(rtcData))) {
Serial.println("Прочёл!!!");
Serial.println(rtcData.RunningTime);
Serial.println(rtcData.counter);
} else {
Serial.println("Паника! Прочесть не получилось.");
}
// Проверяем проверочную сумму
if (rtcData.crc32 != calculateCRC32((uint8_t*) &rtcData)) {
// Если проверочные суммы не сошлись, то на модуль только что подали питание,
// и мы сохраняем "нулевые" значения.
rtcData.RunningTime = 0;
rtcData.counter = 0;
// Обязательно перед записью пересчитываем проверочную сумму
rtcData.crc32 = calculateCRC32((uint8_t*) &rtcData);
// Сохраняем нашу структуру в RTC-память
ESP.rtcUserMemoryWrite(0, (uint32_t*) &rtcData, sizeof(rtcData));
Serial.println("Проверочные суммы не сошлись, все данные сбросили.");
} else {
Serial.println("Проверочные суммы сошлись.");
}
}
void loop() {
// Увеличиваем время счётчика.
// sleepTime (время "сна" в микросекундах)
// * mikroToMillis (переводит микросекунды в миллисекунды)
// + millis() не забываем добавить время, которое прошло с момета запуска программы
// ещё можно добавить некое число на выполнение следующих команд до того, как модуль "заснёт"
rtcData.RunningTime += sleepTime * mikroToMillis + millis();
// Увеличиваем счётчик
rtcData.counter++;
// Не забываем перед записью обновить проверочную сумму
rtcData.crc32 = calculateCRC32((uint8_t*) &rtcData);
// Сохраняем нашу структуру в RTC-памяти
ESP.rtcUserMemoryWrite(0, (uint32_t*) &rtcData, sizeof(rtcData));
// Идём "спать"
ESP.deepSleep(sleepTime);
}
/**
* Магическая функция по подсчёту проверочной суммы нашей структуры.
* Основа её взята из примера ESP8266/RTCUserMemory.
*/
uint32_t calculateCRC32(const uint8_t *data) {
// Обрабатываем все данные, кроме последних четырёх байтов,
// где и будет храниться проверочная сумма.
size_t length = sizeof(rtcData)-4;
uint32_t crc = 0xffffffff;
while (length--) {
uint8_t c = *data++;
for (uint32_t i = 0x80; i > 0; i >>= 1) {
bool bit = crc & 0x80000000;
if (c & i) {
bit = !bit;
}
crc <<= 1;
if (bit) {
crc ^= 0x04c11db7;
}
}
}
return crc;
}
Вкатце что делает программа
- setup()
Читаем, что хранится в RTC памяти.
- Если данные не проходят валидацию, то мы эти данные "обнуляем" - loop()
Увеличиваем счётчики,
пересчитываем новую проверочную сумму,
сохраняем всё.
Идём спать.
Альтернатива RTC
Внутренняя файловая система, работать можно через библиотеку "FS.h" (SPIFFS). Эта система как код скетча энергонезависимая, где можно хранить данные и без питания. Но для неё надо отдельно выделять память от 4МБ модуля.
Последнее редактирование модератором: