Задача: Запись и чтение из внутренней энергонезависимой памяти EEPROM
Исходный материал: PIC16f628a и простенькая devboard.
Микроконтроллер PIC16f628a имеет на борту 128 байт EEPROM, не шибко много, но что есть то есть. Обычно в компиляторах уже есть встроенные функции записи/чтения из памяти, Hi-tech PICC не исключение, но здесь я приведу разработку своих функций с нуля. Начнем с регистра EECON1:
EEPGD – В микроконтроллере PIC16f628a не используется
WRERR – флаг ошибки
• 1 – операция записи прервана
• 0 – операция записи прошла успешно
WREN – Разрешение записи в EEPROM
• 1 – Операция записи разрешена
• 0 – Операция записи запрещена
WR – Контрольный бит записи
• 1 – Инициализация записи
• 0 – Запись завершена
RD – Контрольный бит чтения
• 1 – Инициализация чтения
• 0 – Чтение завершено
*Биты WR и WD нужно устанавливать только в “1”, сброс в низкое логическое состояние происходит автоматически, после завершения операции
Кроме этого есть еще вспомогательные регистры:
- Регистр EEDATA – 8 битный регистр, служит буфером, куда помещаются данные при чтении/записи.
- Регистр EEADR – 7 битный регистр, указывающий адрес куда будет производится запись или адрес, откуда нужно прочитать данные.
- Программный регистр EECON2 – регистр использующийся исключительно для операции запись в EEPROM, для успешной операции записи необходимо последовательно записывать в этот регистр следующее выражение:
EECON2=0x55; EECON2=0xAA;
Да, еще, для EEPROM также может генерироваться прерывание – флаг EEIF устанавливается при успешной операции записи.
Порядок чтения из EEPROM:
- Запись нужного адреса в регистр EEADR.
- Установка бита RD в “1”.
- Данные сохранены в регистре EEDAT и готовы для использования.
Порядок записи в EEPROM:
- Запись нужного адреса в регистр EEADR.
- Запись данных в регистр EEDAT.
- Установка WREN в “1”.
- Запись в регистр EECON2 0x55 и 0хАА.
- Установка бита WR в “1”.
Также в даташите сильно просят отключать на время записи прерывания, вот в принципе и все. Уже можно работать с EEPROM.
Код -пример работы:
#include <htc.h> #define _XTAL_FREQ 4000000 __CONFIG(MCLRDIS & UNPROTECT & WDTDIS & LVPDIS & HS); unsigned char eeprom_read_my(unsigned char adres); // инициализация операции чтения unsigned char eeprom_write_my(unsigned char data, unsigned char adres); // инициализцация операции записи void main() { unsigned char temp=0; CMCON = 0x07; // Выключаем компараторы TRISA = 0xFF; TRISB = 0x00; temp = eeprom_read_my(0x07); // Читаем нужный адрес for (;;) { PORTB = temp; // Присваиваем порту Б значение из EEPROM if (!RA1) { __delay_ms(100); if (!RA1) { if (temp < 240) { // Пишем в память значения от 16 до 240, с шагом 16 temp = temp + 16; eeprom_write_my(temp, 0x07); } else { temp = 16; eeprom_write_my(temp, 0x07); } } } } } unsigned char eeprom_read_my(unsigned char adres) { EEADR = adres; RD = 1; return EEDATA; } unsigned char eeprom_write_my(unsigned char data, unsigned char adres) { GIE=0; EEADR=adres; EEDATA=data; WREN=1; EECON2=0x55; EECON2=0xAA; WR=1; GIE=1; }
Видео с примером работы кода на devboard:
Ну и до кучи фото с состоянием порта B:
А также состояние EEPROM в этот момент:
По адресу 0х07 записано число 0х50 = 0b01010000 (B4 = 1 и B6 = 1 на прошлой картинке).
Исходники на репе здесь.
Здравствуйте . Много узнал на этом . Спасибо . Не могу разобраться с eeprom . Не подскажите как прочитать из памяти фразу целиком (пытаюсь сделать усилитель с темброблоком и lcd ) ? eeprom_read_my(0x07) это значение одного регистра , а как прочитать , скажем , подряд несколько адресов .
там записана фраза “Громкость” .У меня получается только “Г” вывести __EEPROM_DATA(1,0xa1,0x70,0x6f,0xbc,0xba,0x6f,0x63);
__EEPROM_DATA(0xbf,0xc4,2
Добрый день,
Почему не читаете значения в цикле? Организовали цикл и считывайте хоть всю EEPROM.
компилятор такой как у вас. pic16f628a
Спасибо за ответ . Да я уже приблизительно в эту сторону и думал (я очень не давно занимаюсь программированием , да и микроконтроллерами тоже ) , но не знаю как правильно написать его . Если не затруднит можете пример привести . Чую где-то рядом топчусь , но пока не одолел . Спасибо .
так а че тут показывать то:
спасибо за совет . вроде работает .
вот так вышло
for(i = 0; i < 8; i++) {
addr = EEPROM_READ(0x00+i); } читать – читает ,а как вывести прочитанное на lcd в одну строку ? тоже циклом ?
все получилось .спасибо .на очереди i2c .
Хорошо, что получилось 🙂
Уважаемый sarge!
С большим интересом прорабатываю Ваши статьи. С Вашей легкой руки начал осваивать Си и уже кое-что получается. Еще раз хочу поблагодарить Вас за публикации!
Возникла потребность использовать память EEPROM, в статье процесс хорошо расписан. Одно не смог осилить. Мне нужно на этапе прошивки МК заложить в EEPROM начальную информацию. Как это делается в ассеблере, я знаю. А вот как сделать это на Си, что-то запутался. Уж больно не хочется программировать кристалл по частям: основной код – на Си, а начальные данные EEPROM – на ASM. Понимаю, что задачка из “школьных”, но в Сети подсказок, увы, не нашел. Не так уж много статей по PIC на Си. Подскажите, пожалуйста.
Доброго времени суток, использовать еепром на си очень просто:
eeprom_write(0x04, temp); — записали значение переменной temp по адресу 0x04
temp = eeprom_read(0x04); — считали значение из адреса 0x04 в переменную temp
Это понятно, я хотел спросить о другом.
В ASM могут присутствовать строки записи информации в EEPROM на этапе программирования, типа:
Org 0x2100; (адрес EEPROM)
DE 0x37, 0x7D, 0x00, 0x00, 0x02, 0x00, 0x00; (байты данных для программирования)
Пытаюсь найти их аналог для программы на Си. Метод научно-исследовательского тыка тоже не помог – компилятор ругается. Можно, конечно, залить в кристалл только программу, а потом отдельно и начальную информацию EEPROM, но уж больно коряво это выглядит.
А, понял, но не сталкивался с таким вопросом никогда.
Я бы наверное либо по старту писал либо просто еепром один раз прошил заранее отдельно
Ура! Решение найдено!
Нужно вставить строку (строки):
__EEPROM_DATA (0,1,2,3,4,5,6,7); // в скобках – записываемые данные
Строк может быть несколько, данные будут записываться последовательно, а не накладываться. Саму строку рекомендуют располагать до объявления глобальных переменных, логично после строки с __CONFIG( ).
А вот смещать адрес данных в EEPROM – надо писать макросы на ASM, несколько хлопотно. Проще указать для начальных ячеек значения 0xFF. Проверено на HI_TECH_Software v 9.71a – работает!
Спасибо, что отписались 🙂
А какое время требуется для того чтобы записать данные в ячейку? Тоесть для перезаписи в туже ячейку требуется несколько милисек… может я чтото делаю не поравильно? Почему так долго?
Длительность цикла записи/стирания от 4 до 8 мс по даташиту.
А можно ли привести код-пример такой же программы только в программе MPLAB IDE и для микроконтроллера pic16f873?
Если сделаете код, то я добавлю пример. Какая разница в какой IDE код?
Вы наверное не поняли вопроса) Не могли бы Вы составить такую же программу и написать ее в МPLAB IDE для pic16f873 и выложить сюда?) Просто очень нужна помощь, а времени разбираться нету((
Ну значит вы обращаетесь не по адресу, у меня времени этим заниматься тоже нет.
Уведомление: Pic Lab, PIC16, Experiment #12, EEPROM | diymicro.org