EEPROM esterna dove sbaglio?

Ciao ragazzi, sto creando un piccolo dispositivo, visto che mi serve memorizzare dei dati ho deciso di mettere una EEPROM esterna così da poterla cambiare in caso si guastasse.
Cercavo online dei tutorial su come usarla, dovrei memorizzare un numero fornito da una variabile, che potranno andare da 0 a 2200, quindi se non erro devo usare più byte, giusto?

Cercando ho trovato un tutorial che da uno sketch di esempio, ovviamente nello sketch si chiede ad Arduino di memorizzare un valore prestabilito, unico problema di questo sketch che da come dato di lettura un altro valore rispetto a quello che memorizza.

Potreste per favore spiegarmi come risolvere questo problema che si presenta?
Grazie e buon week end a tutti :slight_smile:

#include <Wire.h> 
#define eeprom 0x50 //defines the base address of the EEPROM

void setup()  {
  Wire.begin(); //creates a Wire object
  Serial.begin(9600); 

  unsigned int address = 0; //first address of the EEPROM
  Serial.println("We write the zip code 22222, a zip code");
  for(address = 0; address<5; address++) 
    writeEEPROM(eeprom, address, '2'); // Writes 22222 to the EEPROM

  for(address = 0; address<5; address++) {
    Serial.print(readEEPROM(eeprom, address), HEX); 
    }
  }

void loop() {
  /*there's nothing in the loop() function because we don't want the arduino to 
  repeatedly write the same thing to the EEPROM over and over. 
  We just want a one-time write, so the loop() function is avoided with EEPROMs.*/
}

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

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

Vi allego lo screenshot del risultato ottenuto:

La EEPROM è un 24LC256 collegata come da schema sotto.

Il codice sembra giusto, mancano le due resistenze di pull-up su SDA SCL.

Si scusa, le ho saldate per la verità, sono 2 da 4,7KΩ ma ho dimenticato a disegnarle :sweat_smile:

Non capisco perché il codice in lettura non dia 22222 ma dia 00000
Questa parte che non arrivo a capire.

Cercando nel forum, ho trovato questa discussione che sembra inerente al mio problema, ma mi sto perdendo nel leggerla.

dopo ogni writeEEPROM prova ad aggiungere un delay(5)

Ok grazie, proverò più tardi :slight_smile:

Intanto cercando ho anche trovato questa pagina del forum, in realtà a me serve capire come poter salvare un dato sulla eeprom esterna (24LC256), che può avere valori da 0 a 2000
Tale valore sarà dato dal calcolo di una equazione.
Ovviamente mi serve anche leggerlo alla successiva accensione di Arduino, in pratica il valore sulla eeprom sarà la vecchia lettura, che verrà poi sostituita dalla nuova, però mi serve leggerla per capire quanto è variata.

La pagina trovata è questa, ma usa la eeprom interna di Arduino, io dovrei adattarla (spero di riuscirci), per la 24LC256, non vorrei usare altre librerie perché in pratica ho già incluso 7 librerie, essendo la 24LC256 I2C preferirei sfruttare questa funzione :slight_smile:
https://playground.arduino.cc/Code/EEPROMReadWriteLong/

Ho trovato tutorial online per usare la eeprom esterna ma usa un solo byte quindi memorizza fino a 255, quello postato ad inizio discussione era un tutorial che teoricamente memorizza dati a 4 caratteri ottimo per il mio lavoro, ma onestamente ho trovato difficoltà a capire il tutorial.

Grazie ancora pe ril consiglio, ti faccio sapere più tardi quando provo :slight_smile:

Niente da fare. :frowning:

E invece è giusto :wink: Nelle prime cinque celle della EEPROM hai scritto in ciascuna il valore cinquanta (codice ASCII del carattere '2') e le stai visualizzando in esadecimale: 50(10) == 32(16)

Ok, e come faccio a riavere il valore immesso, cioè seguendo lo sketch 22222 viene scritto nella eeprom, poi io sul monitor lo rivedo in esadecimale quindi 3232323232, giusto?

