chiarimenti EEPROM

salve a tutti

stavo giochicchiando con la eeprom volendo scrivere un array di byte per poi ricaricarla al “riavvio”;
sembrava una cosa semplice e invece mi sono bloccato;

union eepr{
struct prova{

float a = 40;
float b = 40.5;
int c = 4;
} pro;
byte arr[20];
}prov;

for (byte i = 0; i < sizeof(prov.arr); i++){
addr = 0 + i;
  EEPROM.writeByte(addr,prov.arr[i];

}

al riavvio:

for (byte i = 0 ; i < sizef(prov.arr); i++){

addr = 0 + i ;
prov.arr[i] = EEPROM.readByte(addr);
}

ma da seriale i valori sono sempre = 0;

che sbaglio ?

Senza complicarti la vita puoi usare il metodo Put

fabpolli:
Senza complicarti la vita puoi usare il metodo Put

il problema non è nella scrittura ( nel mio programma scrivo prima tutte le celle = 0,salvo i dati della union e poi madno il contenuto via seriale): i dati ci sno sulla eeprom

è che non li carica (correttamente ? ) nella UNION;(presumo)

Ma la domanda è a scopo di studio o stai realizzando qualcosa di pratico? Perché se è la seconda e guardi nel link, troverai anche il metodo get che assieme ti permettono di leggere e scrivere la struttura in EEPROM senza problemi.
Come fai a dire che i dati ci sono in EEPROM se al riavvio leggendoli trovi tutti a zero?

Scusa, ma invece di postare pezzi di codice, che sicuramente non funzionano per altri motivi, perchè non posti l'intero programma o almeno un programmino di test completo?

Inoltre, che libreria stai usando, visto che quella "standard" (EEPROM.h) non mi pare contenga i metodi "readByte" e "writeByte"?

Federico

non so perche ma pensavo di averlo scritto all’inizio, cmq sono su un esp32

l codice per intero è in effetti una prova… .sto cercando di capirci qualcosa…

#include "EEPROM.h"
#define EEPROM_SIZE 512

int addr = 0;

union eepr{
struct prova{

float a ;
float b  ;
int c ;
unsigned long d  ;
} pro;
byte arr[20];
}prov;




void setup() {
  Serial.begin(115200);
  Serial.println("start...");
  if (!EEPROM.begin(EEPROM_SIZE)){
   Serial.println("failed to initialise EEPROM");
   delay(1000000);}
  Serial.println(" bytes read from Flash . Values are:");
  for (int i = 0; i < EEPROM_SIZE; i++)
  {
    Serial.print(byte(EEPROM.read(i))); Serial.print(" ");
  }
  Serial.println("----------------------------------");
delay(15000);  //tempo per guardarecontento eeprom all'avvio
if (EEPROM.read(0) == 0 ){ // se è la prima volta che fai il setup....
    Serial.println("---- scrivo struct ------");
    prov.pro.a = 26;
    prov.pro.b = 26.5;
    prov.pro.c = 40;
    prov.pro.d = 6000;

    for (byte i = 0 ; i < sizeof(prov.arr); i ++ ){
     addr = 0 + i;
      EEPROM.writeByte(addr, prov.arr[i]);
    }
    EEPROM.write(0,1);  // .....la prossima volta andrai a loop
    EEPROM.commit();
} else{
       Serial.println("---- leggo struct ------");
    for (byte i = 0 ; i < sizeof(prov.arr); i ++ ){
     addr = 0 + i;
      EEPROM.readByte(addr);
    }      
    }
                        
}

void loop() {
Serial.println("----------LOOP-------------");
    Serial.print(EEPROM_SIZE);
    Serial.println(" bytes Flash, Values are:");
    for (int i = 0; i < EEPROM_SIZE; i++)
    {
      Serial.print(byte(EEPROM.read(i))); Serial.print(" ");
    }
    Serial.println(); Serial.println("----------------------------------");
  delay(100);

Serial.println(prov.pro.a);
Serial.println(prov.pro.b);
Serial.println(prov.pro.c);
Serial.println(prov.pro.d);


Serial.println("SE non mi resetti entro 20 secondi formattero la EEPROM");

delay(20000);
for (int i = 0; i < EEPROM_SIZE; i++)
    {
     EEPROM.writeByte(i, 0);
    }
    Serial.println(); Serial.println("----------fatto!-------------");
  
EEPROM.writeByte(0,0);
EEPROM.commit();
delay(5000);

ESP.restart();/**/
  
}

Non ho mai lavorato con l’ESP32 ma questo pezzo di codice nel setup secondo me ha un problema logico, tu fai:

for (byte i = 0 ; i < sizeof(prov.arr); i ++ ){
     addr = 0 + i;
      EEPROM.writeByte(addr, prov.arr[i]);
    }
    EEPROM.write(0,1);  // .....la prossima volta andrai a loop

In questo modo parti a scrivere i dati dell’array prov.arr dalla cella zero, fuori dal for sovrascrivi il primo valore scritto con 1.
Inoltre questi valori:

prov.pro.a = 26;
prov.pro.b = 26.5;
prov.pro.c = 40;
prov.pro.d = 6000;

non li scrivi mai in EEPROM, scrivi solo i valodi dell’array che se non erro non sono mai stati inizializzati quindi ci sta che in effetti contengano zero.
e fai eseguire la scrittura in EEPROM, poi successivamente senza resettarla fai ripartire il tutto cosa leggi?
Edit: Ho detto una cavolta è una union non una struct, avevo scordato questo dettaglio

mixmax122:
non so perche ma pensavo di averlo scritto all'inizio, cmq sono su un esp32

mannaggia... era la prima cosa che dovevi dire :wink:

Concordo con @fabpolli, non mi pare che prov.arr venga inizializzata con qualcosa di diverso da zero!

Curiosità:
vedo che per scrivere usi "EEPROM.writeByte" poi per leggere a volte "EEPROM.read" altre "EEPROM.readByte", sono equivalenti?

Federico

fabpolli:
Edit: Ho detto una cavolta è una union non una struct, avevo scordato questo dettaglio

non ti seguo!

quando scrive

  \...
  EEPROM.writeByte(addr, prov.arr[i]);
  \...

non mi pare prov.arr abbia un valore > 0, oppure ho preso un abbaglio? ::slight_smile:

Federico

Federico66:
non mi pare prov.arr abbia un valore > 0, oppure ho preso un abbaglio? ::slight_smile:

Federico

Guarda non sono ferrattissimo nell'argomento union e tra l'altro usare una union con una struct complica ancora di più la cosa e non capisco dove si voglia arrivare con tale codice, comunque un esempio facicle facile di come funziona una union può essere questo che è abbastanza chiaro nel descrivere che di fatto gli elementi della union condividono le medesime posizioni in memoria e che praticamente puoi accedere a una di essa per volta, quando assegni il valore di fatto sovrascrivi quello degli altri elementi della union.
Da quel che so la union con i puntatori a due o più struct serve nei casi in cui solo una per volta delle struct interne alla union è di fatto utilizzata, quindi definendola come union risparmi spazio in memoria, usarne solo una per me non ha molto senso, ma non essendo pratico dell'argomento potrei (e quasi sicuramente lo sto facendo) errare.
Aspetto i più esperti o l'OP che chiarisca il motivo dell'uso della union con una sola struct.

Concordo con fabpolli .

Se usi un unione, viene utilizzato come dimensione quello del dato più grande in byte, in questo caso vengono usati 20 byte di memoria, e questo per salvarci di volta in volta i membri dell'unione, su questi byte esiste solo il valore dell'ultimo membro che hai usato.

  1. Uso i 20 byte per salvare i valori della struct
  2. Su questi 20 byte scrivo gli elementi dell'array non inizializzato
    3)Non ho più i valori della struct perché sovrascritti

