Внешняя память 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<<TWPS1)|(1<<TWPS0))); } uint8_t EEWriteByte(uint16_t address,uint8_t data) { do { //Put Start Condition on TWI Bus TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN); //Poll Till Done while(!(TWCR & (1<<TWINT))); //Проверка статуса if((TWSR & 0xF8) != 0x08) return FALSE; //Now write SLA+W //EEPROM @ 00h TWDR=0b10100000; //Инициализация передачи TWCR=(1<<TWINT)|(1<<TWEN); //Poll Till Done while(!(TWCR & (1<<TWINT))); }while((TWSR & 0xF8) != 0x18); //Now write ADDRH TWDR=(address>>8); //Инициализация передачи TWCR=(1<<TWINT)|(1<<TWEN); //Poll Till Done while(!(TWCR & (1<<TWINT))); //Проверка статуса if((TWSR & 0xF8) != 0x28) return FALSE; //Now write ADDRL TWDR=(address); //Initiate Transfer TWCR=(1<<TWINT)|(1<<TWEN); //Poll Till Done while(!(TWCR & (1<<TWINT))); //Check status if((TWSR & 0xF8) != 0x28) return FALSE; //Now write DATA TWDR=(data); //Initiate Transfer TWCR=(1<<TWINT)|(1<<TWEN); //Poll Till Done while(!(TWCR & (1<<TWINT))); //Check status if((TWSR & 0xF8) != 0x28) return FALSE; //Put Stop Condition on bus TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO); //Wait for STOP to finish while(TWCR & (1<<TWSTO)); //Wait untill Writing is complete _delay_ms(12); //Return TRUE return TRUE; } uint8_t EEReadByte(uint16_t address) { uint8_t data; //Initiate a Dummy Write Sequence to start Random Read do { //Put Start Condition on TWI Bus TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN); //Poll Till Done while(!(TWCR & (1<<TWINT))); //Check status if((TWSR & 0xF8) != 0x08) return FALSE; //Now write SLA+W //EEPROM @ 00h TWDR=0b10100000; //Initiate Transfer TWCR=(1<<TWINT)|(1<<TWEN); //Poll Till Done while(!(TWCR & (1<<TWINT))); }while((TWSR & 0xF8) != 0x18); //Now write ADDRH TWDR=(address>>8); //Initiate Transfer TWCR=(1<<TWINT)|(1<<TWEN); //Poll Till Done while(!(TWCR & (1<<TWINT))); //Check status if((TWSR & 0xF8) != 0x28) return FALSE; //Now write ADDRL TWDR=(address); //Initiate Transfer TWCR=(1<<TWINT)|(1<<TWEN); //Poll Till Done while(!(TWCR & (1<<TWINT))); //Check status if((TWSR & 0xF8) != 0x28) return FALSE; //*************************DUMMY WRITE SEQUENCE END ********************** //Put Start Condition on TWI Bus TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN); //Poll Till Done while(!(TWCR & (1<<TWINT))); //Check status if((TWSR & 0xF8) != 0x10) return FALSE; //Now write SLA+R //EEPROM @ 00h TWDR=0b10100001; //Initiate Transfer TWCR=(1<<TWINT)|(1<<TWEN); //Poll Till Done while(!(TWCR & (1<<TWINT))); //Check status if((TWSR & 0xF8) != 0x40) return FALSE; //Now enable Reception of data by clearing TWINT TWCR=(1<<TWINT)|(1<<TWEN); //Ожидание до конца выполнения while(!(TWCR & (1<<TWINT))); //Проверка статуса if((TWSR & 0xF8) != 0x58) return FALSE; //Чтение данных data=TWDR; //Put Stop Condition on bus TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO); //Wait for STOP to finish while(TWCR & (1<<TWSTO)); //Return TRUE return data; }
Содержание файла-конфигурации 24c64.h:
#ifndef _24C64_H_ #define _24C64_H_ #define FALSE 0 #define TRUE 1 //Прототипы функций void EEOpen();//Функция инициализации памяти uint8_t EEWriteByte(uint16_t,uint8_t);//Функция записи байта в память uint8_t EEReadByte(uint16_t address);//Функция чтения байта из памяти #endif
Файл atmega8_eeprom_read.c:
#include <avr/io.h>//библиотека ввода/вывода #include "util/delay.h"//библиотека задержки #include "24c64.h"//подключаем конфигурационный файл #include "24c64.c"//подключаем файл с набором функций для записи/чтения в EEPROM unsigned char b;//переменная для отправки и приема данных по USART unsigned int address;//переменная адреса //Функция инициализации модуля USART void USART_Init( unsigned int ubrr) { /* Устанавливаем baud rate */ UBRRH = (unsigned char)(ubrr>>8); UBRRL = (unsigned char)ubrr; /* Разрешаем прием и передачу */ UCSRB = (1<<RXEN)|(1<<TXEN); /* устанавливаем формат данных: 8 бит данных, 2 стоп бита*/ UCSRC=0x86;// UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0); } void USART_Transmit( unsigned char data ) //Функция отправки данных по USART { while ( !(UCSRA & (1<<UDRE)) ); //Ожидание опустошения буфера приема UDR = data; //Начало передачи данных } void eeread (void)//Функция чтения данных из памяти EEPROM { for(address=0; address<25; address++)//цикл с адресами данных {b = EEReadByte(address);//присваиваем переменной b прочитанный байт данных USART_Transmit(b);//Передаем прочитанный байт по USART } USART_Transmit(0x0d);//переход в начало строки USART_Transmit(0x0a);//переход на новую строку } int main(void)//Основная программа { //Инициализация EEPROM EEOpen(); _delay_ms (15);//Небольшая задержка //Конфигурируем модуль USART на скорость 115200кБит/с при частоте кварца 16МГц USART_Init (8);//115200 16MHz while(1)//Вечный цикл {eeread ();//Выполняем чтение заданной области памяти из микросхемы EEPROM } }
Программа выполняет чтение данных из микросхемы внешней EEPROM и отправляет прочитанные значения ячеек по порту USART, которые можно легко прочитать подключив конвертер уровней на MAX232 и запустив программу Terminal RS232. Адрес, до которого выполнять чтение, задается в части кода:
for(address=0;address<25;address++) { b = EEReadByte(address); }
0 -начальный адрес ячейки,
25 - значение номера ячейки памяти, до которой выполнять чтение. При желании всегда можно изменить, или задать это значение через переменную, которая будет изменяться в зависимости от того, какую область памяти необходимо считать.
Так же в библиотеке для работы с внешней памятью EEPROM есть функция записи, вызывается она следующим образом:
for(address=0; address<500; address++)//цикл с пределами памяти { if(EEWriteByte(address,a)==0)//проверка возможности записи {//Write Failed ...//Команды для выполнения если запись не удалась break; } }
Таким образом в данной статье есть все необходимые программы для осуществления чтения/записи с внешней микросхемы памяти EEPROM из серии 24CXX. Удачи!
А как записать по i2c
А как записать по i2c в eeprom по адресу 0x7D00(32000)?
eeprom 64 Kb.
int address = 0x7D00; int a =
int address = 0x7D00;
int a = 32000;
EEWriteByte(address,a);
Вот так.
>>Микросхемы EEPROM имеют так
>>Микросхемы EEPROM имеют так называемый Lock-бит.
>>Этот бит защищает микросхему от случайного, или преднамеренного стирания. Записывается он единажды, на заводе, где производят устройство.
Откуда такая информация если не секрет? Я знаю что у них есть нога "только чтение" ни про какой лок бит не слыхивал.
Я так скажу, имел опыт работы
Я так скажу, имел опыт работы с микрой вытянутой из модема старого. Подключил так же как и перед этим обычную, новую микру eeprom. Результат: получилось только прочитать содержимое. Все попытки записать заканчивались неудачей. По сему, микра имеет бит, который отвечает за запись!
То ты наверно вытянул память
То ты наверно вытянул память типа ROM, которая записывается один раз на заводе. Игрался с похожей, вытянутой с мертвого CD-ROM'а.
Добрый вечер! А возможно
Добрый вечер!
А возможно переделать данный проект не с работой 24схх ,а с другим контроллером?
Или полностью придется все переделывать?
Вопрос как-то не корректно
Вопрос как-то не корректно сформулирован.
Контроллер там может быть любой начиная с ATmega8, а микросхема может быть любая из серии 24Cxx