Здравствуйте, уважаемые читатели! Продолжаем знакомиться с фундаментальными вещами, без объяснения которых не возможно проектирование самодельных устройств на основе микроконтроллеров.
В данной статье речь пойдет об энергонезависимой памяти EEPROM (электрически стираемое программируемое постоянное запоминающее устройство). Как видно из названия EEPROM является разновидностью ПЗУ, важной особенностью которой является возможность перезаписывать хранимые в памяти значения (в отличие от FLASH-памяти) во время выполнения скетча и сохранять после отключения питания.
Энергонезависимая память EEPROM прекрасно подходит для хранения настроек работы устройства, которые были выбраны пользователем во время его работы и должны быть сохранены при отключении питания. Например, пользователь может задать определенную температуру, при которой микроконтроллер должен включить нагревательный элемент. Или определенную влажность почвы, при которой будет включен автополив. Определенную освещенность, при которой будет включено освещение и т.д. Так же в данной памяти можно логировать данные, получаемые от внешних датчиков и возникающие в процессе работы ошибки для последующей отладки.
Следует отметить, что запись одного байта в EEPROM занимает 3.3 миллисекунды. А скорость чтения менее 1 микросекунды. EEPROM память рассчитана на 100,000 циклов записи/удаления (https://www.arduino.cc/en/Reference/EEPROMWrite).
В размещенной ниже таблице можно посмотреть сравнение различных типов памяти у микроконтроллеров серии ATtiny и микроконтроллера ATmega328 (основы Arduino UNO).
Как видно из таблицы, размер EEPROM либо равен размеру памяти SRAM (оперативной памяти), либо даже меньше неё. И существенно меньше размера FLASH-памяти (памяти для хранения кода программы).
Работа с памятью EEPROM в среде Arduino UNO отличается от работы с памятью SRAM. При работе с оперативной памятью нам не нужно заботиться, где именно располагается значение переменной, к которой мы обращаемся. Т.к. на этапе компиляции программы под каждую переменную, в зависимости от ее размера, выделяется блок памяти, где и хранится значение переменной. Мы же извлекаем это значение или перезаписываем его, обращаясь к переменной по имени.
При работе с памятью EEPROM мы должны указывать непосредственно адрес байта, в котором храниться переменная. Учитывая, что переменные bool, char, byte – занимают 1 байт, переменные int, word - 2 байта, а переменные long, float – 4 байта.
Т.е. в память EEPROM ATtiny13 можно записать 64 значения переменной типа byte, 32 значения переменной типа int и 16 значений переменной типа long. При этом в качестве адреса ячейки памяти при записи и чтении мы указываем номер первого байта переменной.
Для работы с памятью EEPROM в среде Arduino IDE служит специальная библиотека EEPROM.h. В её примерах есть несколько скетчей, показывающих как работать с основными функциями библиотеки.
Основные функции библиотеки EEPROM.h.
(источник - https://www.arduino.cc/en/Reference/EEPROM)
EEPROM.length () - возвращает размер памяти EEPROM в байтах.
EEPROM.write (address, value) – записывает значение value величиной 1 байт (0-255) по адресу address (от 0 до EEPROM.length()).
EEPROM.read(address) – читает и возвращает байт данных, размещенной по адресу address.
EEPROM.update(address, value) – обновляет байт памяти (записывает новое значение), если новое значение отличается от текущего. Этот вариант записи значения переменной предпочтительнее, т.к. продлевает срок службы памяти, уменьшая число перезаписей.
EEPROM.put(address, data) – автоматически вычисляет размер и записывает данные любого типа по адресу address.
С помощью данной функции можно размещать в памяти переменные разных размеров.
Например, можно последовательно записывать в память переменные разной длины:
int address = 0;
float val1 = 123.456f;
byte val2 = 64;
char name[10] = "Arduino";
не забывая вычислять размер переменной в байтах и сдвигать начальный байт записи на данный размер:
EEPROM.put(address, val1);
address += sizeof(val1); //+4
EEPROM.put(address, val2);
address += sizeof(val2); //+1
EEPROM.put(address, name);
address += sizeof(name); //+10
.....
Так же можно объединить значения переменных в массив или сами переменные в структуры и записывать с помощью функции EEPROM.put() массив или структуру целиком.
EEPROM.get(address, data) – считывает данные по адресу address и заносит их в указанную переменную data.
Естественно, что тип и размер данных, записанных с помощью функции EEPROM.put(), должен совпадать с типом и размером данных, читаемых функцией EEPROM.get(). В примерах библиотеки есть скетчи, иллюстрирующие работу этих функций.
Еще в библиотеке есть оператор EEPROM[], который позволяет работать с памятью EEPROM как с массивом байтов.
byte val = EEPROM[0]; - т.е., получить значение из нулевой ячейки памяти EEPROM
val++; - добавить к полученному значению единицу
EEPROM[0] = val; - и записать новое значение в нулевую ячейку памяти EEPROM
В следующей статье, я расскажу, как увеличить объем памяти EEPROM до 64 КБ. Это будет особенно актуально для микроконтроллеров с малым объемом всех типов памяти, таких как ATtiny.
За счет того, что скорость чтения данных из памяти EEPROM очень велика, мы можем использовать внешнюю память EEPROM как дополнительную оперативную память, либо хранить в ней достаточно объемные массивы данных. Например, шрифты для работы с LED-матицами и LCD-дисплеями. В статье "Создание анимации для LED матрицы 16x16 адресных светодиодов", мы хранили массив изображения с помощью ключевого слова PROGMEM во FLASH-памяти (из-за нехватки оперативной памяти). Подключив внешнюю EEPROM память, изображения и шрифты можно будет хранить во внешней памяти, оставив FLASH-память исключительно для того, для чего она и предназначена, т.е. для хранения прошивки микроконтроллера.
_________________________________________________________
Спасибо, что дочитали до конца! Если статья понравилась, нажмите, пожалуйста, соответствующую кнопку. Если интересна тематика электроники и различных электронных самоделок, подписывайтесь на канал. До встречи в новых статьях!