Ragionandoci forse lo scopo dell'OP è forse creare un array di struct? :o

Poi un unione personalmente non so dove possa servire !? Mantiene in memoria l'ultimo dato inserito "perdendo" gli altri, è un po come una singola variabile che può contenere tipi di dato diverso.

guarda (mi rivolgo al releaser originale)
stamattina ho visto questo pezzo di codice e mi sono "astenuto" dall'andare oltre

union eepr{
struct prova{

float a = 40;
float b = 40.5;
int c = 4;
} pro;
byte arr[20];
}prov;

a prima vista non si capisce cosa faccia parte della union e cosa della struct,
ho pensato: io nella mia cassetta dei ferri tengo maggior ordine ai pezzi di ferro che qui ai byte

e ho lasciato stare

poi però la noia (e i morsi del dolore al piede) hanno risvegliato il mio interesse:

1 manca una parentesi, come fara' a funzionare mi domando

2 un po' in disordine, con calcoli fantasiosi (zero più X fa sempre e solo X, mai altro)

3 idea strana quella di usare una union di una strcut, comunque a parte gli errori di digitazione dovrebbe andare

e all'ora perchè non va?

ho cercato degli esempi, facili da trovare
la ESP32 richiede un comando in più per usare la eeprom il comando commit(), al termine delle modifiche

