Arduino eeprom работа с памятью

Работа с EEPROM

Как упоминалось ранее, ресурс памяти EEPROM ограничен. Для продления срока службы энергонезависимой памяти, вместо функции write() запись, лучше применять функцию update обновление. При этом перезапись ведется только для тех ячеек, где значение отличается от вновь записываемого.

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

Такая память на Ардуино стандартно хранит самое важное для работы контроллера и устройства. К примеру, если на такой базе создается регулятор температуры и исходные данные окажутся ошибочными, устройство будет работать «неадекватно» существующим условиям – сильно занижать или завышать температуру

Существует несколько ситуаций, когда память EEPROM содержит неправильные данные:

  1. При первоначальной активации – еще не было ни одной записи.
  2. В момент неконтролируемого отключения питания – часть или все данные не запишутся или запишутся некорректно.
  3. После завершения возможных циклов перезаписи данных.

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

Для контроля целостности информации используют контрольный код системы. Он создается по образцу записи первоначальных данных и, при проверке, он вновь просчитывает данные. Если результат отличается – это ошибка. Самым распространенным вариантом такой проверки является контрольная сумма – выполняется обычная математическая операция по сложению всех значений ячеек.

Опытные программисты добавляют к этому коду дополнительное «исключающее ИЛИ», например, E5h. В случае если все значения равны нулю, а система по ошибке обнулила исходные данные – такая хитрость выявит ошибку.

Таковы основные принципы работы с энергонезависимой памятью EEPROM для микроконтроллеров Arduino. Для определенных проектов стоит использовать только этот вид памяти. Он имеет как свои плюсы, так и свои недостатки. Для освоения методов записи и чтения лучше начать с простых задач.

Электрическая схема в ASCII символах

                       +-------+                      J1
              +5-------|RST    |               +5---o o o----+   +-----------+
              +5--o----|/CLR1  |         10K          |      |   |           |
                  |    |       |-----o--/VVV\-- +5    +------|---|26 A13(+5V)|
      +------+    |    |1/2 123|     |              +--------|-->|27 /WE(NC) |
 16 o-|/CS2  |    |    |       |--||-+              | +------|-->|23 A11(/WE)|
      |   CS1|----o----|B1     | 100pF              | | J2   |   |           |
      |      |         |    /Q1|---------->---------o o o    |   |  ZIF28    |
      |    Y1|---------|/A1    |                        |    |   |  socket   |
      | 138  |         +-------+         _ 1/2 74HCT132 |    |   |   for     |
      |      |                     +5 --| \   __        |    |   |  EEPROM   |
      |    Y2|--------------------------|  O--| \       |    |   |           |
  8 o-|A2    |                +-------+ |_/   |  O-----------|-->|22 /OE     |
  7 o-|A1  Y4|--------------->|EN   Y7|-----o-|_/       |    |   |           |
  6 o-|A0  Y3|----+    +5-----|RST    |     |   180 ohm |    |   |           |
      |    Y0|-+  |           |     Y6|-----|---/VVV\---|----|---|1 A14(NC)  |
      |  /CS3| |  |           | 259 Y5|-----|-----------|----+   |           |
      +------+ |  |           |     Y4|-----|-----------|------->|2 A12(NC)  |
            |  |  |           |     Y3|-----|-----------+        |           |
  5 o--->---|--|--|--------o--|D    Y2|-----|------------------->|21 A10     |
  4 o--->---|--|--|------o-|--|A2   Y1|-----|------------------->|24 A9      |
  3 o--->---|--|--|----o-|-|--|A1   Y0|-----|------------------->|25 A8      |
  2 o--->---|--|--|--o-|-|-|--|A0     |     |                    |           |
            |  |  |  | | | |  +-------+     |      +5------------|28 +5V(NC) |
            |  |  |  | | | |                |                    |           |
            |  |  |  | | | |  +-------+     |                    |           |
            |  |  |  | | | |  |     Y7|-----|------------o------>|3  A7      |
            |  |  +---------->|EN     |-----|-----------o|------>|4  A6      |
            |  |     | | | |  |       |-----|----------o||------>|5  A5      |
            |  |     | | | |  | 259   |-----|---------o|||------>|6  A4      |
            |  |     | | | |  |       |-----|--------o||||------>|7  A3      |
            |  |     | | | |  |       |-----|-------o|||||------>|8  A2      |
            |  |     | | | +--|D      |-----|------o||||||------>|9  A1      |
            |  |     | | +----|A2   Y0|-----|-----o|||||||------>|10 A0      |
            |  |     | +------|A1     |     |     ||||||||       |           |
            |  |     +--------|A0  RST|     |     ||||||||       | ZIF28     |
            |  |              +-------+     |   +------------+   | socket    |
            |  |                    |       |   |   data in  |   |  for      |
            |  |                   +5       +-->|/OE         |   | EEPROM    |
            |  |                                |     574    |   |           |
            |  +------------------------------->|CLK         |   |           |
            +----+                              |   data out |   |           |
                 |                              +------------+   |           |
                 |              +------------+     ||||||||      |           |
  9 o-------------------------->| SEL        |     ||||||||      |           |
                 |              |          B3|<----|||||||o------|19 D7      |
 11 o---<-----------------------|Y3        B2|<----||||||o-------|18 D6      |
 12 o---<-----------------------|Y2        B1|<----|||||o--------|17 D5      |
 13 o---<-----------------------|Y1  157   B0|<----||||o---------|16 D4      |
 15 o---<-----------------------|Y0        A3|<----|||o----------|15 D3      |
                 |              |          A2|<----||o--- data---|13 D2      |
                 |              |          A1|<----|o---- bus ---|12 D1      |
                 |       GND----|/OE       A0|<----o-------------|11 D0      |
  +5--o--+       |              +------------+                   |           |
      |  |  __   o---------------------------------------------->|20 /CE   14|
    100K +-|  \  |  __                                           +---------+-+
  sw1 |    |   O-o-|  \ 1/2 74HCT132                                       |
  o-->o----|__/    |   O---390ohm--+                                       |
  |   |          +-|__/            |                                  GND -+
  |  --- 1uF     |                LED
  |  ---     +5--+                 |
  |   |                            |
  +---o----------------------------o- GND

