Добавление внешней памяти EEPROM в Ардуино (24LC256)

Очень простой и эффективный способ хранения данных – это использовать внутреннюю память Ардуино. Но это подходит для хранения небольших объемов данных, поскольку в Ардуино встроенная EEPROM имеет размер всего 512 байт.

При работе с более крупными или более сложными проектами нам может потребоваться сохранять дополнительные данные. В связи с этим возникает необходимость использовать внешнюю память, например 24LC256.

Микросхема памяти 24LC256 имеет размер 256 Кбит, что на самом деле составляет 32 Кбайт (262 144 бит / 8 бит = 32 768 байт). Это в 62 раза больше встроенной памяти Ардуино!

Настройка оборудования

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

24LC256

Цифровой мультиметр AN8009
Большой ЖК-дисплей с подсветкой, 9999 отсчетов, измерение TrueRMS...
Подробнее

Микросхему Microchip 24LC256 можно приобрести в 8-контактном DIP-корпусе. Распиновка 24LC256 довольно проста:

  • вывод питания (8)
  • вывод GND (4)
  • вывод защиты от записи (7)
  • вывод SCL (6)
  • вывод SDA (5)
  • выводы адреса (1,2,3)

Прежде чем мы перейдем к программной части, давайте подключим микросхему 24LC256 к нашей Ардуино.

Добавление внешней памяти EEPROM в Ардуино (24LC256)

Используя вышеприведенный рисунок, давайте приступим к подключению микросхемы. Сначала подключите GND и VCC к контактам 4 и 8 соответственно. Далее подключите выводы данных к плате Ардуино. Поскольку мы используем I2C шину, мы будем использовать контакты A4 и A5. Подключите контакт SDA 24LC256 (контакт 5) к контакту A4 Ардуино. Затем подключите SCL (контакт 6) к контакту A5 на Ардуино. Дважды убедитесь, что все подключено правильно, иначе могут произойти странные вещи, если вы их перепутаете.

После того, как выводы данных и питание подключены, у 24LC256 осталось еще четыре неподключенных вывода: вывод WP и три вывода адреса.

Контакт WP обеспечивает защиту от записи. Это позволяет вам контролировать процесс записи данных в EEPROM. Если на этом выводе низкий логический уровень (0), то запись разрешена. Если же на выводе WP будет высокий логический уровень (1), то запись запрещена, но при этом чтение всегда доступно. В рамках этого руководства мы будем записывать в EEPROM, так что вывод WP подключим к GND.

Последние три контакта устанавливают адрес 24LC256, который позволяет идентифицировать конкретную микросхему на I2C шине. Микросхема 24LC256 поставляется с уже установленными четырьмя битами адреса (1010), которые нельзя изменить. Однако последние три бита адреса можно изменять, и это позволяет нам подключать до восьми микросхем 24LC256 на одну шину I2C. Давайте посмотрим на рисунок ниже, чтобы поподробнее разобраться, как формируется этот адрес:

24LC256 адрес

Для простоты понимания как работает I2C адрес, мы можем игнорировать биты начала (Start) и подтверждения (Acknowledge). Шина I2C работает так: 7-битный адрес передается вместе с битом чтения / записи, который сообщает микросхеме, должна ли она записывать входящие данные или читать.

Ардуино позаботится о последнем бите чтения / записи в зависимости от того, какую функцию мы используем. Так как мы используем стандартную библиотеку Ардуино Wire, нам не нужно беспокоиться об этом бите.

И теперь у нас остались семь средних битов, и, как упоминалось выше, первые четыре бита жестко запрограммированы, и мы не можем их изменить. Следующие три бита (A2, A1, A0) являются важными битами, которые мы можем изменять.

Итак, если мы соединим контакты 1, 2 и 3 микросхемы 24LC256 с GND, то микросхема будет иметь I2C адрес 0x50, а если все эти выводы подключить к Vcc, тогда микросхема будет иметь I2C адрес 0x57. Перебирая все комбинации, мы можем получить 8 адресов от 0x50 до 0x57.

Для упрощения просто соединим все контакты с GND, чтобы получился адрес 0x50.

После подключения адресных выводов аппаратная часть этого руководства завершена. Пора переходить к программному обеспечению!

Некоторые используют подтягивающие резисторы на выводах SCL и SDA Ардуино. Хотя это не повредит схеме, но в них нет необходимости, потому что при инициализации библиотеки Wire.h Ардуино знает, что выводы 4 и 5 будут использоваться для I2C, и в связи с этим активируются встроенные подтягивающие резисторы.

Скетч

Ниже приведен полный код работы с внешней памятью 24LC256. Далее рассмотрим его работу подробнее.

#include <Wire.h>    
 
#define disk1 0x50    //Address of 24LC256 eeprom chip
 
void setup(void)
{
  Serial.begin(9600);
  Wire.begin();  
 
  unsigned int address = 0;
 
  writeEEPROM(disk1, address, 123);
  Serial.print(readEEPROM(disk1, address), DEC);
}
 
void loop(){}
 
void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data ) 
{
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(data);
  Wire.endTransmission();
 
  delay(5);
}
 
byte readEEPROM(int deviceaddress, unsigned int eeaddress ) 
{
  byte rdata = 0xFF;
 
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
 
  Wire.requestFrom(deviceaddress,1);
 
  if (Wire.available()) rdata = Wire.read();
 
  return rdata;
}

Чтобы использовать интерфейс I2C, нам необходимо подключить стандартную библиотеку Wire Ардуино, поэтому первым делом подключите Wire.h в верхней части скетча. Вы заметите, что сразу после подключения мы определяем переменную с именем disk1 и присваиваем ей шестнадцатеричное значение 0x50 – это адрес нашей памяти. Эта переменная не является обязательной, но она позволяет нам легко изменить адрес, к которому мы хотим получить доступ, не просматривая весь код и не заменяя значение.