PS
il primo messaggio mi era scappato un punto, lo stavo editando, ma qualcuno lo ha cancellato?
è una sola coriosità

torn24:
Concordo con fabpolli .

fabpolli:
Guarda non sono ferrattissimo nell'argomento union e tra l'altro usare una union con una struct complica...

Grazie

Quindi se ho capito bene, in ogni istante o ci sono dati in struct prova o nell'array prov e quindi se assegna i valori alla struttura e poi legge l'array, quest'ultimo non conterrà dati, o meglio non conterrà dati plausibili.

Federico

lo penso nch'io

però non è prprpio stupida come cosa

si potrebbe usare una union di un array di byte grande esattamente come la dimensione della struttura

e indirizzare i singoli byte della struttura, ad esempio per salvarli in eeprom
senza usare i puntatori
come dice il barr group, che mi hanno fatto leggere all'inizio dell'anno (brutta figura, ricordo)

non usare puntatori ma indici di array

Federico66:
Grazie

Quindi se ho capito bene, in ogni istante o ci sono dati in struct prova o nell'array prov e quindi se assegna i valori alla struttura e poi legge l'array, quest'ultimo non conterrà dati, o meglio non conterrà dati plausibili.

Federico

Sulla plausibilità del dato dipende da come costruisci la union, cercando di capirne di più ho trovato quest'esempio:

    union u_test {
        int  i;
        char s[4];
    } my_test;

    my_test.i = 0x01020304;

    printf("s[0]=%d s[1]=%d s[2]=%d s[3]=%d\n", my_test.s[0], my_test.s[1], my_test.s[2], my_test.s[3]);

Vedi che valorizza i ma poi stampa i singoli elementi dell'array s, ebbene funziona ma ha una peculiarità, memorizza i valori dal meno significativo al più significativo ovvero in s[0] hai 4 e in s[3] hai 1, provato su PC non so se il compilatore di Arduino si comporta al medesimo modo (direi di si), sono rimasto un po "ubriacato" dalla questione

fabpolli:
Vedi che valorizza i ma poi stampa i singoli elementi dell'array s, ebbene funziona ma ha una peculiarità, memorizza i valori dal meno significativo al più significativo ovvero in s[0] hai 4 e in s[3] hai 1, provato su PC non so se il compilatore di Arduino si comporta al medesimo modo (direi di si), sono rimasto un po "ubriacato" dalla questione

Ti rammento che su Arduino (probabilmente, al contrario che sul tuo PC, dove saranno a 32 bit), gli 'int' sono a 16 bit e sono appunto memorizzati in "little-endian" ... ::slight_smile:

Guglielmo

