ESP32 Flash-память – сохранение данных (запись и чтение)

В этой статье мы покажем вам, как сохранять и считывать значения из flash-памяти ESP32 с помощью Arduino IDE. Данные, сохраненные в flash-памяти, остаются там даже при сбросе ESP32 или при отключении питания. В качестве примера мы покажем, как сохранить последнее состояние GPIO.

Сохранение постоянных данных в flash-памяти ESP32

Это руководство устарело. Следуйте новому руководству: [НОВОЕ] ESP32 Сохранение данных с помощью библиотеки Preferences

Прежде чем приступить к этому руководству, у вас должно быть установлено дополнение ESP32 в вашей Arduino IDE. Следуйте одному из следующих руководств для установки ESP32 в Arduino IDE, если вы еще этого не сделали.

Мы также рекомендуем ознакомиться со следующими ресурсами:

Смотреть видеоурок

Это руководство доступно в видеоформате (смотрите ниже) и в текстовом формате (продолжайте чтение).

Необходимые компоненты

Для выполнения этого руководства вам понадобятся следующие компоненты:

Вы можете использовать приведенные выше ссылки или перейти непосредственно на MakerAdvisor.com/tools, чтобы найти все компоненты для ваших проектов по лучшей цене!

MakerAdvisor -- инструменты и компоненты

Flash-память

Данные, сохраненные в flash-памяти, остаются там даже при сбросе ESP32 или при отключении питания. Flash-память очень похожа на EEPROM. Обе являются энергонезависимыми типами памяти.

Сохранение данных в flash-памяти особенно полезно для:

  • запоминания последнего состояния переменной;

  • сохранения настроек;

  • сохранения количества включений устройства;

  • или любого другого типа данных, которые необходимо хранить постоянно.

Одним из ограничений flash-памяти является количество циклов записи. Данные можно считывать из flash-памяти сколько угодно раз, но большинство устройств рассчитаны примерно на 100 000 – 1 000 000 операций записи.

Библиотека EEPROM

Для чтения и записи из flash-памяти ESP32 с помощью Arduino IDE мы будем использовать библиотеку EEPROM. Использование этой библиотеки с ESP32 очень похоже на использование с Arduino. Поэтому, если вы ранее использовали EEPROM на Arduino, здесь все практически так же.

Мы также рекомендуем ознакомиться с нашей статьей об Arduino EEPROM.

С ESP32 и библиотекой EEPROM вы можете использовать до 512 байт flash-памяти. Это означает, что у вас есть 512 различных адресов, и в каждый адрес можно сохранить значение от 0 до 255.

Количество доступных байт flash-памяти ESP32

Запись (Write)

Для записи данных в flash-память используется функция EEPROM.write(), которая принимает в качестве аргументов адрес (позицию), куда вы хотите сохранить данные, и значение (переменная типа byte), которое вы хотите сохранить:

EEPROM.write(address, value);

Например, чтобы записать 9 по адресу 0, нужно написать:

EEPROM.write(0, 9);

Затем необходимо вызвать:

EEPROM.commit();

Чтобы изменения были сохранены.

Чтение (Read)

Для чтения байта из flash-памяти используется функция EEPROM.read(). Эта функция принимает в качестве аргумента адрес байта, который вы хотите прочитать.

EEPROM.read(address);

Например, чтобы прочитать байт, ранее сохраненный по адресу 0, используйте:

EEPROM.read(0);

Это вернет 9, то есть значение, которое мы сохранили по адресу 0.

Запоминание последнего состояния GPIO

Чтобы показать вам, как сохранять данные в flash-памяти ESP32, мы сохраним последнее состояние выхода, в данном случае светодиода. Например, представьте следующий сценарий:

  1. Вы управляете лампой с помощью ESP32

  2. Вы включаете лампу

  3. ESP32 внезапно теряет питание

  4. Когда питание восстанавливается, лампа остается выключенной – потому что она не сохраняет свое последнее состояние

Выход сбрасывает состояние после перезагрузки ESP32

Вы не хотите, чтобы так происходило. Вы хотите, чтобы ESP32 запоминал, что происходило до потери питания, и возвращался к последнему состоянию.

Для решения этой проблемы вы можете сохранить состояние лампы в flash-памяти. Затем вам просто нужно добавить условие в начале вашего скетча для проверки последнего состояния лампы и включить или выключить лампу соответственно.

На следующем рисунке показано, что мы собираемся сделать:

Сохранение последнего состояния выхода после сброса ESP32

Схема подключения

Подключите кнопку и светодиод к ESP32, как показано на следующей принципиальной схеме.

Схема подключения кнопки и светодиода к ESP32 для работы с flash-памятью

Код

Скопируйте следующий код в Arduino IDE и загрузите его на ESP32. Убедитесь, что выбраны правильная плата и COM-порт.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com
*********/

// include library to read and write from flash memory
#include <EEPROM.h>

// define the number of bytes you want to access
#define EEPROM_SIZE 1