Заметки:

1. номера контактов разъема параллельного порта DB25 с левого угла.
3. 24-контактные микросхемы (например, 2816) должны быть выровнены по нижнему краю 28-контактного ZIF сокета.
2. Номера ножек справа для ZIF-28 сокета, не для микросхем.
7. Названия сигналов в ZIF-28 сокете для 28-контактных EEPROM
( для 24-контактных EEPROM они приведены в приложениях).
4. J1 и J2 однорядные 3-контактные разъемы для джамперов (или используйте DPDT переключатель).
5. Для 28-контактных EEPROM, замкните левую пару контактов как на J1, так и на J2.
6. Для 24-контактных EEPROM, замкните левую пару контактов и на J1, и на J2.
8. Переключатель SPST sw1 должен быть открыт для разрешения функционирования программатора.
9. Полный список контактов микросхем смотрите в файле pinouts.txt

takdoom@yahoo.com

Описание памяти EEPROM

Arduino – это целое семейство различных устройств для создания электронных проектов. Микроконтроллеры очень удобны для использования, доступны к освоению даже новичку. Каждый микроконтроллер состоит из платы, программ для обеспечения работы, памяти. В этой статье будет рассмотрена энергонезависимая память, используемая в Arduino.

Ардуино предоставляет своим пользователям три типа встроенной памяти устройств: стационарное ОЗУ (оперативно-запоминающее устройство или SRAM — static random access memory) – необходимо для записи и хранения данных в процессе использования; флеш-карты – для сохранения уже записанных схем; EEPROM – для хранения и последующего использования данных.

По теме: Скачать библиотеку EEPROM

На ОЗУ все данные стираются, как только происходит перезагрузка устройства либо отключается питание. Вторые две сохраняют всю информацию до перезаписи и позволяют извлекать ее при необходимости. Флеш-накопители достаточно распространены в настоящее время. Подробнее стоит рассмотреть память EEPROM.

Аббревиатура расшифровывается, как Electrically Erasable Programmable Read-Only Memory и в переводе на русский дословно означает – электрически стираемая программируемая память только для чтения. Производитель гарантирует сохранность информации на несколько десятилетий вперед после последнего отключения питания (обычно приводят срок в 20 лет, зависит от скорости снижения заряда устройства).