Ok se io volessi rivedere 22222, come faccio?
ho provato in due modi ma entrambi non funzionano:

  1. metodo ho inserito i comandi sotto:
K = (readEEPROM(eeprom, address), HEX)*pow(32, 16);
    Serial.print("Lettura EEPROM ");
    Serial.println(K);

ma ottengo 32767

  1. metodo usando string, ma anche in questo caso ottengo un altro valore
 K = (readEEPROM(eeprom, address), HEX);
    String intero = String (K, DEC);
    Serial.print("Lettura EEPROM ");
    Serial.println(intero);

In pratica dovrei riconvertire ASCII o HEX in intero giusto?
ma non ho idea di come si faccia :weary:

seguendo lo sketch 22222 viene scritto nella eeprom

No, vengono scritti cinque byte di valore cinquanta.

poi io sul monitor lo rivedo in esadecimale quindi 3232323232, giusto?

Si, perché così è stato espressamente ordinato di fare con la riga:

Serial.print(readEEPROM(eeprom, address), HEX);

Ok se io volessi rivedere 22222, come faccio?

Se rimandi al monitor seriale i byte così come sono riappaiono i 22222:

for(address = 0; address<5; address++) 
{
  Serial.write(readEEPROM(eeprom, address)); 
}
Serial.println();

Ma non è il valore ventiduemiladuecentoventidue inteso come valore contenuto in una variabile, è una stringa di cinque caratteri.

ma ottengo 32767

La funzione pow(32, 16), cioè 32 elevato alla 16, genera un valore float talmente
elevato (pari a 1208925819614629174706176) da non essere contenibile in nessuna variabile,
la successiva conversione in intero setta la variabile intera
al massimo valore positivo rappresentabile, che per una int è
appunto 32767.

In pratica dovrei riconvertire ASCII o HEX in intero giusto?

Primo non c'è nessun esadecimale di mezzo (a parte la visualizzazione sul monitor seriale perché così voleva fare chi ha scritto quel codice), e secondo non è un dovere ma è una scelta. Se vuoi memorizzare i tuoi valori sotto forma di stringhe di caratteri ASCII allora si, bisogna convertire avanti e indietro. Se ti basta salvare direttamente i byte dei tuoi valori così come sono allora non c'è nessuna conversione da fare, solo scomporre i valori nei singoli byte e ricomporli.

Un intero (INT) sono solo due byte, e ci sono le funzioni già pronte highByte e lowByte per ottenere i due byte.

Si possono ottenere anche per via aritmetica:

byte h = n / 256;
byte l = n % 256;

oppure logica:

byte h = n >> 8;
byte l = n & 0xFF;

E li ricomponi per via aritmetica:

int n = (int)h*256 + l;

oppure logica:

int n = (int)h<<8 | l;
1 Like

Niente lo leggevo come una variabile, per questo andavo in errore, in pratica ho seguito un tutorial sbagliato, e me serviva un tutorial per memorizzare i dati di una variabile che ottengo tramite il calcolo di un'equazione, tale variabile potrà avere un valore compreso tra 1 e 4 cifre intere.

A prescindere dal tutorial, devo trovare la spiegazione e provare almeno per sapere come lavorano.

ti posso continuare a chiedere consigli, in caso avessi difficolta nel capire come impostare lo sketch che fa per me?

Buona giornata :slight_smile:

@Claudio_FF ho trovato un tutorial con cui si può memorizzare 1 byte sulla eeprom esterna, ora teoricamente, correggimi se sbaglio, io per memorizzare una variabile intera da 1 a 4 cifre dovrei usare 2 byte giusto?

Quindi se a questo sketch aggiungo un ciclo for e scompatto la variabile in singoli byte con lo stesso principio di come lui lo divide in MSB e LSB, usando la funzione ">>" e & potrei risolvere?
Ovviamente in fase di lettura devo ricompattare quindi invece di usare ">>" userò "<<" se ho capito bene come funziona questo comando, ovviamente mi deve ritornare la somma della lettura dei vari indirizzi.

Che dici possibile come soluzione?
Devo capire meglio alcuni punti e poi provo

Questo è lo sketch del tutorial:

#include <Wire.h>
#define disk1 0x50

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

  unsigned int addr = 0;
  Serial.println("scrivo la EEPROM");
  writeEEPROM(disk1, addr, 123);
  Serial.println("leggo la EEPROM");
  int n = readEEPROM(disk1, addr);
  Serial.println(n);
}

void loop() {}

void writeEEPROM(int i2caddr, unsigned int maddr, byte data){
  Wire.beginTransmission(i2caddr);
  Wire.write((int)(maddr >> 8));
  Wire.write((int)(maddr & 0xFF));
  Wire.write(data);
  Wire.endTransmission();
  delay(5);
}

byte readEEPROM(int i2caddr, unsigned int maddr){
  Wire.beginTransmission(i2caddr);
  Wire.write((int)(maddr >> 8));
  Wire.write((int)(maddr & 0xFF)); 
  Wire.endTransmission();

  Wire.requestFrom(i2caddr, 1);
  byte rdata = 0;
  if (Wire.available()) {
     rdata = Wire.read(); 
  }
  return rdata;
}

Non ho capito la necessità del ciclo for. I due byte di un INT si possono scomporre usando uno dei tre modi che ho indicato, come si vede anche dentro le funzioni che hai postato per suddividere l'indirizzo 'maddr' a 16 bit in due byte a 8 bit.

Ci devo lavorare, durante la settimana ho poco tempo, vediamo che riesco a fare nei ritagli di tempo e ti aggiorno :wink:

Penso di aver risolto, non guardare la variabile, ho semplicemnte creato una piccola equazione, visto che nello sketch finale L sarà il volume di un solido che può variare in base all'altezza letta.

ho provato con highbyte e lowByte, ma mi confondo sulla parte successiva, cioè capisco come lavorano per la suddivisone della variabile in byte, ma non capisco come impostare la parte di scrittura, quindi ho portato aventi l'idea del for, sicuramente più complessa ma mi riesce più facile come ragionamento, almeno per la mia mente contorta :sweat_smile:

sembra funzionare, inoltre penso che tramite il for se volessi aumentare i byte potrei farlo aumentando la parte "(variabile >> 8) & 0xFF)" in >> 16 ... >>24 ecc ecc fino al riempimento della memoria ovviamente.

ti ringrazio ancora per gli spunti che mi hai dato, che mi hanno dato l'input per sviluppare lo sketch, ero bloccato completamente :blush:

#include <Wire.h>
#define chip 0x50   //indirizzo chip EEPROM
int L = ((20*1000)/10)+300;

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

  unsigned int indirizzo = 0;
  Serial.println("scrivo la EEPROM");
  scritturaEEPROM(chip, indirizzo, L);   //(indirizzo chip, indirzzo memoria, variabile)
  Serial.println("leggo la EEPROM");
  int n = letturaEEPROM(chip, indirizzo); //(indirizzo chip, indirzzo memoria)
  Serial.println(n);
}

void loop() {}

void scritturaEEPROM(int ind_chip, unsigned int posizione, int variabile) {
  Wire.beginTransmission(ind_chip);

// suddivisione del dato in byte
  byte divisione_variabile[2] = { (variabile & 0xFF),
                                 ((variabile >> 8) & 0xFF)};

// collocazione nella epprom dei byte
  Wire.write((int)(posizione >> 8));   // MSB
  Wire.write((int)(posizione & 0xFF)); // LSB
  for (byte x = 0; x < 2; x++){
    Wire.write(divisione_variabile[x]);
  }
  Wire.endTransmission();
  delay(5);
}
long letturaEEPROM(int ind_chip, int posizione) {
  int unione_variabile[2];
  for (byte x = 0; x<2; x++){
    Wire.beginTransmission(ind_chip);
    Wire.write((int)((posizione + x) >> 8));   // MSB
    Wire.write((int)((posizione + x) & 0xFF)); // LSB
    Wire.endTransmission();
    Wire.requestFrom(ind_chip,1);
    if (Wire.available()) unione_variabile[x] = Wire.read();
  }
return ((unione_variabile[0] << 0) & 0xFF) + ((unione_variabile[1] << 8) & 0xFFFF);
}