Arduino Internal EEPROM READ/WRITE - variabile in formato bouble

Ciao a tutti

ecco come ho risolto la scrittura e la lettura di variabili in formato double all'interno della EEPROM di arduino uno (512byte) che accetta dati solo in formato byte:

dovendo memorizzare dei setpoint in formato double es. 101.23 per poi successivamente rileggerli, ad esempio dopo un reset di arduino, ho messo giù un paio di righe di codice:

#include <EEPROM.h>

int a = 0;

double myvalue = 101.23;
char str_test[] = "     ";

void setup()
{
  Serial.begin(9600);
  Serial.println("Initializing Serial interface...");
  
  a = sizeof(myvalue);
  
  Serial.print("lunghezza variabile myvalue = ");
  Serial.println(a,DEC);
  
  Serial.println(floatToString(str_test, myvalue, 2, 0)); 
  
  a = sizeof(str_test);
  
  Serial.print("lunghezza variabile str_test = ");
  Serial.println(a,DEC);
  for (int i = 0; i < a; i++){
    Serial.print("index of write array: ");
    Serial.print(i);
    Serial.print(" - ");
    Serial.print("value of array: "); 
    Serial.println(str_test[i]);
    EEPROM.write(0+i,str_test[i]);
  }  
}

void loop()
{
  for (int i = 0; i < a; i++){
    Serial.print("index of read array: ");
    Serial.print(i);
    Serial.print(" - ");
    Serial.print("value of array: ");
    str_test[i] = EEPROM.read(0+i);
    Serial.println(str_test[i]);
  }
  Serial.print("letto da EEprom (stringa) =  ");
  Serial.println(str_test);
  myvalue = atof(str_test);
  Serial.print("letto da EEprom (float) =  ");
  Serial.println(floatToString(str_test, myvalue, 2, 0)); 
  delay(2000);
}

//---------------------------------------------------------------------------
char * floatToString(char * outstr, double val, byte precision, byte widthp){
  char temp[16];
  byte i;

  // compute the rounding factor and fractional multiplier
  double roundingFactor = 0.5;
  unsigned long mult = 1;
  for (i = 0; i < precision; i++)
  {
    roundingFactor /= 10.0;
    mult *= 10;
  }
  
  temp[0]='\0';
  outstr[0]='\0';

  if(val < 0.0){
    strcpy(outstr,"-\0");
    val = -val;
  }

  val += roundingFactor;

  strcat(outstr, itoa(int(val),temp,10));  //prints the int part
  if( precision > 0) {
    strcat(outstr, ".\0"); // print the decimal point
    unsigned long frac;
    unsigned long mult = 1;
    byte padding = precision -1;
    while(precision--)
      mult *=10;

    if(val >= 0)
      frac = (val - int(val)) * mult;
    else
      frac = (int(val)- val ) * mult;
    unsigned long frac1 = frac;

    while(frac1 /= 10)
      padding--;

    while(padding--)
      strcat(outstr,"0\0");

    strcat(outstr,itoa(frac,temp,10));
  }

  // generate space padding
  if ((widthp != 0)&&(widthp >= strlen(outstr))){
    byte J=0;
    J = widthp - strlen(outstr);
    
    for (i=0; i< J; i++) {
      temp[i] = ' ';
    }

    temp[i++] = '\0';
    strcat(temp,outstr);
    strcpy(outstr,temp);
  }
  
  return outstr;
}

questo mi permette di convertire un qualsiasi valore da formato double a stringa e viceversa, in questo modo, dato che una stringa non è nient'altro che un array di caratteri, ed un carattere non è nient'altro che un byte, possiamo dedurre che la stringa risultante sia un array di byte che risulta facilmente gestibile sia in lettura che in scrittura sulla EEPROM interna di Arduino Uno.

:slight_smile: :slight_smile: :slight_smile: :slight_smile: :slight_smile: :slight_smile: :slight_smile: :slight_smile:

ottimo! mi sembra una cosa molto utile, perchè non ci fai una libreria?