При этом нужно знать, что возможность перезаписи на устройство ограничена и составляет не более 100 000 раз. Поэтому рекомендуют аккуратно и внимательно относиться к вносимым данным и не допускать перезаписи лишний раз.

Объем памяти, в сравнении с современными носителями, очень небольшой и разный для различных микроконтроллеров. Например, для:

  • ATmega328 – 1кБ
  • ATmega168 и ATmega8 – 512 байт,
  • ATmega2560 и ATmega1280 – 4 кБ.

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

Для записи на EEPROM требуется значительное количество времени – около 3 мс. Если в момент записи отключается питание, данные не сохраняются вовсе либо могут быть записаны ошибочно. Требуется всегда дополнительно проверять внесенную информацию, чтобы избежать сбоев во время работы. Считывание данных происходит гораздо быстрее, ресурс памяти от этого не снижается.

5Работа с EEPROM как с массивом

Очень удобная возможность – обращение к ячейкам памяти как к элементам массива EEPROM. В данном скетче в процедуре setup() мы сначала запишем данные в 4 первых байта, а в процедуре loop() ежеминутно будем считывать данные из всех ячеек и выводить их в последовательный порт.

#include <EEPROM.h>

void setup() {
  EEPROM = 11;  // записываем 1-ю ячейку
  EEPROM = 121; // записываем 2-ю ячейку
  EEPROM = 141; // записываем 3-ю ячейку
  EEPROM = 236; // записываем 4-ю ячейку
  Serial.begin(9600);
}

void loop() {
  for (int addr=0; addr}
  
  delay(60000);
}

Работа с ячейками памяти EEPROM Arduino как с элементами массива

Интерфейс

Устройства EEPROM используют последовательный или параллельный интерфейс для ввода/вывода информации.

Устройства с последовательным интерфейсом

Общий интерфейс может быть в виде шин: SPI и I²C, Microwire, UNI/O и 1-Wire.

Типичный EEPROM протокол содержит 3 фазы: Код операции, фазы адреса и фазы данных. Код операции — обычно первые 8 бит, далее следует фаза адреса в 8-24 бита (зависит от устройства) и в конце запись или чтение информации.

Каждое устройство EEPROM, как правило, имеет свой код операций для выполнения различных функций.
Функции для SPI EEPROM могут быть:

  • Write Enable (WRENAL)
  • Write Disable (WRDI)
  • Read Status Register (RDSR)
  • Write Status Register (WRSR)
  • Read Data (READ)
  • Write Data (WRITE)

EEPROM на печатной плате карты памяти ПК.

Ряд других операций, которые поддерживают некоторые EEPROM устройства:

  • Program
  • Sector Erase
  • Chip Erase commands

Устройства с параллельным интерфейсом

Параллельные устройства EEPROM обычно содержат в себе 8-битную шину данных и адресную шину достаточного объёма для покрытия всей памяти. Большинство таких устройств имеют защиту записи на шинах и возможность выбора чипа. Некоторые микроконтроллеры содержат в себе такие интегрированные EEPROM.
Операции на таких устройствах проще и быстрее в сравнении с последовательным интерфейсом EEPROM, но за счет того, что для его функционирования требуется большое количество точек вывода (28pin и больше), параллельная память EEPROM теряет популярность уступая место памяти типа Flash и последовательной EEPROM.

Другие устройства

Память EEPROM используется для функционирования и в других видах продуктов. Продукты, такие как часы реального времени, цифровые потенциометры, цифровые датчики температуры, в частности, могут иметь небольшое количество EEPROM для хранения информации о калибровке или другие данные, которые должны быть доступны в случае потери питания. Он также был использован на игровых картриджах, чтобы сохранить игровой прогресс и настройки, до использования внешней и внутренней флэш-памяти.

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

Для начала рассмотрим запись в EEPROM Arduino числа больше, чем 255, например число 999. При записи в EEPROM число 999 будет разбиваться на множитель (старший байт) и недостающее число (младший байт), занимая при этом уже две ячейки в энергонезависимой памяти (т.е. 999 = 3×256 + 231). Чтобы вывести сохраненное число на монитор порта, его нужно будет «собрать» с помощью функции .

Скетч. Запись в память EEPROM int, float

#include <EEPROM.h>  // импортируем библиотеку