fabpolli:
Sulla plausibilità del dato dipende da come costruisci la union, cercando di capirne di più ho trovato

Visto, ma devo digerirlo, faccio fatica a capirlo solo leggendolo :slight_smile:

Nel frattempo ho fatto una prova su Arduino con l’esempio dell’OP:

union eepr {
  struct prova {
    float a ;
    float b  ;
    int c ;
    unsigned long d  ;
  } pro;
  byte arr[20];
} prov;

void setup() {
  Serial.begin(9600);
  
  Serial.println("=> inizializzo struttura");
  prov.pro.a = 26;
  prov.pro.b = 26.5;
  prov.pro.c = 40;
  prov.pro.d = 6000;

  Serial.println("=> inizializzo array");
  for (byte i = 0 ; i < sizeof(prov.arr); i ++ ) {
    prov.arr[i] = sizeof(prov.arr) - i;
  }
  Serial.println("=> leggo entrambi");
  Serial.print("prov.pro.a = ");Serial.println(prov.pro.a);
  Serial.print("prov.pro.b = ");Serial.println(prov.pro.b);
  Serial.print("prov.pro.c = ");Serial.println(prov.pro.c);
  Serial.print("prov.pro.d = ");Serial.println(prov.pro.d);
  Serial.println("======================");
  for (byte i = 0 ; i < sizeof(prov.arr); i ++ ) {
    Serial.print("prov.arr[");Serial.print(i);Serial.print("] = ");Serial.println(prov.arr[i]);
  }
  Serial.println("======================");

  Serial.println("=> inizializzo struttura");
  prov.pro.a = 26;
  prov.pro.b = 26.5;
  prov.pro.c = 40;
  prov.pro.d = 6000;
  Serial.println("=> leggo entrambi");
  Serial.print("prov.pro.a = ");Serial.println(prov.pro.a);
  Serial.print("prov.pro.b = ");Serial.println(prov.pro.b);
  Serial.print("prov.pro.c = ");Serial.println(prov.pro.c);
  Serial.print("prov.pro.d = ");Serial.println(prov.pro.d);
  Serial.println("======================");
  for (byte i = 0 ; i < sizeof(prov.arr); i ++ ) {
    Serial.print("prov.arr[");Serial.print(i);Serial.print("] = ");Serial.println(prov.arr[i]);
  }
}

void loop() {}

l’esito come previsto è

=> inizializzo struttura
=> inizializzo array
=> leggo entrambi
prov.pro.a = 0.00
prov.pro.b = 0.00
prov.pro.c = 2828
prov.pro.d = 117967114

prov.arr[0] = 20
prov.arr[1] = 19
prov.arr[2] = 18
prov.arr[3] = 17
prov.arr[4] = 16
prov.arr[5] = 15
prov.arr[6] = 14
prov.arr[7] = 13
prov.arr[8] = 12
prov.arr[9] = 11
prov.arr[10] = 10
prov.arr[11] = 9
prov.arr[12] = 8
prov.arr[13] = 7
prov.arr[14] = 6
prov.arr[15] = 5
prov.arr[16] = 4
prov.arr[17] = 3
prov.arr[18] = 2
prov.arr[19] = 1

=> inizializzo struttura
=> leggo entrambi
prov.pro.a = 26.00
prov.pro.b = 26.50
prov.pro.c = 40
prov.pro.d = 6000

prov.arr[0] = 0
prov.arr[1] = 0
prov.arr[2] = 208
prov.arr[3] = 65
prov.arr[4] = 0
prov.arr[5] = 0
prov.arr[6] = 212
prov.arr[7] = 65
prov.arr[8] = 40
prov.arr[9] = 0
prov.arr[10] = 112
prov.arr[11] = 23
prov.arr[12] = 0
prov.arr[13] = 0
prov.arr[14] = 6
prov.arr[15] = 5
prov.arr[16] = 4
prov.arr[17] = 3
prov.arr[18] = 2
prov.arr[19] = 1

