Программирование AT24C16 EEPROM с помощью Arduino Nano

Я пытался запрограммировать EEPROM AT24C16 и настроил схему в соответствии с прилагаемым изображением.

Я использую следующий код Arduino:

#include <Wire.h>    
 
#define disk1 0x50    //Адрес микросхемы eeprom 24LC256
 
void setup(void)
{
  Serial.begin(9600);
  Wire.begin();  
 
  unsigned int address = 10;
 
  writeEEPROM(disk1, address, 72);
  Serial.println(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);
  Serial.println(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
  Serial.println(Wire.endTransmission());
 
  Wire.requestFrom(deviceaddress,1);
 
  if (Wire.available()) rdata = Wire.read();
 
  return rdata;
}

К сожалению, я всегда получаю только " 255 " на последовательном мониторе, предполагая, что данные не были записаны.

Код был взят из этого учебника, который объясняет, как проводка на контактах 1-3 управляет адресом чипа.

, 👍0

Обсуждение

Посмотрите, какие значения возвращают ваши вызовы .endTransmission(). Возможно, вы захотите использовать скетч I2CScanner, чтобы хотя бы убедиться, что он отображается на шине., @timemage

Привет, обновил код, так что он распечатывает вызовы .endTransmission () и получает "2", возвращенное от обоих, которое, согласно проводному документу, является "2: получено NACK при передаче адреса"., @user2105725

Я думал, что должен напечатать вызов endTransmission как для writeEEPROM(), так и для readEEPROM() ? - обновит вопрос, когда я знаю, куда поместить инструкцию print..., @user2105725

Итак, обновленный код возвращает "0" для вызовов конечной передачи чтения и записи., @user2105725

Что произойдет, если вместо этого вы используете unsigned int address = 0;?, @timemage

То же самое. Я пробовал разные адреса и разные значения, и они всегда кажутся одним и тем же результатом.., @user2105725


2 ответа


Лучший ответ:

1

Что ж, мне кажется, я вижу часть того, что происходит. Я не уверен, в какой степени это проблема Arduino, но это может быть полезно для тех, кто хочет соединить этот чип с Arduino. Итак, вот что я вижу:

В том, что касается I2C, вы пишете на чип просто отлично. Но содержание того, что вы пишете, не совсем корректно для самого чипа.

У вас есть:

Wire.beginTransmission(deviceaddress);
Wire.write((int)(eeaddress >> 8));   // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB

Это интуитивно понятно, но, к сожалению, не так, как, по-видимому, работает AT24C16. Чтобы было ясно, в учебнике, на который вы ссылались, используется 24LC256, который использует приведенную выше схему адресации. Но вы не используете этот чип.

Микросхемы серии, описанной в спецификации AT24LC16, нуждаются в постепенно увеличивающихся адресах EEPROM для увеличения объема памяти. По мере увеличения размера чипа они эффективно крадут настраиваемые биты из выводов A0, A1, A2 и перепрофилируют их как часть адреса EEPROM, закодированного в адрес I2C. Вы увидите, что для адресуемого EEPROM до 2Kbit/256byte/8 бит все A0, A1, A2 могут быть использованы для установки адреса I2C (чтобы иметь несколько этих чипов). К тому времени, когда вы доберетесь до 16-битного/2-битного/11-битного адресуемого чипа, все A0, A1, A2 будут указаны как no connect; в таблице данных говорится, что они могут быть подключены к земле. Причина этого, вероятно, только в том, чтобы контролировать шум.

Чип ожидает, что только младшие 8 бит словесного адреса EEPROM будут отправлены в части данных записи I2C (или "фиктивной" записи). Но ожидается, что биты, превышающие 8 бит, верхние 3 бита для вашего 11-битного адресуемого, будут закодированы в сам адрес I2C следующим образом:

const uint8_t i2c_base_address = 0x50;
const uint8_t upper_three_eeprom_adress_bits = (eeaddress >> 8) & 0x7;
const uint8_t i2c_address = i2c_base_address | upper_three_eeprom_adress_bits;
Wire.beginTransmission(i2c_address);
Wire.write(eeaddress & 0xFF); // адрес LSB

В таблице данных говорится о "БАЙТОВОЙ ЗАПИСИ", когда отдельные байты на транзакции записи I2C записываются в EEPROM. И это говорит о "ЗАПИСИ СТРАНИЦЫ", когда отправляется вся полезная нагрузка страницы, 16 байт для вашей модели. Поскольку вы отправляете два байта как часть части данных записи I2C, вы не делаете ни того, ни другого. Понятие чипа "текущий адрес" обновляется по-разному для записи "байт" и "страница".

Если бы я догадался, они не хотели, чтобы была качественная разница в обработке транзакций записи I2C 1 против 2 байтов или попеременно между транзакциями записи I2C 15 (размер страницы минус один) против транзакций записи I2C 16 байтов (размер страницы). Таким образом, они просто решили, что все, что находится посередине между записью одного байта и записью всей страницы, должно игнорироваться, поэтому операция записи EEPROM не выполняется.

,

Большое вам спасибо за то, что нашли время ответить так глубоко и ясно. Я обновил свой код, и он, похоже, работает! Должен ли я опубликовать свой код в качестве другого ответа? Раздел комментариев этого не допустит..., @user2105725

По-моему, это звучит разумно. Да, комментарии на самом деле не предназначены для материала ответов, не говоря уже о коде любого значительного размера., @timemage


2

В ответ на ответ @timemage я обновил свой код, который теперь позволяет мне читать и записывать на чип EEPROM по назначению. Вот код на всякий случай, если кто-то еще захочет сделать это быстро:

#include <Wire.h>

#define disk1 0x50    //Адрес микросхемы eeprom

void setup(void)
{
  Serial.begin(9600);
  Wire.begin();

  unsigned int address0 = 0;

  writeEEPROM(disk1, address0, 1);

  Serial.println(readEEPROM(disk1, address0), DEC);
}

void loop() {}

void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data )
{

  const uint8_t i2c_base_address = 0x50;
  const uint8_t upper_three_eeprom_adress_bits = (eeaddress >> 8) & 0x7;
  const uint8_t i2c_address = i2c_base_address | upper_three_eeprom_adress_bits;
  Wire.beginTransmission(i2c_address);
  Wire.write(eeaddress & 0xFF); // адрес LSB

  Wire.write(data);
  Wire.endTransmission();

  delay(5);
}

byte readEEPROM(int deviceaddress, unsigned int eeaddress )
{
  byte rdata = 0xFF;


  const uint8_t i2c_base_address = 0x50;
  const uint8_t upper_three_eeprom_adress_bits = (eeaddress >> 8) & 0x7;
  const uint8_t i2c_address = i2c_base_address | upper_three_eeprom_adress_bits;
  Wire.beginTransmission(i2c_address);
  Wire.write(eeaddress & 0xFF); // адрес LSB
  
  Wire.endTransmission();

  Wire.requestFrom(deviceaddress, 1);

  if (Wire.available()) rdata = Wire.read();

  return rdata;
}
,