int num = 999;                      // разбиваем число на 2 байта
byte hi  = highByte(num);   // старший байт
byte low = lowByte(num);  // младший байт

void setup() {
  Serial.begin(9600);    // запускаем монитор порта

   EEPROM.update(1, hi);     // записываем старший байт в ячейку 1
   EEPROM.update(2, low); // записываем младший байт в ячейку 2

  delay(1000);

  byte val1 = EEPROM.read(1);  // считываем 1 байт по адресу ячейки
  byte val2 = EEPROM.read(2);  // считываем 1 байт по адресу ячейки

  Serial.println("highByte - "+String(val1));  // выводим старший байт на монитор
  Serial.println("lowByte  - "+String(val2));  // выводим младший байт на монитор

  int NUM = word(hi, low);       // "собираем" число из байтов
  Serial.println("int num  - "+String(NUM));    // выводим полученное число
}

void loop() {
}

Пояснения к коду:

  1. для записи данных в ячейку в программе использована функция , которая перезаписывает ячейку только в случае различия сохраняемых данных с данными в ячейке EEPROM Arduino Uno;
  2. основная проблема с сохранением больших чисел (int, float) в память EEPROM заключается в том, чтобы случайно не перезаписать нужную ячейку новой информацией. Для этого нужно учитывать размер сохраняемых данных в ПЗУ, используя функции и .

Скетч. Запись строк в EEPROM (String)

#include <EEPROM.h>  // импортируем библиотеку

int address = 10;  // адрес первой ячейки для записи

long cod = 8904; // разбиваем телефонный номер на две части
long tel = 2768282;
String email = "ROBOTEHNIKA18@GMAIL.COM"; // сохраняем в строке адрес почты

long COD; // создаём новые переменные для чистоты эксперимента
long TEL;
String EMAIL;

void setup() {
  Serial.begin(9600);  // запускаем монитор порта

  EEPROM.put(address, cod);      // сохраняем код телефона в памяти Ардуино
  address += sizeof(cod);              // узнаем адрес следующей свободной ячейки
  EEPROM.put(address, tel);       // сохраняем номер телефона в памяти Ардуино
  address += sizeof(tel);                // узнаем адрес следующей свободной ячейки
  EEPROM.put(address, email);  // сохраняем электронную почту в памяти

  address = 10;  // адрес первой ячейки для чтения

  Serial.print("Phone: ");  // выводим телефонный номер на монитор
  Serial.print(EEPROM.get(address, COD));
  address += sizeof(COD);
  Serial.println(EEPROM.get(address, TEL));
  address += sizeof(TEL);

  Serial.print("Email: ");  // выводим электронную почту на монитор
  Serial.println(EEPROM.get(address, EMAIL));
}

void loop() {
}

Пояснения к коду:

  1. перед сохранением новых данных в памяти, следует узнать размер данных, которые были сохранены, чтобы начать запись в новой ячейке;
  2. удалив из кода строчки для записи данных, вы можете каждый раз при запуске программы считывать все сохраненные данные из ПЗУ Ардуино.

Принцип действия

Принцип работы EEPROM основан на изменении и регистрации электрического заряда в изолированной области (кармане) полупроводниковой структуры.

Ячейка памяти EEPROM представляет собой транзистор, в котором затвор выполняется из поликристаллического кремния. Затем этот затвор окисляется и в результате он будет окружен оксидом кремния — диэлектриком с прекрасными изолирующими свойствами. Изменение заряда («запись» и «стирание») производится приложением между затвором и истоком большого потенциала, чтобы напряженность электрического поля в тонком диэлектрике между каналом транзистора и карманом оказалась достаточна для возникновения туннельного эффекта. Для усиления эффекта туннелирования электронов в карман при записи применяется небольшое ускорение электронов путём пропускания тока через канал полевого транзистора (явление инжекции горячих носителей). После снятия программирующего напряжения индуцированный заряд остаётся на плавающем затворе, и, следовательно, транзистор остаётся в проводящем состоянии. Заряд на его плавающем затворе может храниться десятки лет.
Чтение выполняется полевым транзистором, для которого карман выполняет функцию затвора. Потенциал плавающего затвора изменяет пороговые характеристики транзистора, что и регистрируется цепями чтения.

