Урок 15
Часть 1
Внутренняя энергонезависимая память EEPROM
Я думаю, может не все, но очень многие знают, что в контроллерах AVR помимо основной оперативной памяти, а также памяти для хранения прошивки существует ещё и энергонезависимая память типа EEPROM. Данная память сделана по технологии электрического стирания информации, что в отличие от её предшественника EPROM, в котором стирание производилось только при помощи ультрафиолетовых лучей, позволило использовать данный тип памяти практически повсеместно. Как мы знаем, ещё существует энергонезависимая память типа Flesh, которая стоит намного дешевле, но у которой также есть существенный минус. Там невозможно стереть отдельный байт, стирание производится только блоками, что не совсем удобно в некоторых случаях, особенно когда информации требуется хранить немного, и информация данная представляет собой небольшие настроечные параметры. Поэтому нам стоит также остановиться на данном типе памяти. И причем не только из-за того, что он присутствует в контроллере, а из-за того, что это очень удобно для хранения некоторых величин, которые нужны нам будут даже после того, как контроллер потерял питание.
Так как мы работаем с контроллером Atmega8A, техническую документацию данного МК мы и откроем и увидим там, что всего такой памяти у нас 512 байт. Это тем не менее не так мало. Если мы, например будем какой-нибудь будильник программировать, чтобы данные установки не потерялись после отключения питания, мы вполне можем с вами обратиться к данной памяти. Также в документации написано, что данная память гарантированно переживёт 100000 циклов записи/считывания.
Теперь напрашивается вопрос. Как же организован процесс работы с данной памятью в микроконтроллере AVR? Как всегда, компания Atmel об этом позаботилась и организовала данный процесс на аппаратном уровне, что очень радует потому, что нам постоянно приходится беречь ресурсы контроллера. Для управления данным аппаратным уровнем существуют определенные регистры.
Один из них — регистровая пара EEAR. Почему пара, а потому что 512 адресов не влезут в 8 бит, требуется ещё один
Как именно мы будем адресоваться, мы увидим в процессе программирования EEPROM.
Следующий — регистр данных EADR
В данный регистр мы будем записывать данные для того чтобы записать их в определённый адрес памяти EEPROM, а также чтобы считать их из определённого адреса той же самой памяти.
Ну и как водится, практически ни одна периферия и технология, организованная на аппаратном уровне, не обходится без управляющего регистра. У нас управляющим регистром является регистр EECR
Давайте сразу немного познакомимся с битами данного регистра.
Бит EERE — бит, заставляющий начать процесс чтения из памяти EEPROM. И, как только данные считались и записались в регистр данных, этот бит сбросится. Поэтому мы можем считать даннй бит не только управляющим, но и статусным или битом состояния.
Бит EEWE — бит, установка которого даёт команду контроллеру записать данные из регистра данных в определенный адрес EEPROM. После завершения процедуры записи, данный бит также сбрасывается самостоятельно.
Бит EEMWE — бит, разрешающий (не начинающий) процесс записи.
Бит EERIE — бит, разрешающий прерывания.
Ну, теперь перейдём к проекту. Проект был создан обычным стандартным образом и назван Test13. Также был подключен файл main.h и созданы файлы eeprom.h и eeprom.c.
Вот исходный код созданных файлов
Test13.c:
#include «main.h»
int main(void)
{
while(1)
{
}
}
main.h
#ifndef MAIN_H_
#define MAIN_H_
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include «eeprom.h»
#endif /* MAIN_H_ */
eeprom.h
#ifndef EEPROM_H_
#define EEPROM_H_
#include «main.h»
void EEPROM_write(unsigned int uiAddress, unsigned char ucData);
unsigned char EEPROM_read(unsigned int uiAddress);
#endif /* EEPROM_H_ */
eeprom.c
#include «eeprom.h»
Сначала, соответственно, мы попробуем записать данные в память EEPROM. Ну, оно и логично, так как пока мы ничего не записали, нам читать также нечего.
Ну, давайте не будем забивать голову и вставим код функции записи, также и функции чтения из примера в технической документации в файл eeprom.c и уберем англоязычные комментарии, вставив туда русскоязычные. После всех исправлений файл станет вот таким
#include «eeprom.h»
void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
{
while(EECR & (1<<EEWE)) //ждем освобождения флага окончания последней операцией с памятью
{}
EEAR = uiAddress; //Устанавливаем адрес
EEDR = ucData; //Пищем данные в регистр
EECR |= (1<<EEMWE); //Разрешаем запись
EECR |= (1<<EEWE); //Пишем байт в память
}
unsigned char EEPROM_read(unsigned int uiAddress)
{
while(EECR & (1<<EEWE))
{} //ждем освобождения флага окончания последней операцией с памятью
EEAR = uiAddress; //Устанавливаем адрес
EECR |= (1<<EERE); //Запускаем операцию считывания из памяти в регистр данных
return EEDR; //Возвращаем результат
}
Напишем прототипы на данные функции в файле eeprom.h
#include «main.h»
void EEPROM_write(unsigned int uiAddress, unsigned char ucData);
unsigned char EEPROM_read(unsigned int uiAddress);
Теперь вызовем функцию записи в функции main() и тем самым попробуем записать какую-нибудь 8-битную величину по адресу 1. Вообще, адресация в данной памяти начинается с 0
int main(void)
{
EEPROM_write(1, 120);
while(1)
Используем мы в качестве опытов ту же самую отладочную плату, вообще ничего к ней не подключая
Соберём проект и перейдём в программу для прошивки Avrdude.
Выберем там наш файл прошивки, затем попытаемся считать контроллер, затем всё сотрем по кнопке «стереть все»
Также в программе avrdude есть ещё одна строка «Eeprom». Данную строку мы можем использовать, чтобы записать в данную память не программно, а из файла. Но мы будем писать из нашей программы, а данную строку будем использовать, чтобы читать в файл память EEPROM. Можно написать в эту строку путь от руки и файл создастся сам. Напишем, например «C:\1\11111» и нажмем «Чтение», и по данному пути запишется в указанный файл вся информация из памяти EEPROM
Вы можете писать любой путь, лишь бы только указанный в нем слева носитель с такой буквой существовал и был доступен для записи. Также папку лучше создать тоже заранее.
Найдём теперь на диске данный файл и откроем его в блокноте
Данный файл имеет приблизительно такой же формат как и файл прошивки. Сначала адрес, затем 32 байта информационных и затем контрольная сумма на эти 32 байта. Если мы не разу не записывали ничего в память EEPROM, то по всем адресам у нас будут FF, то есть во всех битах памяти у нас единички.
Закрываем файл, пытаемся прошить контроллер, затем опять читаем память EEPROM в файл и откроем файл
Мы видим, что в файл записалось число «78», что и означает 120 в десятичном формате.
Теперь попробуем нажать кнопку «Стереть всё», в этом случае память EEPROM стетеься не должна.
Читаем опять EEPROM в файл, открываем файл и видим, что память стёрлась, у нас опять везде «FF».
Почему так произошло? Потому что нужно настроить фьюзы. Читаем фьюзы
Обратим внимание на бит EESAVE. Когда данный бит в единице (как у нас и есть, биты же с инверсией), то мы заставляем при отключении питания, а также при стирании стирать память EEPROM. А чтобы такого не происходило, данный бит нужно сбросить, то есть поставить в него галку и прошить фьюзы.
Прошиваем фьюзы, стираем контроллер, прошиваем контроллер, опять стираем, читаем память EEPROM в файл и открываем его. Теперь мы видим, что ничего у нас не стёрлось
Теперь попробуем отключить контроллер от питания и подать через некоторое время питание опять. Опять читаем EEPROM в файл, у нас всё цело. Отлично!
В следующей части урока мы попробуем программно прочитать данные из памяти EEPROM.
Предыдущий урок Программирование МК AVR Следующая часть
Приобрести программатор USBASP USBISP с адаптером можно здесь USBASP USBISP 3.3 с адаптером
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Добрый день! Для записи в ЕЕПРОМ 4-х байтного числа я использовал готовые функции Атмел eeprom_read_dword () и eeprom_write_dword (), предварительно создав глобальную переменную uint32_t EEMEM… Затем, прогой Hex2bin я переконвертировал файл *.еер в *.bin для нормально симуляции ЕЕПРОМ в Протеусе. В итоге, проект симуляция проекта проходит отлично. Значения в ЕЕПРОМ сохраняются и считываются так как нужно. Но меня вот что беспокоит. В исходном коде объявлена глобальная переменная uint32_t EEMEM. При перезапуске устройства ей всегда присваивается один и тот же адрес в ЕЕПРОМ? Т.е. я опасаюсь, что в реальном устройстве при попытке считать данные eeprom_read_dword (), считается FFFF, например, вместо ранее записанного числа.
Точно ли что при выставленом бите EESAVE стирается память при отключении питания? При перепрошивке да, но про питание не видел
А тут кто-нибудь когда-нибудь на вопросы отвечает?