quindi, conferma che posso leggere correttamente solo il membro appena editato.
L’altro membro contiene sicuramente dati, visto che occupa lo stesso spazio di memoria, ma non sono utilizzabili, almeno per me :slight_smile:

Federico

non mi aspettavo tanti interventi, ci ho messo un po a leggerli…

allora come rpima cosa ho corretto l’errore logico della “addr”

#include "EEPROM.h"
#define EEPROM_SIZE 512

int addr = 50;

union eepr{
struct prova{

float a ;
float b  ;
int c ;
unsigned long d  ;
} pro;
byte arr[20];
}prov;




void setup() {
  Serial.begin(115200);
  Serial.println("start...");
  if (!EEPROM.begin(EEPROM_SIZE)){
   Serial.println("failed to initialise EEPROM");
   delay(1000000);}
  Serial.println(" bytes read from Flash . Values are:");
  for (int i = 0; i < EEPROM_SIZE; i++)
  {
    Serial.print(byte(EEPROM.read(i))); Serial.print(" ");
  }
  Serial.println("----------------------------------");
delay(15000);  //tempo per guardarecontento eeprom all'avvio
if (EEPROM.read(0) == 0 ){ // se è la prima volta che fai il setup....
    Serial.println("---- scrivo struct ------");
    prov.pro.a = 26;
    prov.pro.b = 26.5;
    prov.pro.c = 40;
    prov.pro.d = 6000;

    for (byte i = 0 ; i < sizeof(prov.arr); i ++ ){
     addr +=  i;
      EEPROM.writeByte(addr, prov.arr[i]);
    }
    EEPROM.write(0,1);  // .....la prossima volta andrai a loop
    EEPROM.commit();
} else{
       Serial.println("---- leggo struct ------");
    for (byte i = 0 ; i < sizeof(prov.arr); i ++ ){
     addr = 0 + i;
      EEPROM.readByte(addr);
    }      
    }
                        
}

void loop() {
Serial.println("----------LOOP-------------");
    Serial.print(EEPROM_SIZE);
    Serial.println(" bytes Flash, Values are:");
    for (int i = 0; i < EEPROM_SIZE; i++)
    {
      Serial.print(byte(EEPROM.read(i))); Serial.print(" ");
    }
    Serial.println(); Serial.println("----------------------------------");
  delay(100);

Serial.println(prov.pro.a);
Serial.println(prov.pro.b);
Serial.println(prov.pro.c);
Serial.println(prov.pro.d);


Serial.println("SE non mi resetti entro 20 secondi formattero la EEPROM");

delay(20000);
for (int i = 0; i < EEPROM_SIZE; i++)
    {
     EEPROM.writeByte(i, 0);
    }
    Serial.println(); Serial.println("----------fatto!-------------");
  
EEPROM.writeByte(0,0);
EEPROM.commit();
delay(5000);

ESP.restart();/**/
  
}

usare una struct annidata in una union ha senso quando vuoi trasferire i dati della struct ad arduino(ad esempio). Che sia via seriale o via I2c qualunque dato, deve essere prima scomposto in byte poi trasferito e infine assemblato dall’altro controllore. se questo contiene la stessa union/struct, una volta copiata l’array di byte, i dati saranno automaticamente aggiornati nella struct e pronti per essere utilizzati;
potrei farlo manualmente ? SI, ma perche quando la union è piu efficiente e lo fa in meno cicli ?

questo programma per quanto la EEPROM sia ormai “superata” ha un compito semplicissimo: deve riprendere il programma da dove aveva interrotto in caso di interruzione di corrente:
durante il primo setup scrivo il byte all’address 0 con 1; in caso di riavvio il setup lo legge e va direttamente al loop;
Se il programma invece viene portato a termine scrivo il byte in pos 0 con 0 e riavvio il controllore; al riavvio il setup leggerà il byte 0 e inserirà nella struct i dati pre-definiti;

da notare ce il byte in pos 0 puo assumere max 256 valori che equivalgono a 256 programmi pre-definiti