Ранее подобная конструкция ячеек применялась в ПЗУ с ультрафиолетовым стиранием (EPROM).Сейчас особенностью классической ячейки EEPROM можно назвать наличие второго транзистора, который помогает управлять режимами записи и стирания. Стирание информации производится подачей на программирующий затвор напряжения, противоположного напряжению записи. В отличие от ПЗУ с ультрафиолетовым стиранием, время стирания информации в EEPROM памяти составляет около 10 мс. Структурная схема энергонезависимой памяти с электрическим стиранием не отличается от структурной схемы масочного ПЗУ. Единственное отличие — вместо плавкой перемычки используется описанная выше ячейка.

Некоторые реализации EEPROM выполнялись в виде одного трёхзатворного полевого транзистора (один затвор плавающий и два обычных). Эта конструкция снабжается элементами, которые позволяют ей работать в большом массиве таких же ячеек. Соединение выполняется в виде двумерной матрицы, в которой на пересечении столбцов и строк находится одна ячейка. Поскольку ячейка EEPROM имеет третий затвор, то, помимо подложки, к каждой ячейке подходят 3 проводника (один проводник столбцов и 2 проводника строк).

Упрощенная структурная схема EEPROM.

Чтение и запись EEPROM

Регистры Адреса EEPROM (EEPROM Access Registers) доступны через область ввода-вывода.

Время доступа для записи в EEPROM приведено в таблице 5.1. Функция
самоуправления временем, однако, позволяет программному обеспечению
пользователя определить, когда можно записать следующий байт

Если код
пользователя содержит инструкции по записи EEPROM, необходимо принять
некоторые меры предосторожности. В источниках питания с мощными фильтрами,
питание VCC при включении/выключении медленно повышается (понижается)

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

Таблица 5.1. Биты режимов EEPROM.

EECR Время программирования Операция
EEPM1 EEPM0
3,4 мс Стирание и запись за одну операцию (Атомарная операция)
1 1,8 мс Только стирание
1 1,8 мс Только запись
1 1 Зарезервировано для будущего использования

Чтобы предотвратить непреднамеренную запись EEPROM, необходимо выполнить
определенные правила записи. Подробности см. ниже в разделах
“” и
“”.

Когда выполняется чтение EEPROM, работа процессора приостанавливается на
четыре , прежде чем следующая
инструкция может быть выполнена. При записи EEPROM останавливается на два такта перед выполнением следующей инструкции. То есть на время чтения/записи EEPROM процессор перестаёт выполнять команды и никакие другие инструкции не могут быть выполнены.

Часть первая, I2C и библиотека «Wire».

Последовательный протокол обмена данными IIC (также называемый I2C — Inter-Integrated Circuits, межмикросхемное соединение). Разработана фирмой Philips Semiconductors в начале 1980-х как простая 8-битная шина внутренней связи для создания управляющей электроники. Так как право на использование его стоит денег фарма Atmel назвала его TWI, но смысл от этого не меняется.

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

Для передачи данных используются две двунаправленные лини передачи данных. SDA (Serial Data) шина последовательных данных и SCL (Serial Clock) шина тактирования. Обе шины подтянуты резисторами к плюсовой шине питания. Передача/Прием сигналов осуществляется прижиманием линии в 0, в единичку устанавливается сама, за счет подтягивающих резисторов.

В сети есть хотя бы одно ведущее устройство (Master), которое инициализирует передачу данных и генерирует сигналы синхронизации и ведомые устройства (Slave), которые передают данные по запросу ведущего. У каждого ведомого устройства есть уникальный адрес, по которому ведущий и обращается к нему. Конечно понятно что Ведущий это наш микроконтроллер , а ведомый наша память. Ведущее устройство начинает прижимать шину SCL  к нулю с определенной частотой, а шину SDA прижимать или отпускать на определенное число тактов передавая Единичку или Нолик. Передача данных начинается с сигнала START потом передается 8 бит данных и 9-тым битом Ведомое устройство подтверждает прием байт  прижимая шину SDA к минусу. Заканчивается передача сигналом STOP.

Библиотека «Wire».

Для облегчения обмена данными с устройствами по шине I2C для Arduino написана стандартная библиотека Wire которая есть уже в комплекте IDE. Она имеет следующие основные функции:

Wire.begin(Address) вызывается один раз для инициализации  и подключения к шини как Ведущий или Ведомое устройство. Если Address не задан подключаемся как Мастер устройство.

