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

Программирование микроконтроллеров. Урок 21
(EEPROM.)

Урок 21 (EEPROM.)

На прошлом уроке мы с вами поигрались с АЦП и сделали вольтметр. А на этом уроке мы запишем данные в энергонезависимую память EEPROM и извлечем эти данные оттуда, а также рассмотрим некоторые нюансы, связанные с контролем питания МК.


Энергонезависимая память EEPROM служит для сохранения ключевых данных и настроечных коэффициентов. Использовать эту память как ОЗУ не получится т.к., во-первых, она очень «медленная», а во-вторых, имеет конечный ресурс циклов перезаписи (около 100 тыс.).

Для работы с EEPROM используются три регистра: EEAR (EEARН, EEARL) – старший и младший регистры адреса, EEDR – регистр данных, EECR – регистр управления. Т.к. в ATmega8 имеется 512 байт EEPROM, то для полного охвата адресного пространства требуется два адресных регистра. При этом в регистре EEARH задействован только младший бит. Остальные доступны только для чтения и содержат (0). Регистр EEDR служит для транспортировки сохраняемых данных. В него помещаются данные при записи и извлекаются данные при чтении.

Из-за того, что работа энергонезависимой памяти тактируется её собственным «медленным» генератором, то процесс работы с ней имеет ряд трудностей и ограничений. И в первую очередь необходимо сказать о том, что алгоритм работы EEPROM не тривиален.

Рассмотрим подпрограмму для записи данных в EEPROM.

void eepr_in (unsigned char data_eepr, unsigned int adr_eepr) {
	while (EECR & (1<<EEWE)); 		//ждать завершения предыдущей записи
  	EEARH = (unsigned char) (adr_eepr >> 8);//старший регистр адреса - загрузить адрес
	EEARL = (unsigned char) adr_eepr; 	//младший регистр адреса - загрузить адрес
   	EEDR = data_eepr;    		  	//загрузить данные
   	EECR |= (1<<EEMWE);  			//установить флаг разрешения записи
   	EECR |= (1<<EEWE);   			//дать команду на запись
  	return;
} 
				

Как я уже писал, запись в EEPROM происходит очень «медленно» поэтому чтобы соблюдалась последовательность записываемых/читаемых данных в начале необходимо дождаться завершение процесса записи. Как только этот процесс закончен, и флаг разрешения записи в EEPROM снят, необходимо загрузить старший и младший регистры адреса, затем регистр даты и уже после этого установить флаг разрешения записи EEMWE. После установки флага EEMWE необходимо в течении четырех тактов дать команду на запись установив флаг EEWE. Если этого не сделать, то флаг EEMWE автоматически сбросится и записи данных не произойдет. Поэтому разработчики настоятельно рекомендуют запрещать все прерывания перед установкой флага EEMWE и разрешать их после установки флага EEWE. В противном случае вклинившееся прерывание может отменить запись в EEPROM.

Как вы уже поняли, флаги работы EEPROM находятся в регистре управления EECR. В нем содержится:
EERIE – 3-ий бит. Разрешение прерывания от EEPROM. (1) – прерывание разрешено, (0) – прерывание запрещено.
EEMWE – 2-ой бит. Управление разрешением записи. (1) – запись разрешена (0) – запись запрещена. Автоматически сбрасывается через четыре такта после установки.
EEWE – 1-ый бит. Флаг команды начала процесса записи. (1) – запись начать. После окончания процесса записи автоматически сбрасывается.
EERE – 0-ой бит. Флаг команды начала процесса чтения. (1) – чтение начать. После окончания процесса чтения автоматически сбрасывается.

Процесс чтения данных из EEPROM попроще и организуется следующим образом:

unsigned char eepr_out (unsigned int adr_eepr) { 	
	while (EECR & (1<<EEWE));  		//ждать завершение предыдущей записи
	EEARH = (unsigned char) (adr_eepr >> 8);//старший регистр адреса - загрузить адрес
	EEARL = (unsigned char) adr_eepr; 	//младший регистр адреса - загрузить адрес
   	EECR = (1<< EERE);   			//дать команду на чтение
	return (EEDR);				//возвращаем данные из регистра EEDR
} 

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

Для проверки программы необходимо собрать схему из урока 18. Энкодером выставляем тестовое значение и по нажатию на кнопку оно записывается в энергонезависимую память.

Вот как это работает.

На видео видно, что записанные данные после включения устройства снова появляются на экране. Но это может быть не всегда. Велика вероятность того, что при выключении устройства или понижении напряжения питания, данные, хранящиеся в EEPROM, могут испортиться. Это происходит из-за того, что при снижении напряжения питания, МК может выполнять запись в EEPROM по своему усмотрению. Будет ли что-то записано в память, какие это будут данные никому не известно.

Есть только один действенный способ сохранять данные, записанные в EEPROM – включить детектор пониженного напряжения питания (Brown-Out Detection). Для этого необходимо запрограммировать конфигурационные ячейки BODEN и BODLEVEL:
BODEN – Разрешает (0) / запрещает (1) работу схемы контроля питания.
BODLEVEL – Определяет порог срабатывания схемы контроля питания. (0) – 4V, (1) – 2.7V.

При программировании конфигурационных ячеек (фьюзов) необходимо помнить, что запрограммированной ячейкой считается та, в которой (0), а не запрограммированной та в которой (1). По поводу программирования фьюзов можно освежить свою память, перечитав урок 15.

Ну вот, теперь память работает без сбоев и защищена.

На следующем уроке мы рассмотрим работу аналогового компаратора. Для этого нам понадобиться резисторы, которые мы использовали при работе с АЦП. И конечно, на сон грядущий, необходимо почитать:
Евстифеев А.В. «Микроконтроллеры AVR семейства Tiny и Mega фирмы Atmel» 2008г. Страницы 305…309.
А также найти пару статей, рассказывающих о том, что это за «звери» такие, компараторы и с чем их «едят».

А на сегодня всё. Удачи.

12.04.20

Если вдруг найдете в статье неточности или заблуждения. Напишите мне об этом. Я подправлю.

Приложение:
Файлы к уроку 21