Главная chevron_right Уроки chevron_right Встроенные библиотеки chevron_right Библиотека EEPROM

Библиотека EEPROM

Подробное руководство по библиотеке EEPROM для Arduino: чтение, запись и обновление данных в энергонезависимой памяти микроконтроллера.

Микроконтроллер на платах Arduino с AVR-чипами оснащён EEPROM — энергонезависимой памятью, которая сохраняет данные даже после отключения питания. Представьте её как крошечный жёсткий диск внутри чипа. Библиотека EEPROM даёт удобный доступ к этой памяти: можно читать и записывать отдельные байты или целые структуры данных.

Разные платы Arduino располагают разным объёмом EEPROM:

  • ATmega328P — 1024 байта
  • ATmega168 и ATmega8 — по 512 байт
  • ATmega1280 и ATmega2560 — 4 КБ (4096 байт)
  • Arduino и Genuino 101 — эмулированное пространство EEPROM объёмом 1024 байта

Чтобы подключить библиотеку к своему скетчу:

#include <EEPROM.h>

Примеры использования

Список готовых примеров для библиотеки EEPROM:

Функции

read()

Описание

Читает один байт из EEPROM по указанному адресу. Ячейки, в которые ни разу ничего не записывалось, возвращают значение 255.

Синтаксис

EEPROM.read(address)

Параметры

address — адрес ячейки для чтения, начиная с 0 (тип int)

Возвращаемое значение

Значение, хранящееся в указанной ячейке (тип byte)

Пример

#include <EEPROM.h>

int a = 0;
int value;

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

void loop()
{
  value = EEPROM.read(a);

  Serial.print(a);
  Serial.print("\t");
  Serial.print(value);
  Serial.println();

  a = a + 1;

  if (a == 512)
    a = 0;

  delay(500);
}

Практическое замечание

Если вы читаете ячейку впервые (например, на новом или только что прошитом чипе) и получаете 255 — это нормально. Такое значение означает, что ячейка никогда не записывалась. Учитывайте это при инициализации переменных из EEPROM.

---

write()

Описание

Записывает один байт в EEPROM по указанному адресу. Значение записывается безусловно, независимо от того, что там хранилось раньше.

Синтаксис

EEPROM.write(address, value)

Параметры

address — адрес ячейки для записи, начиная с 0 (тип int)

value — значение для записи, от 0 до 255 (тип byte)

Возвращаемое значение

Нет

Важно: Одна операция записи в EEPROM занимает около 3,3 мс. Ресурс памяти ограничен — производитель гарантирует около 100 000 циклов записи/стирания на каждую ячейку. Избегайте частой записи в одни и те же адреса — это продлит жизнь памяти. Если данные меняются редко, используйте update() вместо write().

Пример

#include <EEPROM.h>

void setup()
{
  for (int i = 0; i < 255; i++)
    EEPROM.write(i, i);
}

void loop()
{
}

---

update()

Описание

Записывает байт в EEPROM только в том случае, если новое значение отличается от уже сохранённого. Это умная альтернатива write() — лишних циклов стирания не происходит.

Синтаксис

EEPROM.update(address, value)

Параметры

address — адрес ячейки для записи, начиная с 0 (тип int)

value — значение для записи, от 0 до 255 (тип byte)

Возвращаемое значение

Нет

Совет: Если ваша программа периодически сохраняет одни и те же данные (например, состояние настроек), используйте update() вместо write(). Это значительно увеличит ресурс ячеек EEPROM, поскольку запись происходит только при реальном изменении значения.

Пример

#include <EEPROM.h>

void setup()
{
  for (int i = 0; i < 255; i++) {
    // выполняет то же, что EEPROM.write(i, i)
    EEPROM.update(i, i);
  }
  for (int i = 0; i < 255; i++) {
    // записать значение "12" в ячейку 3 только при первом запуске
    // в оставшиеся 254 раза ячейка не будет перезаписана
    EEPROM.update(3, 12);
  }
}

void loop()
{
}

---

get()

Описание

Читает из EEPROM данные любого типа или объект. Подходит для примитивных типов (float, int, long) и пользовательских структур (struct).

Синтаксис

EEPROM.get(address, data)

Параметры

address — адрес начала чтения, начиная с 0 (тип int)

data — переменная, в которую будут прочитаны данные; может быть примитивным типом (например, float) или пользовательской структурой

Возвращаемое значение

Ссылка на переданную переменную data

Пример

#include <EEPROM.h>

struct MyObject{
  float field1;
  byte field2;
  char name[10];
};

