Problemino con scrittura su SD da EEPROM

Ho scritto uno schetchino per leggere i dati da una EEPROM 24c04 e scriverli in formato esadecimale formattati in 16 byte per riga.

Il programma funziona perfettamente se lo faccio scrivere sulla seriale, ma perqualche ragione non scrive su SD, o meglio scrive tutti ZERO, però formattati correttamente.

Vi allego il sorgente:

#include <Wire.h>
#include <SD.h>
#define EEPROM_address 0x50       // 24c04 i2c Address is HEX 50

unsigned int max_address=511, data_address=0;
byte data, i;
File dump_file;

void setup(void)
{
  // if (digitalRead(2)) {max_address = 255;}   // 24c02
  // if (digitalRead(3)) {max_address = 511;}   // 24c04
  // if (digitalRead(4)) {max_address = 1023;}   // 24c08
  // if (digitalRead(5)) {max_address = 2047;}   // 24c16
  Serial.begin(115200);
  pinMode(10, OUTPUT);
  Wire.begin();
  i = 0;
  if (!SD.begin(10)) {
    Serial.println("SD Card Error !\nCheck SD Card and Reset");
    while(1);
  }
  Serial.println("SD Card Ready !");
  Serial.println("Dumping Data...");
}


void loop()
{  
  for (data_address = 0 ; data_address <= max_address ; data_address + 1)
  {  
   byte data = data_read(EEPROM_address, data_address);
   SD_write();
   if (data_address == max_address) {Serial.print("Memory Dumped on SD"); while(1);}
  }
}


void SD_write()
{
  dump_file = SD.open("Dump.txt", FILE_WRITE);
  if(data < (10, HEX)) dump_file.print("0");
  dump_file.print(data, HEX);
  i = i + 1;
  if(i == 16){dump_file.println(""); i = 0;}
  dump_file.close();
}
  

byte data_read(int device_address, unsigned int cell_address ) 
{
  byte cell_data = 0xFF;
  Wire.beginTransmission(device_address);
  Wire.write(cell_address);
  Wire.endTransmission();
  Wire.requestFrom(device_address,1);
  if (Wire.available()) cell_data = Wire.read();
  return cell_data;
}

SD_write();
che deve scrivere?
prova a guardare questo esempio :wink:

:smiley: troppa fretta, non avevo visto che era una funzione :slight_smile:

occhio che la tua funzione fa questo...
in quanto l'if senza parentesi esegue una sola istruzione

if(data < (10, HEX)) {     //--< questo non credo che funzioni...
  dump_file.print("0");
} 
dump_file.print(data, HEX);
i = i + 1;

penso che tu volessi fare:

if(data < 0x0A) {     //--< valore 10 esadecimale
   dump_file.print("0");
} else {
   dump_file.print(data, HEX);
}
i = i + 1;

No no, invece quella è l'unica cosa che mi funziona bene. In sostanza qull' IF fa in modo che se la cifra è minore di 10 quindi un numero a una sola cifra, venga anteposto uno ZERO per formattare correttamente il testo e facilitare un seguente rilettura. in sostanza 1 diventa 01, 2 diventa 02, etc, etc.

Il problema è che il file.print(data, HEX) mi printa sempre ZERO, mentre dovrebbe restituirmi il valore della cella di memoria (che è a 8 bit) quindi un valore da 0 a 255, o meglio visto che lo stampo in HEX da 0 a FF.

La cosa funziona perfettamente se lo stampo sulla seriale, ma qui per qualche motivo mi da ZERO... boh...

Hai due variabili data, e quella locale al loop() nasconde quella globale, che quindi non viene mai alterata.

Togli quella locale o, meglio, passa il valore da scrivere come parametro a SD_write().

PS: L'if di cui parla Patrick è effettivamente da correggere, dagli retta.

Ma che pirla... hai ragione. In sostanza ho aggiunto di nuovo byte prima di data che ridefinise la variabile.

Darò un occhio anche alla if se dite che non va bene. Però per qualche ragione funziona ugualmente. Probabilmente fortuna.

Grazie raga

In realtà non funziona nemmeno come deve, perché HEX vale 16 e:

In the C and C++ programming languages, the comma operator (represented by the token ,) is a binary operator that evaluates its first operand and discards the result, and then evaluates the second operand and returns this value (and type).

SukkoPera:
In realtà non funziona nemmeno come deve, perché HEX vale 16 e:

in realtà proprio grazie all'inserimento della virgola "casualmente" fa esattamente quello che l'OP voleva cioè aggiungere lo zero se la cifra è minore di 16 esadecimale :smiley:

cambia la if così e funzionerà uguale

if(data < 0x10)  //se data < di 16 esadecimale

Allora, con ordine:

L' IF funziona come l'ho scritto prima, dopo la modifica non funziona piu, ho fatto un pò di prove e pare che voglia per forza la specifica ", HEX" dopo il valore, che va racchiuso tra parentesi tonde. Poi posso scriverlo in decimale o esadecimale (probabilmente pure in binario) ma comunque VUOLE che sia specificato il formato di uscita (e in effetti ha senso).

In pratica come l'ho scritto io printa questo:

SD Card Ready !
Dumping Data...
000102030405060708090A0B0C0D0E0F
101112131415161718191A1B1C1D1E1F
202122232425262728292A2B2C2D2E2F
30Memory Dumped on SD !

L'altra che avete proposto invece printa questo:

SD Card Ready !
Dumping Data...
00010203040506070809ABCDEF
101112131415161718191A1B1C1D1E1F
202122232425262728292A2B2C2D2E2F
30Memory Dumped on SD !

In sostanza non riconosce le lettere come maggiori di 10, probabilmente perchè manca la formattazione come esadecimale. E questa è una.

Detto questo, il programma continua ad andare bellamente fregandosene del controllo FOR... mi sono chiesto perchè e sembrerebbe che nel ciclo FOR faccia differenza se scrivo valore++ o valore + 1, in particolare con quest'ultimo pare non funzionare e resta sempre a zero (posto che l'ho inizializzata a zero).
La cosa mi disturba, non ne capisco il perchè...

Detto questo... Funzionaaaa ! ! !

Ora leggendo i primi 256 registri di una memoria (corrispondente ad una 24c02), mi salva il contenuto della memeoria in dump.txt sulla scheda SD, formattato correttamente in 16 righe da 16 byte. La memoria è stata precedentemente scritta con valori incrementali da 0 a 255. Il risultato è questo:

000102030405060708090A0B0C0D0E0F
101112131415161718191A1B1C1D1E1F
202122232425262728292A2B2C2D2E2F
303132333435363738393A3B3C3D3E3F
404142434445464748494A4B4C4D4E4F
505152535455565758595A5B5C5D5E5F
606162636465666768696A6B6C6D6E6F
707172737475767778797A7B7C7D7E7F
808182838485868788898A8B8C8D8E8F
909192939495969798999A9B9C9D9E9F
A0A1A2A3A4A5A6A7A8A9AAABACADAEAF
B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF
C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF
D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF
E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF

Abbiamo postato nello stesso momento... Ho letto cio che avete scritto e non ho ben capito la faccenda dell'IF, cioè... che vol di ? Nel senso il discorso che il C e C++ la virgola etc etc...

Vi posto il codice funzionante per completezza, è ancora grezzo, una volta finito la seriale sparirà lasciando posto a pulsanti e led per rendere il dispositivo stand-alone, andranno gestiti i file e altre cose, forse un display:

#include <Wire.h>
#include <SD.h>
#define EEPROM_address 0x50       // 24cXX i2c Address is HEX 50, as for most memories

unsigned int max_address=255, data_address=0;
byte data, i;
File dump_file;

void setup(void)
{
  // if (digitalRead(2)) {max_address = 255;}   // 24c02
  // if (digitalRead(3)) {max_address = 511;}   // 24c04
  // if (digitalRead(4)) {max_address = 1023;}   // 24c08
  // if (digitalRead(5)) {max_address = 2047;}   // 24c16
  Serial.begin(115200);
  pinMode(10, OUTPUT);
  Wire.begin();
  i = 0;
  if (!SD.begin(10)) {
    Serial.println("SD Card Error !\nCheck SD Card and Reset");
    while(1);
  }
  Serial.println("SD Card Ready !");
  Serial.println("Dumping Data...");
}


void loop()
{  
  for (data_address = 0 ; data_address <= max_address ; data_address++)
  {  
   data = data_read(EEPROM_address, data_address);
   SD_write();
   if (data_address == max_address) {Serial.print("Memory Dumped on SD !"); while(1);}
  }
}


void SD_write()
{
  dump_file = SD.open("dump.txt", FILE_WRITE);
  if(data < (0x0A, HEX)){dump_file.print("0");}
  dump_file.print(data, HEX);
  i = i + 1;
  if(i == 16){dump_file.println(""); i = 0; Serial.print("/");}
  dump_file.close();
}
  

byte data_read(int device_address, unsigned int cell_address )
{
  byte cell_data = 0xFF;
  Wire.beginTransmission(device_address);
  Wire.write(cell_address);
  Wire.endTransmission();
  Wire.requestFrom(device_address,1);
  if (Wire.available()) cell_data = Wire.read();
  return cell_data;
}

SukkoPera:
In realtà non funziona nemmeno come deve, perché HEX vale 16 e:

ma quello non è mica l'operatore virgola, è il separatore di argomento di funzione....
Ops lessi di fretta, porgo le mie scuse

Vuol dire che quella sintassi non ha alcun senso in un if (in una print sì), te la sei inventata tu e funziona PER PURO CASO. Fai semplicemente if (data < 16).