Wire.beginTransmission(address)  начинает передачу на ведомое I2C устройство с заданным адресом.

Wire.endTransmission() прекращает передачу данных ведомому. Функция возвращает значение типа byte:

  • 0 — успех.
  • 1- данные слишком длинны для заполнения буфера передачи.
  • 2 — принят NACK при передаче адреса.
  • 3 — принят NACK при передаче данных.
  • 4 — остальные ошибки.

Wire.write() запись данных  от ведомого устройства в отклик на запрос от ведущего устройства, или ставит в очередь байты для передачи от мастера к ведомому устройству.Фактически записывает данные в буфер. Размер буфера 32 байта ( минус 2 байта адрес, фактически 30 байт), а передает буфер функция Wire.endTransmission().

  • Wire.write(value) — value: значение для передачи, один байт.
  • Wire.write(string) — string: строка для передачи, последовательность байтов.
  • Wire.write(data, length) — data: массив данных для передачи, байты. length: количество байтов для передачи.

Wire.read() Считывает байт, который был передан от ведомого устройства к ведущему или который был передан от ведущего устройства к ведомому. Возвращаемое значение byte : очередной принятый байт.

Это самые основные функции библиотеке, остальные мы рассмотрим по ходу пьесы ))

Arduino EEPROM запись, чтение данных

Для занятия нам понадобятся следующие детали:

плата Arduino Uno / Arduino Nano / Arduino Mega;

Скетч. Чтение Arduino EEPROM (read)

#include <EEPROM.h>  // импортируем библиотеку
int address;                     // переменная для хранения адреса
byte value;                      // переменная для хранения значения

void setup() {
   Serial.begin(9600);  // запускаем монитор порта
   Serial.println(EEPROM.length());  // выводим общее количество ячеек в памяти
   delay(3000);

   // перебираем в цикле все адреса в EEPROM памяти, пока все не переберем
   while (address < EEPROM.length()) {
      value = EEPROM.read(address);  // считываем значение байта
      Serial.print("Address: ");               // выводим полученные данные на монитор порта
      Serial.print(String(address));
      Serial.print(", value: ");
      Serial.println(String(value));
      address++;                                       // наращиваем адрес и повторяем операции
      delay(100);
   }
}
void loop() {
}

Пояснения к коду:

  1. функция позволяет узнать общее число ячеек в памяти. Если вы работаете с Nano ATmega168, то цикл закончится на 512 ячейке;
  2. если память не использовалась, то все значения в ячейках будут равны 255.

Скетч. Запись Arduino EEPROM (write)

#include <EEPROM.h>  // импортируем библиотеку
int address;                     // переменная для хранения адреса
byte value;                      // переменная для хранения значения

void setup() {
   Serial.begin(9600);  // запускаем монитор порта
   Serial.println(EEPROM.length());  // выводим общее количество ячеек в памяти
   EEPROM.write(0,100);                    // записываем значение 100 в ячейку с адресом 0
   delay(3000);

   // перебираем в цикле все адреса в EEPROM памяти, пока все не переберем
   while (address < EEPROM.length()) {
      value = EEPROM.read(address);  // считываем значение байта
      Serial.print("Address: ");               // выводим полученные данные на монитор порта
      Serial.print(String(address));
      Serial.print(", value: ");
      Serial.println(String(value));
      address++;                                       // наращиваем адрес и повторяем операции
      delay(100);
   }
}
void loop() {
}

Пояснения к коду:

  1. функция каждый раз перезаписывает данные в ячейке с адресом 0, что снижает жизненный цикл памяти, лучше использовать ;
  2. в следующих примерах не будем перебирать все ячейки в памяти, а запишем и прочитаем только несколько байт в энергонезависимой памяти Ардуино.

Arduino eeprom работа с памятью
Пример работы предыдущей программы

Скетч. Перезапись в Arduino EEPROM (update)

#include <EEPROM.h>  // импортируем библиотеку

void setup() {
   Serial.begin(9600);  // запускаем монитор порта

   EEPROM.update(0,100);               // записываем значение 100 в ячейку с адресом 0
   delay(2000);

   Serial.println(EEPROM.read(0));  // выведет на монитор порта 100
   Serial.println(EEPROM);          // выведет на монитор порта 100
   }
}
void loop() {
}