Кроме того, если вы планируете добавить более одной микросхемы памяти, проще называть их disk1, disk2 и т. д., а не 0x50, 0x51… что может запутать.

Далее у нас есть функция setup() и функции loop(). В этом руководстве функция loop() оставлена ​​пустой, поэтому мы просто сосредоточимся на функции setup().

Сначала мы инициализируем последовательное соединение, а затем инициируем соединение I2C, вызывая Wire.begin(). Это активирует контакты 4 и 5 для I2C, а также подключает внутренние подтягивающие резисторы.

Затем мы создаем новую переменную для хранения адреса ячейки EEPROM, в которую мы хотим записать (не адрес самой микросхемы EEPROM, а адрес байта, который мы хотим считать / записать). Поскольку эта EEPROM имеет 32 Кбайт памяти, этот адрес может быть любым числом от 0 до 32 767. Мы начнем с адреса 0.

После того, как мы все инициализировали, мы переходим к нашим двумя основными функциям: writeEEPROM и readEEPROM, которые фактически выполняют всю основную работу записи / чтения байтов данных.

Давайте сначала начнем с функции writeEEPROM. Эта функция принимает три аргумента: адрес устройства (переменная disk1), адрес памяти EEPROM и байт данных, которые мы хотим записать.

Первый аргумент — это адрес устройства, в память которого мы хотим выполнить запись, в нашем случае у нас только одно устройство (disk1), поэтому мы передаем его.

Следующим аргументом является адрес ячейки EEPROM, в которую мы будем сохранять данные, и, как было сказано выше, этот адрес может находиться в диапазоне от 0 до 32 767. Наконец, нам нужно передать байт данных, который мы хотим сохранить.

Пример: writeEEPROM (disk1, address, 123) будет записывать десятичное число 123 в «address» (который равен 0) на устройство disk1 (0x50).

Давайте перейдем к самой функции writeEEPROM, чтобы узнать, что она делает.

void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data )
{
 Wire.beginTransmission(deviceaddress);
 Wire.write((int)(eeaddress >> 8)); // MSB
 Wire.write((int)(eeaddress & 0xFF)); // LSB
 Wire.write(data);
 Wire.endTransmission();
 delay(5);
}

Сначала мы вызываем функцию Wire.beginTransmission, которая отправляет адрес устройства, для того чтобы микросхема памяти знала, что мы хотим с ней связаться. Затем мы должны отправить адрес ячейки EEPROM, в которую мы хотим записать данные.

Поскольку наша микросхема EEPROM имеет 32 000 ячеек, мы используем два байта (16 бит) для хранения адреса. Но поскольку мы можем отправлять только один байт за раз, то мы должны разделить его.

Первая функция отправки принимает eeaddress и сдвигает биты вправо на восемь. Затем мы выполняем побитовое И, чтобы получить только последние восемь бит. Чтобы понять это рассмотрим это на примере:

Допустим, мы хотим записать в ячейку с адресом 20000 ( 0100 1110 0010 0000 в двоичном формате). Сначала нам нужно отправить MSB (старший бит), поэтому мы должны переместить наш адрес на восемь бит:

0100 1110 0010 0000 (eeaddress)
После сдвига на 8 бит вправо получаем
0100 1110

Теперь у нас есть первая половина адреса, пора получить вторую половину:

0100 1110 0010 0000 (eeaddress)
После побитового И 0xFF с eeaddress мы получаем
0010 0000

В результате этих операций микросхема 24LC256 получает адрес 1001 1100, а затем 0010 0000, который сообщает ей, что она должна сохранить следующий байт в ячейке с адресом 20000. Теперь, когда мы отправили адрес, мы отправляем данные, а затем завершаем процесс, вызывая функцию endTransmission.

Микросхема 24LC256 получит данные и запишет их по этому адресу. Чтобы завершить эту функцию, вы наверное заметили, что добавлена задержка в 5 миллисекунд. Это дает микросхеме время для завершения операции записи. Без этого, если вы попытаетесь выполнить последовательную запись, могут произойти странные вещи.

После того как мы научились сохранять наши данные в EEPROM, пора перейти к функции readEEPROM, которая позволяет считывать данные из микросхемы памяти.

byte readEEPROM(int deviceaddress, unsigned int eeaddress ) 
{
  byte rdata = 0xFF; 
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress,1);
  if (Wire.available()) rdata = Wire.read();
  return rdata;
}

ReadEEPROM принимает два аргумента и возвращает байт (данные). Аргументы, которые принимает ReadEEPROM — это те же первые два аргумента, что и у функции writeEEPROM, адрес устройства и адрес ячейки EEPROM, из которого следует считать данные.

Сначала мы объявляем переменную для хранения байта, который мы собираемся получить. Затем мы начинаем так же, как мы делали с функцией записи, запуская процесс beginTransmission, а затем отправляем адрес устройства, к которому мы хотим получить доступ (это работает точно так же, как функция записи).

Далее мы завершаем передачу. В итоге мы установили связь с 24LC256 с адресом, который нас интересует, так что теперь нам просто нужно запросить и прочитать данные.

Следующая функция requestFrom() отправляет этой микросхеме команду начать отправку данных по указанному выше адресу. Второй аргумент – сколько считать байтов (начиная с этого адреса). Мы запрашиваем только один. Наконец, мы проверяем, есть ли данные на шине I2C, и, если они есть, считываем их в переменную rdata. Возвращаем байт данных и все готово!

Это все, что вам действительно нужно знать, чтобы успешно использовать внешнюю память с Ардуино.

Добавить комментарий

Ваш электронный адрес не будет опубликован.


*