void setup(){

  float f = 0.00f;   //Переменная для хранения данных, считанных из EEPROM.
  int eeAddress = 0; //Адрес в EEPROM, с которого начинается чтение

  Serial.begin( 9600 );
  while (!Serial) {
    ; // ожидание подключения serial-порта. Нужно только для Leonardo
  }
  Serial.print( "Read float from EEPROM: " );

  //Получить данные типа float из EEPROM по адресу 'eeAddress'
  EEPROM.get( eeAddress, f );
  Serial.println( f, 3 );  //Может вывести 'ovf, nan', если данные в EEPROM не являются корректным float.

  // get() также работает с пользовательскими структурами.
  eeAddress = sizeof(float); //Сдвинуть адрес на следующий байт после float 'f'.
  MyObject customVar; //Переменная для хранения пользовательского объекта, считанного из EEPROM.
  EEPROM.get( eeAddress, customVar );

  Serial.println( "Read custom object from EEPROM: " );
  Serial.println( customVar.field1 );
  Serial.println( customVar.field2 );
  Serial.println( customVar.name );
}

void loop(){ /* Пустой loop */ }

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

get() читает столько байт, сколько занимает тип переменной data. Например, для float это 4 байта, для int — 2 байта. Функция сама вычисляет размер через sizeof и последовательно читает нужное количество ячеек, начиная с address. Убедитесь, что при записи и чтении используется одинаковый тип — иначе данные будут интерпретированы неверно.

---

put()

Описание

Записывает в EEPROM данные любого типа или объект. Работает аналогично get(), но в обратном направлении.

Синтаксис

EEPROM.put(address, data)

Параметры

address — адрес начала записи, начиная с 0 (тип int)

data — данные для записи; может быть примитивным типом (например, float) или пользовательской структурой

Возвращаемое значение

Ссылка на переданные данные data

Примечание: Внутри put() использует update(), поэтому запись происходит только при изменении значения. Это автоматически защищает ресурс EEPROM при повторной записи одинаковых данных.

Пример

#include <EEPROM.h>

struct MyObject {
  float field1;
  byte field2;
  char name[10];
};

void setup() {

  Serial.begin(9600);
  while (!Serial) {
    ; // ожидание подключения serial-порта. Нужно только для нативного USB-порта
  }

  float f = 123.456f;  //Переменная для записи в EEPROM.
  int eeAddress = 0;   //Адрес, по которому будут сохранены данные.


  //Один простой вызов: первый аргумент — адрес, второй — объект.
  EEPROM.put(eeAddress, f);

  Serial.println("Written float data type!");

  /*put также предназначен для работы с пользовательскими структурами.*/

  //Данные для сохранения.
  MyObject customVar = {
    3.14f,
    65,
    "Working!"
  };

  eeAddress += sizeof(float); //Сдвинуть адрес на следующий байт после float 'f'.

  EEPROM.put(eeAddress, customVar);
  Serial.print("Written custom data type! \n\nView the example sketch eeprom_get to see how you can retrieve the values!");
}

void loop() {   /* Пустой loop */ }

Типичная ошибка

Не забывайте следить за адресами при записи нескольких переменных разных типов. Если записать float по адресу 0, следующую переменную нужно записывать начиная с адреса 4 (так как float занимает 4 байта). Смешение адресов приведёт к чтению «мусора».

---

EEPROM[]

Описание

Оператор [] позволяет обращаться к ячейкам EEPROM так же, как к элементам массива через идентификатор EEPROM. Это удобный способ прямого чтения и записи отдельных байт.

Синтаксис

EEPROM[address]

Параметры

address — адрес ячейки для чтения или записи, начиная с 0 (тип int)

Возвращаемое значение

Ссылка на ячейку EEPROM

Пример

#include <EEPROM.h>

void setup(){

  unsigned char val;

  //Прочитать первую ячейку EEPROM.
  val = EEPROM[ 0 ];

  //Записать первую ячейку EEPROM.
  EEPROM[ 0 ] = val;

  //Сравнить содержимое
  if( val == EEPROM[ 0 ] ){
    //Выполнить какое-либо действие...
  }
}

void loop(){ /* Пустой loop */ }

Практическое замечание

Оператор [] — это синтаксический сахар для прямого доступа к байтам. Он ведёт себя как read() при чтении и как write() при присваивании. Если хотите сэкономить ресурс памяти при записи, лучше явно использовать update().

---

length()

Описание

Возвращает количество ячеек в EEPROM текущего микроконтроллера в виде значения типа unsigned int. Удобна для написания кода, который автоматически адаптируется к объёму памяти конкретной платы.

Синтаксис

EEPROM.length()

Возвращаемое значение

Количество ячеек EEPROM в виде unsigned int

Где пригодится

Используйте length() в циклах, чтобы не выходить за границы памяти:

for (int i = 0; i < EEPROM.length(); i++) {
  EEPROM.write(i, 0); // Очистить всю EEPROM
}

Это особенно полезно при написании универсального кода, который должен работать на разных платах Arduino с разным объёмом EEPROM.