// constants won't change. They're used here to set pin numbers:
const int buttonPin = 4;    // the number of the pushbutton pin
const int ledPin = 16;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

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

  // initialize EEPROM with predefined size
  EEPROM.begin(EEPROM_SIZE);

  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);

  // read the last LED state from flash memory
  ledState = EEPROM.read(0);
  // set the LED to the last stored state
  digitalWrite(ledPin, ledState);
}

void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }
  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;

  // if the ledState variable is different from the current LED state
  if (digitalRead(ledPin)!= ledState) {
    Serial.println("State changed");
    // change the LED state
    digitalWrite(ledPin, ledState);
    // save the LED state in flash memory
    EEPROM.write(0, ledState);
    EEPROM.commit();
    Serial.println("State saved in flash memory");
  }
}

Просмотреть исходный код

Как работает код

Давайте быстро рассмотрим код.

Это код с подавлением дребезга (debounce), который меняет состояние светодиода каждый раз при нажатии кнопки. Но в этом коде есть кое-что особенное – он запоминает последнее состояние светодиода даже после сброса или отключения питания ESP32. Давайте посмотрим, что нужно сделать, чтобы ESP32 запоминал последнее состояние GPIO.

Сначала необходимо подключить библиотеку EEPROM.

#include <EEPROM.h>

Затем вы определяете размер EEPROM. Это количество байтов, к которым вы хотите получить доступ в flash-памяти. В данном случае мы сохраняем только состояние светодиода, поэтому размер EEPROM установлен в 1.

#define EEPROM_SIZE 1

Мы также определяем другие переменные, необходимые для работы этого скетча.

// constants won't change. They're used here to set pin numbers:
const int buttonPin = 4; // the number of the pushbutton pin
const int ledPin = 16; // the number of the LED pin

// Variables will change:
int ledState = HIGH;
// the current state of the output pin
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int. unsigned long lastDebounceTime = 0; // the last time the output pin was toggled unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers

setup()

В функции setup() вы инициализируете EEPROM с заданным размером.

EEPROM.begin(EEPROM_SIZE);

Чтобы убедиться, что ваш код инициализируется с последним состоянием светодиода, в setup() вы должны прочитать последнее состояние светодиода из flash-памяти. Оно хранится по адресу ноль.

ledState = EEPROM.read(0);

Затем вам просто нужно включить или выключить светодиод в соответствии со значением, прочитанным из flash-памяти.

digitalWrite (ledPin, ledState);

loop()

Следующая часть loop() проверяет, была ли нажата кнопка, и меняет переменную ledState каждый раз при нажатии кнопки. Чтобы исключить ложные срабатывания, мы используем таймер. Этот фрагмент кода основан на примере скетча подавления дребезга кнопки из Arduino IDE.

// read the state of the switch into a local variable:
int reading = digitalRead(buttonPin);

// check to see if you just pressed the button
// (i.e. the input went from LOW to HIGH), and you've waited long enough
// since the last press to ignore any noise:

// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
  // reset the debouncing timer
  lastDebounceTime = millis();
}

if ((millis() - lastDebounceTime) > debounceDelay) {
  // whatever the reading is at, it's been there for longer than the debounce
  // delay, so take it as the actual current state:

  // if the button state has changed:
  if (reading != buttonState) {
    buttonState = reading;

    // only toggle the LED if the new button state is HIGH
    if (buttonState == HIGH) {
      ledState = !ledState;
    }
  }
}
// save the reading. Next time through the loop, it'll be the lastButtonState:
lastButtonState = reading;

Вам просто нужно сохранять состояние светодиода в flash-памяти каждый раз, когда состояние светодиода изменяется.

Мы проверяем, отличается ли состояние GPIO от переменной ledState.

if (digitalRead(ledPin)!= ledState) {

Если отличается, мы изменяем состояние светодиода с помощью функции digitalWrite().

digitalWrite(ledPin, ledState);

Затем мы сохраняем текущее состояние в flash-памяти. Для этого мы используем EEPROM.write() и передаем в качестве аргументов позицию адреса, в данном случае 0, и значение для сохранения, в данном случае переменную ledState.

EEPROM.write(0, ledState);

Наконец, мы вызываем EEPROM.commit(), чтобы изменения вступили в силу.

EEPROM.commit();

Демонстрация

После загрузки кода на ESP32 нажмите кнопку, чтобы включить и выключить светодиод. ESP32 должен сохранять последнее состояние светодиода после сброса или отключения питания.

Демонстрация сохранения последнего состояния в flash-памяти ESP32

Заключение

Подводя итог, в этом уроке вы узнали, как сохранять данные в flash-памяти ESP32 с помощью библиотеки EEPROM. Данные, сохраненные в flash-памяти, остаются там даже после сброса ESP32 или отключения питания.

У нас есть другие статьи об ESP32, которые могут вам понравиться:

Это отрывок из нашего курса: Learn ESP32 with Arduino IDE. Если вам нравится ESP32 и вы хотите узнать больше, мы рекомендуем записаться на курс Learn ESP32 with Arduino IDE.


Источник: ESP32 Flash Memory – Store Permanent Data (Write and Read)