l' unico errore che mi é saltato all'occhio é che il Arduni UNO monta un ATmega328 che ha 1024 byte di EEprom non 512.
Ciao Uwe

Non per criticare, ma è un procedimento assurdo :slight_smile:
Un float, o un long int, altro non è che un valore composto da 4 byte, pertanto non devi fare altro che leggere singolarmente questi byte e memorizzarli nella EEPROM, per ricomporre il numero fai l'inverso leggi i 4 valori dalla EEPROM e li ricopi nella relativa variabile.
Quanto sopra è fattibile in due modi semplicissimi, il primo tramite i puntatori, il secondo tramite una unione.

Ti metto il link a questa discussione dove è già stato affrontato il problema e dove trovi spiegati ampiamente i due sistemi basati sulla unione e su i puntatori.

Questa cosa è interessante :slight_smile:

Capisco che Arduino ci metta di fronte a un SDK facilissimo, ma quando dobbiamo risolvere problemi sarebbe meglio approfondire...
http://www.nongnu.org/avr-libc/user-manual/group__avr__eeprom.html
Come puoi vedere le funzioni per leggere e scrivere valori float... già ci sono!
Ciao

:slight_smile:
è................. ma così non c'è gusto :smiley:
grazie per la dritta, ma preferisco "sbatterci" un po' la testa e cercare soluzioni "fattibili" con gli strumenti a disposizione (arduino IDE)

terrò comunque in considerazione le funzioni incluse in <avr/eeprom.h> :smiley:

grazie :smiley:

uwefed:
l' unico errore che mi é saltato all'occhio é che il Arduni UNO monta un ATmega328 che ha 1024 byte di EEprom non 512.
Ciao Uwe

hai ragione UWE :stuck_out_tongue: come posso farmi perdonare!!!!! posso scrivere 1024 volte su una lavagna vecchio stile (gesso + cancellino) "ATmega328 = 1024byte di EEPROM"

:smiley: scherzo!

saluti
Kattivik76

kattivik76:
hai ragione UWE :stuck_out_tongue: come posso farmi perdonare!!!!! posso scrivere 1024 volte su una lavagna vecchio stile (gesso + cancellino) "ATmega328 = 1024byte di EEPROM"
:smiley: scherzo!
saluti
Kattivik76

Se ti fa piacere e non gratti col gesso sulla lavagna ...

e poi non fa piú piacere di chiedere qualcosa che Ti coprono di proposte migliorative che Tu non avevi chiesto ... chiedi una A e Ti danno un enciclopedia, é ingiusto ...

scherzo anch io.
Ciao Uwe

Ciao,

su vostro consiglio ho lavorato un po' sul codice per aggiustare il tiro in merito all'estetica del codice stesso, direi che i risultati si notano, e molto :stuck_out_tongue:

ho utilizzato la libreria <avr/eeprom.h> e le funzioni:

  • void eeprom_read_block (const void * __src, void * __dst, size_t __n)
  • void eeprom_write_block (const void * __src, void * __dst, size_t __n)

utilizzando come da esempio su web, una struttura di dati

struct settings_t
{
  double Set_start[3];
  double Set_stop[3];
} settings;

composta in totale da 24byte (12byte per l'array Set_start e 12byte per l'array Set_stop)
ed utilizzando all'occorrenza le seguenti righe di codice:

lettura eeprom durante la fase di setup()

eeprom_read_block((void*)&settings, (void*)0, sizeof(settings));

scrittura eeprom durante la fase di memorizzazione dei dati utente

eeprom_write_block((const void*)&settings, (void*)0, sizeof(settings));

semplice, pulito, lineare :smiley:

ecco il link dove ho pubblicato tutto il codice modificato per l'implementazione della gestione read/write dei settaggi su EEPROM interna di Arduino UNO.

grazie!!!!

Ciao,

ho effettuato l'aggiornamento del codice e della documentazione del progetto antigelo caldaia anche qui, tutte le modifiche apportate al progetto originale sono evidenziate in giallo. :smiley:

saluti
kattivik76