Пояснения к коду:

  1. вывод данных из ячейки с адресом 0 выполняется с помощью разных функций;
  2. функции write/read/update позволяют работать только с типами данных byte и использовать эти функции для данных типа float или int уже нельзя. Для этого следует использовать put/get, которые мы рассмотрим далее.

Родственные типы памяти

Флэш-память является более поздней формой EEPROM. В промышленности, существует конвенция, чтобы зарезервировать термин EEPROM для побайтно стираемой памяти относительно поблочно стираемой флэш-памяти. EEPROM занимает большую площадь кристалла, чем флэш-память для той же мощности, потому что каждая ячейка обычно требует чтения, записи и стирания, в то время как для стирания Flash схемы памяти используются большие блоки ячеек.

Новые технологии энергонезависимой памяти, такие как в FeRAM и MRAM медленно заменяют EEPROM в некоторых устройствах, но, как ожидается, останется небольшая доля рынка для EEPROM в обозримом будущем.

Запись EEPROM

Для записи ячейки памяти пользователь должен записать адрес в EEARL, а данные — в EEDR. Если биты EEPMn равны 0b10, то запись EEPE (в течение четырех тактов после записи EEMPE) вызовет только операцию записи (время программирования приведено выше в таблице 5-1). В EEPE бит остается установленным до тех пор, пока операция записи не завершится. Если записываемая ячейка не была очищена (стерта) перед записью, сохраненные данные должны считаться потерянными. Пока микроконтроллер занят программированием, невозможно выполнить какие-либо другие операции с EEPROM.

Калибровка генератора тактовой частоты с помощью регистра калибровки (Oscillator Calibration Register) используется для настройки времени доступа к EEPROM. Убедитесь, что частота генератора соответствует требованиям, описанным в разделе “OSCCAL – Oscillator Calibration Register » (в оригинальной документации стр. 27, на моём сайте будет описана позже).

В следующих примерах кода показана одна функция на Ассемблере и C для стирания, записи или атомарной записи EEPROM. В примерах предполагается, что прерывания управляются (например, отключением прерываний глобально) таким образом, что во время выполнения этих функций прерывания не будут происходить.

EEPROM_write:
; Дождаться завершения предыдущей записи
sbic EECR, EEPE
rjmp EEPROM_write
; Установить режим программирования
ldi r16, (0<<EEPM1)|(0<<EEPM0)
out EECR, r16
; Записать начальный адрес (r17) в регистр адреса
out EEARL, r17
; Записать данные (r16) в регистр данных
out EEDR, r16
; Записать логическую единицу в EEMPE
sbi EECR, EEMPE
; Начать запись EEPROM, установив EEPE
sbi EECR, EEPE
ret
void EEPROM_write(unsigned char ucAddress, unsigned char ucData)
{
/* Дождаться завершения предыдущей записи */
while(EECR & (1<<EEPE)) ;
/* Установить режим программирования */
EECR = (0<<EEPM1)|(0>>EEPM0)
/* Настроить регистры адреса и данных */
EEARL = ucAddress;
EEDR = ucData;
/* Записать логическую единицу в EEMPE */
EECR |= (1<<EEMPE);
/* Начать запись EEPROM, установив EEPE */
EECR |= (1<<EEPE);
}

См. также пример здесь.

В следующих примерах кода показаны функции на Ассемблере и C для чтения EEPROM. В примерах предполагается, что прерывания управляются таким образом, чтобы во время выполнения этих функций не возникало прерываний.

EEPROM_read:
; Дождаться завершения предыдущей записи
sbic EECR, EEPE
rjmp EEPROM_read
; Записать начальный адрес (r17) в регистр адреса
out EEARL, r17
; Начать запись EEPROM, записав EERE
sbi EECR, EERE
; Читать данные из регистра данных
in r16, EEDR
ret
unsigned char EEPROM_read(unsigned char ucAddress)
{
/* Дождаться завершения предыдущей записи */
while(EECR & (1<<EEPE))
;
/* Настроить регистра адреса */
EEARL = ucAddress;
/* Начать чтение EEPROM, записав EERE */
EECR |= (1<<EERE);
/* Вернуть данные из регистра данных */
return EEDR;
}

См. также пример здесь.