Scusa ma non ho capito bene.. Tu fai:

if(data < (0x0A, HEX)){dump_file.print("0");}
 dump_file.print(data, HEX);

Lo fai perché quando vuoi visualizzare un valore esadecimale ad una cifra aggiungi giustamente uno zero.

Ma quella sintassi NON ESISTE, come ti hanno fatto notare, e ti funziona solamente perché la costante "HEX" vale, appunto, 16!! Se non ci credi, prova a fare:
Serial.println(HEX);

Ma vorrei anche sottolineare che lo "0" lo devi mettere prima di valori ad una cifra ESADECIMALE quindi tra 0 ed F (15). tu hai scritto 0x0A che vale 10 (decimale) e che è sbagliato! Devi farlo per valori non minori di 10, ma di 0x10 ESADECIMALE ossia 16!

Per cui per fare le cose correttamente tu DEVI fare:

if(data < 16){dump_file.print("0");}
 dump_file.print(data, HEX);

Si è vero GRAZIE per l'aiuto, provato e funge. Effettivamente è sensato, svarione mio. Però che C....uore che funzionava lo stesso ah ah ah. Sul serio, grazie ancora per avermi fatto notare la gran cavolata che stavo facendo.

Alla fine dai non è venuto cosi malvagio, funziona benino. Ma secondo voi è normale che è cosi lento, cioè per scaricare un mezzo kilobyte ci mette tipo un minuto. Sembra proprio che sia la gestione della SD che porta via tempo, perchè sulla seriale è molto veloce, roba di un secondo o giu di li. Va boh, prenderò un caffe nel frattempo.

Spero che possa tornare utile a qualcuno se gli servisse.
Appena posso vorrei fare il contrario, cioè scrivere sulla EEPROM esterna da un file sulla SD; a volte è comodo non dover avere il pc collegato, soprattutto se devi programmare diverse EEPROM di fila.
Magari ci starebbe bene pure una verifica della scrittura, ma per ora c'è gia molta carne al fuoco.

dukeluca86:
Ma secondo voi è normale che è cosi lento, cioè per scaricare un mezzo kilobyte ci mette tipo un minuto. Sembra proprio che sia la gestione della SD che porta via tempo, perchè sulla seriale è molto veloce, roba di un secondo o giu di li.

Eh, certo, perché tu ad OGNI BYTE apri il file, scrivi i due caratteri, e poi richiudi.

Apri il file UNA volta, prima del for(), scrivi, e chiudilo all'uscita del for().

Inoltre tu l'hai messo nel loop(), e per evitare di fare queste cose all'infinito hai messo un controllo che finisce con un loop infinito... Tutto inutile, ti basta metterlo nella setup()!

E magari prima di fare la open() cancella l'eventuale file preesistente, per sicurezza...

Insomma io farei una cosa del genere (scritta al volo, DA PROVARE):

#include <Wire.h>
#include <SD.h>
#define EEPROM_address 0x50       // 24cXX i2c Address is HEX 50, as for most memories

unsigned int max_address=255, data_address=0;
byte data, i;
File dump_file;

void setup(void)
{
  // if (digitalRead(2)) {max_address = 255;}   // 24c02
  // if (digitalRead(3)) {max_address = 511;}   // 24c04
  // if (digitalRead(4)) {max_address = 1023;}   // 24c08
  // if (digitalRead(5)) {max_address = 2047;}   // 24c16
  Serial.begin(115200);
  pinMode(10, OUTPUT);
  Wire.begin();
  i = 0;
  if (!SD.begin(10)) {
    Serial.println("SD Card Error !\nCheck SD Card and Reset");
    while(1);
  }
  Serial.println("SD Card Ready !");
  dumpData();
}


void loop()
{  
}

void dumpData() {
  Serial.println("Dumping Data...");
  if ( SD.exists("dump.txt") )
    SD.delete("dump.txt"");
  dump_file = SD.open("dump.txt", FILE_WRITE);
  for (data_address = 0 ; data_address <= max_address ; data_address++) {
    data = data_read(EEPROM_address, data_address);
    if( data < 0x10 ) {
	  Serial.print("0");
	  dump_file.print("0");
	}
    dump_file.print(data, HEX);
    Serial.print(data, HEX);
    if( (data_address % 16) == 15){
	  dump_file.println(); 
	  Serial.println();
	}
  }
  dump_file.close();
  Serial.println();
  Serial.println("Memory Dumped on SD !");
}


byte data_read(int device_address, unsigned int cell_address )
{
  byte cell_data = 0xFF;
  Wire.beginTransmission(device_address);
  Wire.write(cell_address);
  Wire.endTransmission();
  Wire.requestFrom(device_address,1);
  if (Wire.available()) cell_data = Wire.read();
  return cell_data;
}