Как хранить данные в Arduino
У плат семейства плат Arduino есть несколько видов памяти. Во-первых, это статическое ОЗУ (оперативное запоминающее устройство), которая используется для хранения переменных в процессе выполнения программы. Во-вторых, это флеш-память, в которой хранятся написанные вами скетчи.
И в-третьих, это EEPROM, которую можно использовать для постоянного хранения информации. Первый тип памяти – энергозависимый, он теряет всю информацию после перезагрузки Arduino. Вторые два типа памяти хранят информацию пока она не будет перезаписана новой, даже после отключения питания.
Последний тип памяти – EEPROM – позволяет записывать данные, хранить их и считывать при необходимости. Эту память мы и рассмотрим сейчас.
EEPROM означает Electrically Erasable Programmable Read-Only Memory, т.е. электрически стираемое перепрограммируемое постоянное запоминающее устройство. Данные в этой памяти могут храниться десятки лет после отключения питания. Количество циклов перезаписи – порядка нескольких миллионов раз.
Количество EEPROM памяти в Arduino довольно ограничено:
- для плат, основанных на микроконтроллере ATmega328 (например, Arduino UNO и Nano), количество памяти составляет 1 кБ,
- для плат на ATmega168 и ATmega8 – 512 байт,
- на ATmega2560 и ATmega1280 – 4 кБ.
2Библиотека EEPROM
Для работы с EEPROM для Arduino написана специальная библиотека, которая входит в Arduino IDE по умолчанию. Библиотека содержит следующие возможности.
ФункцияНазначениеread(address) | считывает 1 байт из EEPROM; address – адрес, откуда считываются данные (ячейка, начиная с 0); |
write(address, value) | записывает в память значение value (1 байт, число от 0 до 255) по адресу address; |
update(address, value) | заменяет значение value по адресу address, если её старое содержимое отличается от нового; |
get(address, data) | считывает данные data указанного типа из памяти по адресу address; |
put(address, data) | записывает данные data указанного типа в память по адресу address; |
EEPROM[address] | позволяет использовать идентификатор “EEPROM” как массив, чтобы записывать данные в память и считывать их из памяти. |
Чтобы задействовать библиотеку в скетче, подключаем её директивой #include EEPROM.h.
3Запись целых чисел в EEPROM
Давайте запишем в память EEPROM два целых числа, а затем прочитаем их из EEPROM и выведем в последовательный порт. С числами от 0 до 255 проблем нет, они занимают как раз 1 байт памяти и с помощью функции EEPROM.write() записываются в нужную ячейку.
Если число больше, чем 255, то с помощью операторов highByte() и lowByte() его нужно делить на байты и записывать каждый байт в свою ячейку. Максимальное число при этом – 65536 (или 216).
#include // подключаем библиотеку EEPROM void setup() { int smallNum = 123; // целое число от 0 до 255 EEPROM.write(0, smallNum); // запись числа в ячейку 0 int bigNum = 789; // число > 255 разбиваем на 2 байта (макс. 65536) byte hi = highByte(bigNum); // старший байт byte low = lowByte(bigNum); // младший байт EEPROM.write(1, hi); // записываем в ячейку 1 старший байт EEPROM.write(2, low); // записываем в ячейку 2 младший байт Serial.begin(9600); // инициализация послед. порта } void loop() { for (int addr=0; addr
Смотрите, монитор последовательного порта в ячейку 0 просто выводит число, меньшее, чем 255. В ячейках 1 и 2 хранится большое число 789. При этом ячейка 1 хранит множитель переполнения 3, а ячейка 2 – недостающее число 21 (т.е. 789 = 3×256 + 21).
Запись целых чисел в EEPROM Arduino
Чтобы заново «собрать» большое число, разобранное на байты, есть функция word(): int val = word(hi, low), где “hi” и “low” – это значения старшего и младшего байтов числа “val”.
Во всех остальных ячейках, которые не были нами ни разу записаны, хранятся числа 255.
4Запись чисел с плавающей запятой и строк в EEPROM
Для записи чисел с плавающей запятой и строк нужно использовать метод EEPROM.put(), а для чтения – EEPROM.get().
#include // подключаем библиотеку void setup() { int addr = 0; // адрес float f = 3.1415926f; // число с плавающей точкой (типа float) EEPROM.put(addr, f); // записали число f по адресу addr addr += sizeof(float); // вычисляем следующую свободную ячейку памяти char name[20] = “Hello, SolTau.ru!”; // создаём массив символов EEPROM.put(addr, name); // записываем массив в EEPROM Serial.begin(9600); // инициализация послед. порта } void loop() { for (int addr=0; addr
В процедуре setup() сначала запишем число с плавающей запятой “f”. Затем сдвинемся на количество ячеек памяти, которое занимает тип “float”, и запишем строку символов “char” ёмкостью 20 ячеек.
В процедуре loop() будем считывать все ячейки памяти и пытаться расшифровать их сначала как тип “float”, а затем как тип “char”, и выводить результат в последовательный порт.
Запись чисел с плавающей запятой в EEPROM Arduino
Видно, что значение в ячейках с 0 по 3 правильно определилось как число с плавающей точкой, а начиная с 4-ой – как строка.
Появляющиеся значения ovf (переполнение) и nan (не число) говорят о том, что значение в ячейке памяти по этому адресу не может быть корректно преобразовано в число с плавающей точкой. Если вы точно знаете, какого типа данные какие ячейки памяти занимают, то у вас не будет возникать проблем.
5Работа с EEPROM как с массивом
Очень удобная возможность – обращение к ячейкам памяти как к элементам массива EEPROM. В данном скетче в процедуре setup() мы сначала запишем данные в 4 первых байта, а в процедуре loop() ежеминутно будем считывать данные из всех ячеек и выводить их в последовательный порт.
#include void setup() { EEPROM[0] = 11; // записываем 1-ю ячейку EEPROM[1] = 121; // записываем 2-ю ячейку EEPROM[2] = 141; // записываем 3-ю ячейку EEPROM[3] = 236; // записываем 4-ю ячейку Serial.begin(9600); } void loop() { for (int addr=0; addrРабота с ячейками памяти EEPROM Arduino как с элементами массива
Источник: https://soltau.ru/index.php/arduino/item/378-kak-khranit-dannye-v-arduino
Основные особенности EEPROM памяти
EEPROM память является энергонезависимой. Это значит, что после записи информации, и отключения питания, данные сохранятся. Пожалуй, самым приятным моментом использования внешней памяти является мысль того, что она есть, и существует дополнительное хранилище для информации. Однако, когда дело доходит до использования, всё становится немного иначе.
Необходимо выполнить строгую последовательность действий, предписанных руководством, чтобы «достучаться» и попытаться произвести операцию записи. С чтением дела обстоят немного проще. Да и в целом картина выглядела бы неплохо, если бы процесс не осложнял сам отладчик среды разработки.
Автор не решается сказать, кто здесь виноват, но чуть ниже вы убедитесь, что порой придётся «поработать», чтобы добиться результата.
Чтение и запись в EEPROM память выполняется в нормальном режиме работы и не требует остановки МК. За 1 машинный цикл способна выполниться операция с 1 байтом памяти. Операция записи производится по принципу «стирание – запись».
Даже когда ячейка пуста, МК сначала производи подготовку, «записывая/стирая» значение типа 0, а потом производит запись информации, время которой, контролируется внутренним таймером, и зависит от напряжения и питания.
Доступ к памяти программ, а также все прерывания, во время операции записи запрещёны. Все возникшие прерывания ставятся в очередь, а после завершения операции, происходит переход по соответствующему вектору.
Такая последовательность действий обусловлена из-за конвейерной обработки данных. Для доступа к функциям EEPROM памяти существует шесть регистров специального назначения:
· EEDATA;
· EEDATH;
· EEADR;
· EEADRH;
· EECON1;
· EECON2;
Вкратце рассмотри назначение каждого из них.
Регистр EEADR
Регистр EEADR используется для сохранения ячейки памяти данных. Спаренные регистры EEADRH:EEADR содержат 14-разрядные данные для записи или отображают значение из памяти программ при чтении. Также для EEPROM памяти данных должен быть загружен физически реализованный адрес памяти программ, потому что циклическая адресация не поддерживается, то есть адрес 0х4000h отображается как 0х0000h.
Регистр EEDATA
Данные сохраняются/читаются из регистра EEDATA.
Регистры EECON1, EECON2
Относятся к регистрам управления. Регистр EECON1 содержит биты управления косвенной операцией записи/чтения EEPROM памяти данных и FLASH памяти программ. Регистр EECON2 физически не реализован, он используется только при операциях записи с целью предотвращения случайной записи. На рис.6.1. представлена информация об управляющих битах регистра EECON1.
Рис.6.1 – управляющий регистр EECON1
Бит: | Значение: |
Производит выбор памяти, к которой будет выполненное обращение: EEPGD = 0 – обращение к EEPROM памяти; EEPGD = 1 – обращение к FLASH памяти; | |
Не реализован, читается как 0. | |
Не реализован, читается как 0. | |
Не реализован, читается как 0. | |
WRERR – флаг ошибки записи. 0 – состояние – операция завершена; 1 – состояние – операция прервана. Возможно причинной послужил сигнал сброса. | |
WREN – применяется для разрешения/запрещения записи. 0 – операция записи запрещена. 1 – операция записи разрешена. Аппаратно сбрасывается в 0, по завершении операции записи. | |
WR – инициализация записи данных. Возможно установить программно 1, что будет служить признаком начала инициализации. 0 – запись завершена. 1 – начать процесс инициализации записи. Сбрасывается автоматически, после завершения инициализации. | |
RD – инициализирует операцию чтения из указанной памяти. 1 – инициализировать чтение. Сбрасывается автоматически по завершении операции. При чтении из EEPROM памяти, данные будут доступны в регистре EEDATA в следующем машинном цикле, после установки бита. При чтении FLASH памяти программ, данные будут доступны на 2 машинном цикле. 0 – чтение завершено. |
Первоначальное знакомство завершено. В следующем разделе представлены примеры операций чтение/запись с EEPROM памятью.
Использование EEPROM памяти
Операции чтения/записи с EEPROM памятью довольно сложно выполнимы. Операция записи имеет высший приоритет, поэтому рассмотрим её первой.
Источник: https://cyberpedia.su/6x5fc7.html
Учебный курс AVR. Работа с EEPROM. Объявление переменных. Чтение и запись данных. Ч1
Введение
При программировании микроконтроллеров AVR иногда возникает потребность сохранять данные, которые бы после выключения питания или сброса контроллера не изменяли свое значение.
Для этих целей в составе AVR есть энергонезависимая память данных EEPROM (Electrically Erasable Programmable Read-Only Memory — электрически стираемое перепрограммируемое ПЗУ).
EEPROM имеет адресное пространство отличное от адресных пространств ОЗУ и flash памяти, в котором можно читать и записывать одиночные байты. В зависимости от модели микроконтроллера EEPROM может иметь объем от 512 байт (как, например, в микроконтроллере atmega16) до нескольких килобайт.
Гарантированное количество циклов перезаписи этой памяти составляет не меньше 100000.
В этой статье на примере atmega16 мы разберемся, как работать с этим типом памяти, какие возможные проблемы при этом могут возникать и как с ними бороться.
Объявление переменных в EEPROM
Использование EEPROM начинается с объявления переменных, хранящиеся в этой памяти. Синтаксис объявления таких переменных отличается от объявлений обычных переменных (хранящихся в ОЗУ) только наличием ключевого слова. В зависимости от компилятора данное ключевое слово может разным.
Объявление переменной в EEPROM для IAR AVR и CodeVision AVR://8-ми разрядная переменная__eeprom uint8_t setting_2//объявление массива 16-ти разрядных переменных __eeprom uint16_t set[8];//объявление массива и его инициализация__eeprom uint8_t data[3] = {11, 3, 13};//указатель на 8-ми разрядную переменную в EEPROM, который сам хранится в RAMuint8_t __eeprom * pSetting;//указатель на 8-ми разрядную переменную в EEPROM, который сам храниться в EEPROM__eeprom uint8_t __eeprom*pSetting;
Объявление переменной в EEPROM для AtmelStudio 6:
#include
//8-ми разрядная переменная в EEPROM
uint8_t setting EEMEM;//объявление массива в EEPROM
uint16_t set[8] EEMEM;//указатель на 8-ми разрядную переменную в EEPROM, который сам хранится в RAM
uint8_t *pSetting;//указатель на 8-ми разрядную переменную в EEPROM, который сам храниться в EEPROM
uint8_t *pSetting EEMEM;
Инициализация переменных в EEPROM
При объявлении переменных в EEPROM их можно инициализировать, то есть присвоить начальные значения.
//для IAR AVR, CodeVision AVR__eeprom uint8_t counter = 100;__eeprom uint16_t data[3] = {20, 08, 1981};//для AtmelStudio 6uint8_t counter EEMEM = 23;
uint8_t data[3] EEMEM = {21, 04, 1979};
Инициализацию переменных хранящихся в ОЗУ компилятор “запихивает” в начало программы микроконтроллера – перед вызовом функции main. И она выполняется каждый раз, когда на микроконтроллер подается питание или происходит его сброс.
С EEPROM переменными ситуация немного другая, их должен инициализировать сам пользователь путем программирования EEPROM специальным файлом (с расширением .eep).
Как сгенерировать файл для EEPROM? Если в коде есть инициализация EEPROM переменных, то AtmelStudio 6 и CodeVision AVR создадут этот файл автоматически. А вот в IAR`e для этого нужно прописывать линкеру команды. Делается это так.
Меню Project > Options…>Linker вкладка Output. Устанавливаем значения по умолчанию – галочка Override default снята, формат – Debug information for C-SPY. На вкладке Extra Options ставим галочку Use Command Options и в окошке ниже прописываем такие строчки:-Ointel-standard,(CODE)=.hex
-Ointel-standard,(XDATA)=.eep
После компиляции и сборки проекта IAR создаст файл прошивки – .hex и файл для EEPROM`a – .eep
Полученный eep файл записывается с помощью программатора в микроконтроллер.
Чтение и запись EEPROM
В IAR`e и CodeVision AVR использование EEPROM переменных по сути ничем не отличается от использования обычных переменных (хранящихся в ОЗУ и регистрах).
Вся работа по организации чтения и записи в эти EEPROM переменные выполняется компилятором.//для IAR AVR, CodeVision AVR__eeprom uint8_t data;…
//читаем из EEPROMuint8_t tmp = data;//записываем в EEPROM
data = 129;
В AtmelStudio для чтения/записи EEPROM переменных используются специальные макросы. Они определены в файле eeprom.h. Вот некоторые из них:
uint8_t eeprom_read_byte (const uint8_t *__p) – прочитать байт
uint16_t eeprom_read_word (const uint16_t *__p) – прочитать слово (2 байта)
uint32_t eeprom_read_dword (const uint32_t *__p) – прочитать двойное слово (4 байта)void eeprom_write_byte (uint8_t *__p, uint8_t __value) – запись байта
void eeprom_write_word (uint16_t *__p, uint16_t __value) – запись слова (2 байта)
void eeprom_write_dword (uint32_t *__p, uint32_t __value) – запись дв. слова (4 байта) Макросы принимают в качестве параметра адрес переменной размещенной в EEPROM. Для взятия адреса переменной используется оператор &. Примеры ниже поясняют использование этих макросов.
#include //объявляем переменные uint8_t data EEMEM;uint16_t pin_code EEMEM;…//читаем байт из eepromuint8_t tmp = eeprom_read_byte(&data);//записываем слово в eepromeeprom_write_word (&pin_code, 5327)
Заключение
Из этой статьи вы узнали:- как объявить переменную в EEPROM памяти,- как создать файл для инициализации EEPROM,- как прочитать и записать данные в EEPROM.
В следующей статье будут разобраны регистры, используемые для чтения и записи в EEPROM, а также низкоуровневая работа с этим типом памяти.
Источник: http://chipenable.ru/index.php/programming-avr/item/158
Работа с энергонезависимой памятью EEPROM
Кроме FLASH-памяти программ и оперативной памяти RAM в микроконтроллере есть другой вид памяти – EEPROM. В отличии от RAM-памяти данные в памяти EEPROM сохраняются даже после выключения питания.
Аббревиатура EEPROM расшифровывается как Electrically Erasable Read-Only Memory (электрически стираемая память ПЗУ).
В микроконтроллерах AVR серии Classic для работы с памятью EEPROM достаточно трёх управляющих регистров:
EEAR – регистр, содержащий адрес по которому будет чтение или запись в EEPROMEEDR – регистр с данными, которые либо считываем из памяти EEPROM, либо записываемEECR – регистр управленияРассмотрим работу с памятью EEPROM на основе микроконтроллера AVR ATmega8. У данного микроконтроллера 512 байт энергонезависимой памяти. И что стоит отметить количество циклов запись/стирание ограничено 100.000 (это минимальное количество, гарантированное производителем – компанией ATMEL) для каждой ячейки памяти.
Для адресации используется два регистра EEARH и EEARL т.к. для адресации 512 байт памяти необходимо 9 бит. Младшие 8 бит адресуемой ячейки хранятся в регистре EEARL, а старший 9-й бит храниться во младшем бите регистра EEARH. На иллюстрации показано распределение бит:
Регистр EEDR – обычный восьмибитный в котором находится результат при чтении из памяти или в который заносится значение при записи в EEPROM.
Рассмотрим управляющий регистр EECR:
биты [7:4] – не используютсябит EERIE [3] – EEPROM Ready Interrupt Enable или разрешение прерывания при обнулении бита EEWE (что происходит после окончания записи).бит EEMWE [2] – EEPROM Master Write Enable – необходимо установить этот бит в “1” и в течении 4х тактов дать команду на запись – установив бит EEWE в “1”. Этот бит аппаратно сбрасывается в “0” после 4 тактов.бит EEWE [1] – EEPROM Write Enable – бит, разрешающий запись в память (при условии, что бит EEMWE установлен).бит EERE [0] – EEPROM Read Enable – при установке соответствующего адреса ячейки, которую будем считывать, данный бит запускает процесс чтения.
Что стоит помнить при работе с энергонезависимой памятью EEPROM:
1. Она довольно медленная, по даташиту на микроконтроллер AVR ATmega8 (читай все микроконтроллеры AVR серии classic) среднее время записи в память составляет порядка 8,5 мс.
2. Возможно повреждение данных в памяти при включении/выключении питания микроконтроллера. А именно при нарастании напряжения, ядро начинает работать и выполнять код, например запись в EEPROM.
Если эта команда начнет выполняться при “недостаточном”, для корректной работы памяти, напряжении, то данные будут утеряны. Для минимизации таких неприятных возможностей следует использовать BOD – Brown-Out Detection.
Это аппаратный блок микроконтроллера, задающее минимальное рабочее напряжение питания при котором микроконтроллер начинает работать.
3. Отслеживать количество циклов запись/стирание для предотвращения выхода ячеек из строя т.к. есть теоретическое ограничение на 100.000 обращений к каждой ячейки памяти.
Рассмотрим простой пример программы на ассемблере AVR Studio:
.include “m8def.inc” .def wreg =R16 ldi wreg, 0b10100000
out MCUCR, wreg ldi wreg, 0x00 main: out EEARL, wreg ; запись адреса, есть еще EEARH
out EEDR, wreg ; данные
sbi EECR, EEMWE
sbi EECR, EEWE sbic EECR, EEWE ; проверка окончания записи
rjmp PC-1 inc wreg ; инкрементируем регистр
cpi wreg, 0x05 ; сравниваем значение с константой 0x05 breq PC+2 ; перепрыгиваем через след. команду
; если равенство выполняется т.е. wreg = 0x05 rjmp main
sleep
Просимулируйте работу программы в AVR Studio. Запуск симуляции – CTRL + F7. Для просмотра содержимого памяти нажмите ALT + 4 и в выпадающем списке в левом верхнем углу выберите EEPROM.
В результате работы данной программы в памяти EEPROM будут следующие данные:
Всё верно, так и должно быть – сначала данные в ячейке wreg являлись и адресом ячейки и значением, которое записывалось в ячейку. Ячейка инкрементировалась, и как только значение в этой ячейке стало равно 0x05, выполнилась команда PC+2 – “перескок” через следующую команду (“перескок” через команду rjmp main).
Скачать исходник данной программы для микроконтроллера AVR ATmega8
Вопросы задавайте на форуме.
Источник: http://radioded.ru/samouchitel-avr-studio/rabota-s-energonezavisimoy-pamyatiu-eeprom
Устройство микроконтроллера: АЛУ и организация памяти
Процессорное ядро микроконтроллеров:
– арифметико-логическое устройство
– организация памяти
Доброго дня уважаемые радиолюбители!
Приветствую вас на сайте “Радиолюбитель“
Сегодня (точнее – в течении нескольких статей) мы с вами более подробно рассмотрим основу любого микроконтроллера – процессорное ядро.
Основные элементы:
1. Арифметико-логическое устройство
АЛУ – сердце (а может быть и ум, с честью и совестью) микроконтроллера.
Здесь мы не будем входить в роль “маньяка-расчленителя” и ковыряться во внутренностях этого устройства.
Усвоим только, что благодаря АЛУ происходит вся работа микроконтроллера.
Если у вас когда-нибудь появится желание более глубже узнать как работает “сердце” микроконтроллера (а будет неплохо, если оно появится), то в книгах замечательных авторов Белова, Рюмика, Евстифеева, Ревича, Баранова и многих других, вы всегда найдете подробный ответ.
2. Память микроконтроллера (организация памяти)
Прежде чем рассматривать память микроконтроллера, немного поговорим о памяти вообще.
Человеческая память – с ней все понятно, – она бывает “твердой” (когда находишься в твердой памяти, а иногда еще и в здравом уме) и, как не прискорбно, – “дырявой”.
А вся информация хранится в так называемых “нейронах” – маленьких ячейках памяти.
У микроконтроллеров почти все также.
Только, если у человека самая маленькая ячейка для хранения информации называется “нейрон”, то для микроконтроллера самая маленькая ячейка памяти для хранения информации называется “бит“.
В одном бите может храниться или одна логическая единица, или один логический ноль.
Бит – минимальная единица измерения объема памяти в микропроцессорной технике.
Следующая основная, или самая распространенная, единица измерения памяти – байт.
Байт – это восемь бит информации.
В одном байте может храниться только восемь нулей и единиц. Максимальное число которое можно записать в байт – 255.
Если в программе вы будете оперировать большими числами то следует знать (чтобы знать сколько байт потребуется для хранения числа), что максимальное число, которое можно записать в: – один байт = 255 – два байта = 65 535 – три байта = 16 777 215 – четыре байта – число величиной более 4 миллиардов (если вы не входите хотя бы в сотню журнала “Форбс”, то четыре байта памяти для хранения чисел вам не понадобятся). Запись в память и чтение из памяти происходит байтами (нельзя записать или считать один бит информации).
Следующая единица измерения – килобайт.
В килобайте помещается 1024 байт информации (именно 1024, а не 1000 байт). Есть еще и большие величины измерения объема памяти (мегабайт, гигабайт), но в микроконтроллерах они пока не применяются.
Я надеюсь, что с единицами измерения электронной памяти нам все понятно:
Организация памяти в микроконтроллере
Микросхемы AVR имеют три вида памяти:
– память программ, она же FLASH-память
– память данных, она же ОЗУ (оперативно-запоминающее устройство), она же SRAM
– энергонезависимая память, она же ЭСППЗУ, она же EEPROM
В микроконтроллере выделяется три адресных пространства в которых располагаются вышеперечисленные разновидности памяти. Память данных при этом (в смысле выделенного адресного пространства) оказалась немного обделенной – ей приходится делить свое адресное пространство с ячейками памяти в которых хранятся регистры общего назначения и регистры ввода/вывода (о них вы подробно узнаете в следующей статье). Эти регистры физически не относятся к памяти данных, но находятся в том же адресном пространстве. Если начальные адреса памяти программ и энергонезависимой памяти начинаются с нулевого адреса, то начальный адрес памяти данных не начинается с нулевого адреса – с нулевого адреса занимают места регистры общего назначения и регистры ввода/вывода, и только за ними следуют адреса ячеек памяти программ.
В некоторых видах МК ATiny память данных отсутствует.
Память программ (FLASH память)
Память программ предназначена для хранения в ней наших программ, а также любых нужных нам данных, которые не меняются в ходе выполнения программы (константы). При выключении питания микроконтроллера, все данные в памяти программ сохраняются.
Память программ, естественно, имеют все микроконтроллеры.
Размер памяти программ, в зависимости от типа МК, варьируется от 1 килобайта до 256 килобайт.
Доступ к памяти программ имеет только программист при программировании МК, у самого МК доступ к памяти программ тоже имеется, но только для чтения данных из памяти, записать туда он ничего не может (мало ли что, вдруг захочет испортить нашу программу).
Правда, у МК семейства Mega есть возможность (с разрешения программиста) вносить изменения в памяти программ, но это отдельная история.
Для памяти программ есть еще два вида измерения объема памяти – “слово” и “страница“.
Дело в том, что память программ состоит из ячеек состоящих из двух байт. Такая ячейка называется “словом”. А сделано это так потому, что почти все команды МК состоят из двух байт, и, соответственно, для их записи нужно два байта в памяти программ. Каждая команда МК – это одно “слово”.
Есть несколько команд, для записи которых требуется 4 байта в памяти – два слова, но такие команды встречаются в МК у которых память программ больше 8 килобайт.
Таким образом, в одну ячейку памяти программ можно записать:
– любую команду, состоящую из двух байт
– половину команды, состоящей из 4 байт
– две константы, каждая из которых умещается в один байт, или одну шестнадцатиразрядную константу.
При этом, если вы записываете в память три однобайтовых константы, они все равно займут в памяти четыре байта (два слова).
Кроме того, запись в память программ осуществляется не только “словами”, но еще и “страницами”. Размер “страницы” составляет от 64 до 256 байт (чем больше объем памяти программ, тем больше объем “страницы”). Что это значит. Если вы создали маленькую программку, объем которой составляет 11 слов (22 байта), в памяти программ она все равно займет место в одну страницу, т.е. как минимум 64 байта. “Лишние” 42 байта при этом будут заполнены или нулями, или единицами. Вот такие вот, пироги. Но и это еще не все.
Память программ может иметь три состояния (если можно так выразиться):
1. Вся память находится в распоряжение программиста
В этом случае мы можем забить всю память полностью своей программой и данными. А программа будет стартовать с нулевого адреса памяти.
2. Часть памяти забирает МК
В случае, если при работе МК используются прерывания (а я надеюсь – вы помните, что это такое), часть памяти МК забирает для нужд обработки прерываний и хранит в ней “векторы прерываний“.
Что это такое.
Когда мы разрешаем МК обрабатывать прерывания, он, начиная с нулевого адреса памяти, забирает часть ячеек для хранения в них адресов, по которым надо перейти МК для выполнения подпрограммы прерывания. Для каждого прерывания МК выделяет два байта памяти (одно слово) в которых хранятся адреса подпрограмм обработки прерываний. Вот эти адреса, которые указывают где находится в памяти подпрограмма обработки того, или иного прерывания, называются “векторами прерываний“. А вся область памяти, в которой хранятся “векторы прерываний”, называется таблицей векторов прерываний. Количество занятых ячеек памяти под прерывания зависит напрямую от количества возможных прерываний данного микроконтроллера (от нескольких штук, до нескольких десятков). Все прерывания располагаются в начале памяти программ, с нулевого адреса, и имеют четкую последовательность. По нулевому адресу всегда располагается вектор прерывания по “сбросу” (Reset). Когда мы включаем устройство, или производим сброс кнопкой, срабатывает прерывание по сбросу. МК считывает с нулевого адреса (с ячейки) адрес, который указывает где в памяти находится начало нашей программы, и перейдя по этому адресу начинает выполнять программу. Сама программа в этом случае будет располагаться в памяти программ сразу за таблицей прерываний.
3. МК забирает еще одну часть памяти программ (точнее не забирает, а выделяет область в конце памяти, в которой программист размещает специальную программу – “загрузчик”).
Такое возможно в МК семейства “MEGA”, у которых есть возможность разрешить МК вносить изменения в памяти программ. Что это значит.
Некоторые МК имеют возможность самопрограммироваться. В практике любителей такая возможность МК используется крайне редко. Возможность перепрограммироваться (самопрограммироваться) нужна, в основном, в случаях промышленного производства какого-то устройства на микроконтроллере, для которого потом может выпускаться обновление программного обеспечения. Мы эту возможность рассматривать не будем, по крайней мере пока. Нам достаточно только знать, что в МК, которые поддерживают самопрограммирование, память программ разделяется на две части:
– верхняя – секция прикладной программы, где располагается наша программа и векторы прерываний
– нижняя – секция загрузчика (Boot Loader Section – по английски), где программист располагает свою программу-загрузчик. Размер секции загрузчика зависит от общего размера памяти программ МК, и может составлять от 128 байт до 4096 байт. Если возможность самопрограммирования МК мы не используем, то эта секция отдается для нашей программы и данных.
Ну а FLASH-памятью память программ называют потому, что она делается по так называемой Flash-технологии (как и всем нам привычные компьютерные “флешки”)
Память программ допускает 10 тысяч циклов перепрограммирования.
Память данных (Статическое ОЗУ, SRAM)
Оперативно-запоминающее устройство, оно же память данных типа SRAM, предназначена для хранения в ней различных данных, получаемых в результате работы программы.
При выключении питания микроконтроллера, все данные хранящиеся в ней теряются.
Память данных есть почти во всех микроконтроллерах (отсутствует у простейших МК семейства Tiny).
Во всех МК семейства Mega (и части МК семейства Tiny) объем встроенной памяти данных колеблется от 128 байт до 8 килобайт, и почти вся она отдана в наше полное распоряжение.
Только немножко забирает себе МК для организации стека (что это такое узнаем позднее). В некоторых МК предусмотрено подключение внешней памяти (она может быть любого типа – FLASH, SRAM, EEPROM) объемом до 64 килобайт. В случае подключения внешней памяти в таких МК, она становится как-бы продолжением памяти данных.
Запись в память данных и чтение из нее происходит побайтно, и в отличии от памяти программ в ней нет деления на страницы и слова.
Энергонезависимая память (EEPROM)
Энергонезависимая память также относится к памяти данных, но в отличие от последней имеет несколько особенностей. Предназначена она для хранения данных и констант, которые должны сохраняться при отсутствии питания.
EEPROM имеют все микроконтроллеры.
При выключении питания микроконтроллера все данные, хранящиеся в энергонезависимой памяти сохраняются (поэтому она и называется энергонезависимой).
Объем энергонезависимой памяти, в зависимости от типа МК, колеблется от 64 байт до 4 килобайт.
Запись и чтение информации в память производится побайтно. Однако в старших моделях семейства MEGA, энергонезависимая память, так же как и память программ, имеет страничную запись. Объем страницы небольшой, составляет всего 4 байта.
На практике эта особенность не имеет значения – и запись, и чтение осуществляется все равно побайтно.
Число циклов записи и стирания памяти достигает 100 000.
Главная особенность EEPROM заключается в том, что при записи в нее данных она становится очень “медленной” – запись одного байта может продолжаться от 2 до 4 миллисекунд (это очень низкая скорость), и может случиться, к примеру, что во время записи сработает какое-либо прерывание и в этом случае процесс записи данных будет загублен.
Кроме того, не рекомендуется записывать данные в энергонезависимую память с нулевого адреса (не помню источника этих сведений, но точно помню, что где-то читал) – возможно повреждение данных в ходе работы МК. Иногда программисты отступают на несколько байт от начала памяти, и только в следующих ячейках начинают запись данных.
Предыдущие статьи:
♦ Микроконтроллер и как его победить
♦ Микроконтроллер и системы счисления
♦ Микроконтроллер и логические операции
♦ Общее устройство микроконтроллера
Следующие статьи:
♦ Регистры общего назначения, регистры ввода/вывода, стек, счетчик команд
♦ Регистр состояния SREG
♦ Порты ввода/вывода микроконтроллера
Источник: http://radio-stv.ru/mikrokontrolleri/ustroystvo-i-programmirovanie-mikrokontrollerov-dlya-nachinayushhih/ustroystvo-mikrokontrollera-alu-i-organizatsiya-pamyati
Внешняя память EEPROM серии 24cXX и микроконтроллер AVR
В некоторых конструкция, более интересных и сложных, необходимо сохранять переменные на время отключения питания, или вести журнал изменения переменной (например если устройство предназначено для отслеживания изменения температуры на протяжении суток).
Для этих целей необходимо иметь хранилище данных не зависимое от питания устройства, то есть энергонезависимое. Например для хранения нескольких переменных, таких как например последнее значение температуры перед отключением питания, или пароль кодового замка необходимо всего несколько байт памяти.
Для таких задач вполне хватает штатной, встроенной в микроконтроллер энергонезависимой памяти. А что делать если необходимо сохранить несколько килобайт данных.
Или записать небольшой файл в память устройства, или просто устройству не хватает например памяти для хранения текста, выводимого потом на экран. Как пример анимация в виде серии картинок (кадров) для вывода на дисплей NOKIA 3310, картинки занимают очень много памяти, они просто не влезут в память микроконтроллера.
Решить задачу поможет микросхема внешней памяти EEPROM. EEPROM – (Electrically Erasable Programmable Read-Only Memory) что значит Программируемая Память с Электрическим Стиранием.
То есть такие микросхемы предназначены для хранения данных без внешних источников питания. Им не страшно отключение питания. Их легко можно стереть, выполнив определенную команду. Данные микросхемы работают по протоколу I2C что подразумевает высокую скорость работы.
Организация пами Микросхемы EEPROM представляют из себя таблицу с двумя столбиками, 1-й – адрес, 2-й – значение.
Адрес | Данные |
0000 | L |
0001 | 1 |
0002 | 3 |
0003 | f |
… | … |
n | x |
Адрес ограничивается только номиналом микросхемы EEPROM. Номиналы микросхем бывают:
24c02, 24c08, 24c16, 24c32, 24c64, 24c128, 24c256, 24c512 изредка но можно найти.
Все микросхемы серии абсолютный аналог друг-друга.
Значение поля “Данные” ограничивается пределами типа данных int, то есть от -32767 до 32767. Данные лучше всего записывать в шестнадцатиричной системе, то есть: в десятичной системе число “35” будет соответствовать значению “0x23” в шестнадцатиричной.
От себя:
Для записи например значения температуры лучше всего использовать несколько ячеек памяти.
Так например температуру +37,5 лучше всего разбить на три ячейки:
1. знак температуры (+/-)
2. температура до запятой (37)
3. температура после запятой (5)
Запятую в таком случаи необходимо будет устанавливать программно для вывода значения температуры напрмиер на дисплей, после первых трех символов значения.
Микросхемы EEPROM выпускаются как в корпусах типа DIP так и корпусах для поверхностного монтажа SOIC. Если к устройству нет определенных жестких требований по части корпуса, то можно использовать и DIP корпус, разницы нет.
Обычно микросхемы серии 24cХХ отличаются лишь объемом внутренней памяти.
Рассмотрим пример программы для работы с одной из этих микросхем. Программа ориентирована на работу микроконтроллера ATmega8 и микросхемы внешней EEPROM 24c64, схема подключения 24c64 к микроконтроллеру ATmega8 показана на рис. 1Рис. 1
Содержание файла 24c64.c, файл содержит набор подпрограмм для работы с внешней EEPROM памятью по шине I2C(по сути в данном коде не чистый I2C а программный посредством интерфейса TWI).
-
#include “24c64.h”
-
void EEOpen()
-
{ //Конфигурация TWI модуля
-
TWBR = 5;
-
TWSR &= (~((1
Источник: https://avrlab.com/node/84
EPROM, EEPROM и flash-память
На заре возникновения памяти, сохраняющей данные при отключении питания (EPROM, Erasable Programmable ROM — «стираемая/программируемая ROM», или по-русски ППЗУ — «программируемое ПЗУ»), основным типом ее была память, стираемая ультрафиолетом: UV-EPROM (Ultra-Violet EPROM, УФ-ППЗУ).
Причем часто приставку UV опускали, так как всем было понятно, что EPROM — это стираемая ультрафиолетом, а ROM (или ПЗУ) просто, без добавлений— это однократно программируемые кристаллы OTP-ROM. Микроконтроллеры с УФ-памятью программ были распространены еще в середине 1990-х.
В рабочих образцах устройств с УФ-памятью кварцевое окошечко, через которое осуществлялось стирание, заклеивали кусочком черной липкой ленты, так как информация в UV-EPROM медленно разрушается и на солнечном свету.
Рис. 18.7. Устройство элементарной ячейки EPROM
На рис. 18.7 показано устройство элементарной ячейки EPROM, которая лежит в основе всех современных типов flash-памяти. Если исключить из нее то, что обозначено надписью «плавающий затвор», мы получим самый обычный полевой транзистор — точно такой же входит в ячейку DRAM.
Если подать на управляющий затвор такого транзистора положительное напряжение, то он откроется, и через него потечет ток (это считается состоянием логической единицы). На рис. 18.
7 вверху-и изображен такой случай, когда плавающий затвор не оказывает никакого влияния на работу ячейки — например, такое состояние характерно для чистой flash-памяти, в которую еще ни разу ничего не записывали.
Если же мы каким-то образом (каким— поговорим отдельно) ухитримся разместить на плавающем затворе некоторое количество зарядов — свободных электронов, которые показаны на рис. 18.7 внизу в виде темных кружочков со значком минуса, то они будуу экранировать действие управляющего электрода, и такой транзистор вообще перестанет проводить ток. Это состояние логического нуля.
Поскольку плавающий затвор потому так и называется, что он «плавает» в толще изолятора (двуокиси кремния), то сообщенные ему однажды заряды в покое никуда деваться не могут.
И записанная таким образом информация может храниться десятилетиями (до последнего времени производители обычно давали гарантию на 10 лет, но на практике в обычных условиях время хранения значительно больше).
Заметки на полях
Строго говоря, в NAND-чипах (о которых далее) логика обязана быть обратной. Если в обычной EPROM запрограммированную ячейку вы не можете открыть подачей считывающего напряжения, то там наоборот — ее нельзя запереть снятием напряжения. Поэтому, в частности, чистая NAND-память выдает все нули, а не единицы, как EPROM. Но это нюансы, которые не меняют суть дела.
Octajiocb всего ничего — придумать, как размещать заряды на изолированном от всех внешних влияний плавающем затворе. И не только размещать — ведь иногда память и стирать приходится, потому должен существовать способ их извлекать оттуда.
В UV-EPROM слой окисла между плавающим затвором и подложкой был достаточно толстым (если величину 50 нанометров можно охарактеризовать словом «толстый», конечно), и работало все это довольно грубо.
При записи на управляющий затвор подавали достаточно высокое положительное напряжение — иногда до 36—40 В, а на сток транзистора — небольшое положительное.
При этом электроны, которые двигались от истока к стоку, настолько ускорялись полем управляющего электрода, что просто перепрыгивали барьер в виде изолятора между подложкой и плавающим затвором. Такой процесс называется еще «инжекцией горячих электронов».
Ток заряда при этом достигал миллиампера — можете себе представить, каково было потребление всей схемы, если в ней одновременно программировать хотя бы несколько тысяч ячеек.
И хотя такой ток требовался на достаточно короткое время (впрочем, с точки зрения быстродействия схемы не такое уж и короткое — миллисекунды), но это было крупнейшим недостатком всех старых образцов EPROM-памяти.
Еще хуже другое — и изолятор, и сам плавающий затвор такого издевательства долго не выдерживали и постепенно деградировали, отчего количество циклов стирания-записи было ограничено нескольким сотнями, максимум— тысячами.
Во многих образцах flash-памяти более позднего времени даже была предусмотрена специальная схема для хранения карты «битых» ячеек — в точности так, как это делается для жестких дисков. В современных моделях с миллионами ячеек такая карта тоже имеется — однако число циклов стирания/записи теперь возросло до сотен тысяч. Как этого удалось добиться?
Рис. 18.8. Процесс стирания в элементарной ячейке EPROM
Сначала посмотрим, как осуществлялось в этой схеме стирание. В UV-EPROM при облучении ультрафиолетом фотоны высокой энергии сообщали электронам на плавающем затэоре достаточный импульс для того, чтобы они «прыгали» обратно на подложку самостоятельно, без каких-либо электрических воздействий.
Первые образцы электрически стираемой памяти (EEPROM, Electrically Erasable Programmable ROM — «электрически стираемое перепрограммируемое ПЗУ», ЭСППЗУ) были созданы в компании Intel в. конце 1970-х при непосредственном участии будущего основателя Atmel Джорджа Перлегоса. Он использовал «квантовый эффект туннелирования Фаулера-Нордхейма».
За этим непонятным названием кроется довольно простое по сути (но очень сложное с физической точки зрения) явление: при достаточно тонкой пленке изолятора (ее толщину пришлось уменьшить с 50 до 10 нм) электроны, если их слегка подтолкнуть подачей не слишком высокого напряжения в нужном направлении, могут просачиваться через барьер, не перепрыгивая его.
Сам процесс показан на рис. 18.8 вверху (обратите внимание на знак напряжения на управляющем электроде).
Старые образцы EEPROM именно так и работали: запись производилась «горячей инжекцией», а стирание — «квантовым туннелированием». Оттого они были довольно сложны в эксплуатации — разработчики со стажем помнят, что первые микросхемы EEPROM требовали два, а то и три питающих напряжения, причем подавать их при записи и стирании требовалось в определенной последовательности.
Превращение EEPROM во flash происходило по трем разным направлениям. В первую очередь — в направлении совершенствования конструкции самой ячейки. Для начала избавились от самой противной стадии — «горячей ин-жекции».
Вместо нее при записи стали также использовать «квантовое тун-нелирование», как и при стирании. рис. 18.
8 внизу показан этот процесс— если при открытом транзисторе подать на управляющий затвор достаточно высокое (но значительно меньшее, чем при «горячей инжекции») напряжение, то часть электронов, двигающихся через открытый транзистор от истока к стоку, «просочится» через изолятор и окажется на плавающем затворе. Потребление тока при записи снизилось на несколько порядков. Изолятор, правда, пришлось сделать еще тоньше, что обусловило довольно большие трудности с внедрением этой технологии в производство.
Второе направление — ячейку сделали несколько сложнее, пристроив к ней второй транзистор (обычный, не двухзатворный), который разделил вывод стока и считывающую шину всей микросхемы.
Благодаря всему этому удалось добиться значительного повышения долговечности — до сотен тысяч циклов записи/стирания (миллионы циклов, характерные для флэш-карточек, получаются, если добавить схемы коррекции ошибок).
Кроме того, схемы формирования высокого напряжения и соответствующие генераторы импульсов записи/стирания перенесли внутрь микросхемы, отчего пользоваться этими типами памяти стало несравненно удобнее — они стали питаться от одного напряжения (5, 3,3 или даже 1,8 В).
И, наконец, третье, едва ли не самое главное усовершенствование заключалось в изменении организации доступа к ячейкам на кристалле, вследствие чего этот тип памяти и заслужил наименование — flash (то есть «молния»), ныне известное каждому владельцу цифровой камеры или карманного МРЗ-плеера.
Так в середине 1980-х назвали разновидность EEPROM, в которой стирание и запись производились сразу целыми блоками — страницами. Процедура чтения из произвольной ячейки, впрочем, по понятным причинам замедлилась— для его ускорения приходится на кристаллах flash-памяти располагать промежуточную (буферную) SRAM.
Для флэш-накопителей это не имеет особого значения, так как там все равно данные читаются и пишутся сразу большими массивами, но для использования в микроконтроллерах это может оказаться неудобным. Тем более, в МК неудобно использовать самый быстродействующий вариант flash-технологии — т. н.
память типа NAND (от наименования логической функции «И-НЕ»), где читать и записывать память в принципе возможно только блоками по 512 байт (это обычная величина сектора на жестком диске, также читаемого и записываемого целиком за один раз — отсюда можно понять основное назначение NAND).
В МК обычно используют традиционную (типа NOR) flash-память программ, в которой страницы относительно невелики по размерам — порядка 64—256 байт. Впрочем, если пользователь сам не берется за создание программатора для такой микросхемы, он может о страничном характере памяти и не догадываться.
А для пользовательских данных применяют EEPROM либо с возможностью чтения произвольного байта, либо секционированную, но на очень маленькие блоки — например, по 4 байта. При этом для пользователя все равно доступ остается побайтным.
Характерной чертой такой памяти является довольно медленная (порядка миллисекунд) процедура записи, в то время как чтение протекает ничуть не медленнее любых других операций в МК.
Развитие технологий flash-памяти имело огромное значения для удешевления и доступности микроконтроллеров. В дальнейшем мы будем иметь дело с энергонезависимой памятью не только в виде встроенных в микроконтроллер памяти программ и данных, но и с отдельными микросхемами, позволяющими записывать довольно большие объемы информации.
Источник: http://nauchebe.net/2010/06/eprom-eeprom-i-flash-pamyat/
Работа с EEPROM в AVR-GCC
Перевод очень хорошей статьи от Dean Camera на русский язык. В ней содержатся пояснения о самой EEPROM, работа с встроенной библиотекой eeprom.h, приведены примеры для записичтения byte, word и block, работа с EEMEM.
В статье рассматривается компилятор AVR-GCC. Это больше адаптация, нежели перевод. Часть текста я выкинул, посчитав лишним, где-то добавил от себя. Статья рассчитана на тех, кто не работал с EEPROM и хочет на простых примерах научиться с ним работать.
Что такое память EEPROM?
Большинство МК AVR от Atmel содержат EEPROM (Electronically Erasable Read-Only Memory) — энергонезависимую память с довольно большим количеством циклов записи.
Данные, записанные в эту память, не будут сбрасываться даже при отключении питания, что очень удобно, например, для хранения настроек или каких-то идентификационных данных. EEPROM в AVR имеет ограниченное количество циклов записи — 100 000.
Количество циклов чтения не ограничено.
Как осуществляется доступ?
Доступ к EEPROM в AVR можно получить с помощью специальных регистров, которые отвечают за адрес, информацию для записи (или прочитанную информацию) и совершаемое действие (запись/чтение).
В языке C нет каких-либо стандартов доступа или адресации памяти (не считая Flat Model для SRAM). Поэтому каждый компилятор использует свой метод хранения информации в памяти. Мы будем рассматривать компилятор AVR GCC.
Использование библиотеки AVRLibC EEPROM
AVRLibC (обычно она входит в состав компилятора AVR-GCC) содержит готовую библиотеку для работы с EEPROM. Чтобы ее использовать, нужно добавить следующий заголовочный файл:#include В этой библиотеке три основных типа данных: byte (1 байт), word (2 байта) и блок данных. В новых версиях добавлены еще два типа – dword (4 байта) и float (8 байт). Их мы рассматривать не будем — работа с ними идентична работе с byte word типами. Для каждого типа есть своя функция записи и чтения. Вот они:// Читаем пишем по одному байту (byte) uint8_t eeprom_read_byte (const uint8_t *addr) void eeprom_write_byte (uint8_t *addr, uint8_t value) // Читаем пишем по два байта (word) uint16_t eeprom_read_word (const uint16_t *addr) void eeprom_write_word (uint16_t *addr, uint16_t value) // Читаем пишем блоками void eeprom_read_block (void *pointer_ram, const void *pointer_eeprom, size_t n) void eeprom_write_block (const void *pointer_ram, void *pointer_eeprom, size_t n)
Чтение byte word
Для начала, попробуем написать программу, считывающую 1 байт из EEPROM – например, по адресу 46.#include void main(void) { uint8_t ByteOfData; ByteOfData = eeprom_read_byte((uint8_t*)46); } Здесь мы считываем байт данных по адресу 46 из EEPROM и записываем в переменную «ByteOfData».
Объявляем переменную размером 1 байт, потом вызываем функцию eeprom_read_byte, которой в качестве параметра передаем указатель на байт в EEPROM. Word-тип записывается и читается так же, за исключением того, что функции нужен указатель на int.
#include void main(void) { uint16_t WordOfData; WordOfData = eeprom_read_word((uint16_t*)46); }
Работа в блоками данных в EEPROM
А что, если Вы хотите записать больше 2 байт информации? Неудобно будет делить их на кусочки по два байта… Для этого придумали блоки данных. Функции доступа к блокам отличаются от остальных функций чтениязаписи. Обе функции ничего не возвращают и работают с переменными, переданными в качестве параметра.
Давайте взглянем на объявление функции чтения:void eeprom_read_block (void *pointer_ram, const void *pointer_eeprom, size_t n)Выглядит сложно! Но на практике это не так. Она использует элементы, с которыми Вы, возможно, не знакомы – указатели на void. Обычные указатели ссылаются на определенный тип данных.
Например, “uint8_t*” указывает на unsigned char, а “int16_t*” – на signed int. Но ведь void – это не тип данных, что же это значит? Указатели на void полезны с случае, когда тип данных неизвестен или не важен. Указатель на void указывает на адрес в памяти, где хранится информация, и не важно, какого она типа.
Именно поэтому функции для работы с блоками данных используют их. Ей не важен тип, она просто копирует нужное количество байт. Вернемся к нашим функциям. В качестве параметров нужно передавать: void-указатель на адрес в RAM, void-указатель на адрес в EEPROM и количество байт.
Для начала, попробуем прочесть 10 байт из EEPROM, начинающиеся с адреса 12, в строку.#include void main(void) { uint8_t StringOfData[10]; eeprom_read_block((void*)&StringOfData, (const void*)12, 10); } Все еще выглядит сложно? Давайте пройдемся по каждому аргументу отдельно: • (void*)&StringOfData – это указатель на RAM.
Функция записывает прочитанные данные сюда. Он имеет тип unit8_t, поэтому добавляем явное преобразование – (void*) • (const void*)12 – это указатель на EEPROM. Функция чтения его не изменяет. Мы используем постоянный адрес (константу), поэтому преобразуем его к const void* • 10 – количество байт, которое мы читаем.
Функцию записи надо использовать так же, только первым аргументом посылаем данные, которые хотим записать, а вторым – место в EEPROM, куда данные будут записаны.
Использование EEMEM
Теперь Вы знаете, как читать и писать данные в EEPROM по фиксированному адресу. Но это не всегда удобно. В больших программах использование фиксированных адресов может привести к путанице, и часть данных может потеряться. Для таких случаев есть EEMEM.
Объявленный в той же библиотеке, макрос EEMEM указывает компилятору, что Вы хотите разместить переменную не в SRAM, а в EEPROM.
К примеру, создадим несколько таких переменных:#include uint8_t EEMEM NonVolatileChar; uint16_t EEMEM NonVolatileInt; uint8_t EEMEM NonVolatileString[10];Использовать их напрямую (var=value;) нельзя! Грубо говоря, эти переменные содержат адреса, автоматически выделенные компилятором.
В примере выше, NonVolatileChar будет хранится по адресу 0, NonVolatileInt – по адресу 1..2, а NonVolatileString[10] – 3..12. Для корректной работы нужно подставлять их в функции, рассмотренные выше.
Приведем пример чтения трех переменных (byte, int и block) из EEPROM в обычные переменные (SRAM):#include uint8_t EEMEM NonVolatileChar; uint16_t EEMEM NonVolatileInt; uint8_t EEMEM NonVolatileString[10]; void main(void) { uint8_t SRAMchar; uint16_t SRAMint; uint8_t SRAMstring; SRAMchar = eeprom_read_byte(&NonVolatileChar); SRAMint = eeprom_read_word(&NonVolatileInt); eeprom_read_block((void*)&SRAMstring, (const void*)&NonVolatileString, 10); }
Установка значений по умолчанию
Источник: http://robocraft.ru/blog/3043.html