[RISOLTO]SD >richiamare una variabile int .

Salve avrei un paio di domande:

1)Come posso richiamare una variabile salvata sulla SD quando riaccendo arduino mkr 1010 ?

2)Ho scritto bene il codice nel loop per salvare la variabile?

 switch (pin[i])
        {
          case BANCONOTA5:
            banconota5 = banconota5 + 5;
            sommapar =  banconota5 +  banconota10 + banconota20 + banconota50 + banconota100;
           
            SD.begin();
            myFile = SD.open("totali.txt", FILE_WRITE);


            if (myFile) {
              myFile.println(sommapar);
              myFile.close();

              Serial.println(sommapar);
            }

            else {
              Serial.println("error.txt");
            }

            break;
  1. ti basta rileggere il pezzo di file che contiene in valore della variabile, caricarlo in una stringa e assegnare alla variabile il ritorno della funzione atoi() di quella stringa

  2. ni, ovvero, il codice che hai scritto ha un senso e fa cose, ma quello che fa é scrivere sul file il valore, in cifre, della variabile, ma lo scrive alla fine del file. Ora, se non hai altre variabili salvate su quel file é perfetto, all'occorrenza hai anche lo storico dei valori, se ne hai ritrovare l'ultimo valore non é cosa semplice

Ah, non ho capito il Serial.println ("error.txt"), per come é scritto ti scrive quella scritta. Vuoi che ri scriva il contenuto del file error.txt? Devi lavorare in altro modo

Buongiorno.
Cercherò di essere più chiaro possibile nelle domande, come si vede dal mio codice parliamo di un contatore di impulsi, a me serve il salvataggio e lo storico della variabile sul SD fin qua ci siamo, ma quando riparte dopo lo spegnimento vorrei che arduino mi vada a caricare l'ultimo valore della variabile per proseguire nel conteggio .

1 Like

La cosa migliore è strutturare la scrittura in modo che OGNI salvataggio occupi esattamente lo stesso numero di bytes così da pter effettuare calcoli sulla posizione.

Ad esempio, se tu devi scrivere sempre degli "int", sai che essi occupano 2 bytes quindi, ad ogni salvataggio sulla SD, farai una scrittura con SD.write(&tuoInt, 2); ovvero scriverai, in binario (la cosa è comunque anche fattibile in ASCII con altri metodi) i 2 bytes del tuo "int".

Alla partenza del programma, per recuperare l'ultimo valore "int" scritto, ti basterà posizionarti alla fine del file, leggere la posizione corrente nel file (con la SD.position()), decrementare la posizione di DUE (la lunghezza di un "int"), posizionarsi su tale nuova posizione (con la SD.seek()) e leggere i DUE bytes che compongono il tuo ultimo "int".

Se invece che lavorare in binario vuoi lavorare in ASCII, devi solo considerare che un "int" va da -32768 a 32767 e che quindi devi fare in modo che OGNI salvataggio del valore occupi SEMPRE i 6 caratteri necessari (quindi, ad esempio, il valore 12 lo dovrai salvare come +00012 ed il valore -12 come -00012, così che siano sempre occupati 6 caratteri) e poi applicare la stessa logica di prima solo che lo spostamento per recuperare l'ultimo valore dovrà essere di 6 caratteri invece che di 2 bytes.

Guglielmo

Ok, quindi il punto 2 ha per risposta "si". Ora il punto 1.

  1. apri il file in lettura, il puntatore é alla posizione 0
  2. riposizioni il puntatore alla posizione file.size()-2, DOVRESTI essere sull'ultima cifra del numero
  3. torni indietro di 1 carattere alla volta fino a che trovi una cosa che NON é una cifra, sei prima dell'inizio dell'ultimo numero (non leggere con la read(), ma con la pick(), così non sposti avanti il punto di lettura ogni lettura)
  4. vai avanti di 1 carattere, sei sulla prima cifra del numero
  5. variabile=0
  6. finché pick() una cifra
    6.1) variabile=variabile*10+(read()-'0')

Dovrebbe andare bene

Ps, il (Guglielmo.modestia==TRUE?m:g)od ha dato una risposta migliore

>Silente: non ho capito il tuo punto 3 ... perché diavolo ti vuoi spostare di un byte e cosa cerchi? Se i bytes sono scritti in BINARIO, come ho scritto, sono tutte sequenze di 2 bytes, senza nulla in mezzo e non ci sono caratteri cifra o non cifra ... sei in BINARIO !!!

Guglielmo

Sono un principiante per capire tutte le cose che mi suggerite di fare ma servirebbe un esempio ,
noi andiamo avanti modificando esempi di codice adattandoli alle nostre esigenze ,proprio per questo arduino piace a tantissima persone .

Parli di int, ma un int al massimo accetta -32768 a 32767 sicuro che basta ?

come già detto da Guglielmo:
Su un file puoi scrivere e accodare i valori in due modi, in formato binario, quindi un int è 2 byte
oppure scrivi in formato testo, ma qui c'e' il problema che 123 occupa 3 byte (anzi 3 char) mentre 12345 occupa 5 byte.

Il file lo puoi aprire su PC con un notepad, ma se formato testo lo leggi facile, se binario i valori sono scritti come nella memoria del micro (byte per byte)

Quindi prima di tutto devi decidere se formato testo o binario.
Binario è più semplice da gestire perché un int ad esempio occupa sempre 2 byte

Per un file testo dovresti scrivere occupando sempre lo stesso numero di caratteri, lo si può fare
"formattando" il valore con snprintf() (ma non funziona con i float)
La snprintf() converte il valore in testo, quindi devi avere un array di char che contenga il valore convertito.

  char buf[10];
  snprintf(buf,10,"%05d",sommapar);  // 123 => "00123"
  myFile.print(buf);
  myFile.print(' ');    // separatore      SCRIVIAMO QUINDI 6 byte per ogni valore  NO println!!
  myFile.close();

Lo stesso array lo puoi usare per poi leggere l'ultimo dato dal file. Le indicazioni sono quelle di Guglielmo per un file di testo al post#3
Ma fatta la scrittura, poi vediamo la lettura.

Nid, io questo:

snprintf(buf,10,"%05d",sommapar);  // 123 => "00123"

lo scriverei invece:

snprintf(buf,10,"%+06d",sommapar);  // 123 => "+00123"

così da non avere problemi tra segnati e non segnati :wink:

Guglielmo

Salve, grazie ancora per tutti i consigli ma non riesco a leggere i vostri esempi, ho provato a

modificare il mio così nel loop per salvare solo l'ultima scritte così è più gestibile.. almeno credo,

il file viene cancellato e riscritto solo l ultimo valore ma comunque non riesco a richiamarlo al momento

di ripartenza di arduino .

  switch (pin[i])
        {
          case BANCONOTA5:
            banconota5 = banconota5 + 5;
            sommapar =  banconota5 +  banconota10 + banconota20 + banconota50 + banconota100;

            SD.begin();
            SD.remove("totali.txt");
            myFile = SD.open("totali.txt", FILE_WRITE);


            if (myFile) {

              myFile.print(sommapar);
              myFile.close();

              Serial.println(sommapar);
              Serial.println("salvata");
              delay(50);
            }

            else {
              Serial.println("error.txt");
            }

            break;

WinGamesyun:
il file viene cancellato e riscritto solo l ultimo valore ma comunque non riesco a richiamarlo al momento
di ripartenza di arduino .

La lettura alla partenza la devi fare nel setup()
Se esiste il file, lo apri in lettura. Poi leggi in un array di char e lo converti con atoi()
Logicamente leggi il primo valore, dici che c'e' solo 1 valore ora (ma la FILE_WRITE accoda)

char buf[20];
int i=0;
while (myFile.available()) {
 buf[i]=myFile.read();
 i++;
 if(i>=19) break;
}
buf[i]='\0';

valore=atoi(buf);

Buongiorno,
ho fatto un copia e incolla nel setup modificando solo la variabile..sembra che
ci sia una parentesi in più mi da questo errore .

apr21a_POSTA_PORTA:89:27: error: expected ';' before ')' token

buf = myFile.read());
Togliendo una parentesi dopo il read mi fa compilare il codice
ma comunque non mi aggiorna la variabile >sommapar<
ho ricontrollato il file txt si aggiorna sempre con il nuovo valore cancellando il vecchio .

```

  • char buf[20];
      int i = 0;
      while (myFile.available()) {
        buf[i] = myFile.read());
        i++;
        if (i >= 19) break;
      }
      buf[i] = '\0';
      sommapar = atoi(buf);
      Serial.println(sommapar);*
    ```
    Ho anche aggiunto myFile.close();

... magari se riportassi sempre il codice completo invece che dei pezzi, sarebbe più facile capire il perché!

Guglielmo

Eccolo :o

[code]
#include <SD.h>
#include <RTClib.h>
#include <Wire.h>
RTC_DS1307 rtc;
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x27);
#define BLYNK_PRINT Serial
#include <SPI.h>
#include <WiFiNINA.h>
#include <BlynkSimpleWiFiNINA.h>
#include <TimeLib.h>
#include <WidgetRTC.h>
WidgetRTC blynk_rtc;
char auth[] = "";
char ssid[] = "Vodafone";
char pass[] = "xxxx";
char server[] = "blynk-cloud.com";
int port = 8080;
WidgetLCD blynk_lcd(V31);
WidgetLCD blynk1_lcd(V10);

BlynkTimer timer;
#define PORTA         1
#define POSTA         2
#define RESET         3
#define BANCONOTA5    5
#define BANCONOTA10   6
#define BANCONOTA20   7
#define BANCONOTA50   8
#define BANCONOTA100  10


int key[8] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH,};
int pin[8] = {BANCONOTA5, BANCONOTA10, BANCONOTA20, BANCONOTA50, BANCONOTA100, PORTA, POSTA, RESET,};
int  banconota5  = 0;
int  banconota10  = 0;
int  banconota20  = 0;
int  banconota50  = 0;
int  banconota100  = 0;
//int posta = 1;
int porta =  1;
int  sommapar =  0;

String postas = String (postas);
String posta = String ("VUOTO");
String posta1 = String ("PIENO");
File myFile;
File myFile1;
void setup()
{


  WiFi.begin(ssid, pass);
  Blynk.config(auth, server, port);

  Blynk.connect();
  Serial.begin(9600);

  // Blynk.email("dellipaolmail.com", "CAMBIA MARIO", "acceso e connesso.");
  timer.setInterval(90000L, leggidati );
  timer.setInterval(300000L, leggidati1 );

  Serial.println("Initializing SD card...");
  if (!SD.begin(4)) {
    Serial.println("SD non presente");
    lcd.begin(16, 2);
    lcd.setBacklight(255);
    lcd.home(); lcd.clear();
    lcd.setCursor(2, 0);
    lcd.print(">V1.0<SD>KO ");
    lcd.setCursor(0, 1);
    lcd.print("SD NON PRESENTE");

    while (1);
  }
  Serial.println("sd presente.");
  lcd.begin(16, 2);
  lcd.setBacklight(255);
  lcd.home(); lcd.clear();
  lcd.setCursor(4, 0);
  lcd.print("SD > OK ");
  lcd.setCursor(2, 1);
  lcd.print("ATTENDERE>V1.0");
  delay(3000);

  char buf[20];
  int i = 0;
  while (myFile.available()) {
    buf[i] = myFile.read());
    i++;
    if (i >= 19) break;
  }
buf[i] = '\0';
  sommapar = atoi(buf);
  Serial.println(sommapar);

  Wire.begin();
  Wire.beginTransmission(0x27);

  lcd.begin(16, 2);
  lcd.setBacklight(255);
  lcd.home(); lcd.clear();
  lcd.setCursor(1, 0);
  lcd.print("WIN GAMES");
  lcd.setCursor(0, 1);
  lcd.print("TOTALI");
  delay(1000);
  blynk1_lcd.clear();
  blynk1_lcd.print(0, 0, postas );
  blynk1_lcd.print(0, 1, "HOPPER,1" );


  blynk_lcd.clear();
  blynk_lcd.print(4, 0, sommapar );
  blynk_lcd.print(4, 1, " TOTALI ");


  for (int i = 0; i < 8 ; i++)

    pinMode(pin[i], INPUT_PULLUP);


}

void loop()
{

  int k;

  for (int i = 0; i < 8 ; i++)
  {
    k = digitalRead(pin[i]);
    if ( key[i] != k )
    {
      if ( key[i] == HIGH && k == LOW )
      {
        Serial.print("PIN");
        Serial.println(pin[i]);

        switch (pin[i])
        {
          case BANCONOTA5:
            banconota5 = banconota5 + 5;
            sommapar =  banconota5 +  banconota10 + banconota20 + banconota50 + banconota100;

            SD.begin();
            SD.remove("totali.txt");
            myFile = SD.open("totali.txt", FILE_WRITE);


            if (myFile) {

              myFile.print(sommapar);
              myFile.close();


              Serial.println("salvata");

            }

            else {
              Serial.println("error.txt");
            }
            myFile1 = SD.open("totali1.txt", FILE_WRITE);


            if (myFile1) {

              myFile1.print( "INSERITA BANCONOTA DA  5 EURO SOMMA PARZIALE  =  ");
              myFile1.println(sommapar);
              myFile1.close();


              Serial.println("salvata1");

            }

            else {
              Serial.println("error1.txt");
            }
            break;

          case BANCONOTA10:
            banconota10 = banconota10 + 10;
            sommapar = banconota5 +  banconota10 + banconota20 + banconota50 + banconota100;

            Serial.println(" BANCONOTA 10");
            break;
          case BANCONOTA20:
            banconota20 = banconota20 + 20;
            sommapar = banconota5 +  banconota10 + banconota20 + banconota50 + banconota100;
            Serial.println(" BANCONOTA 20");
            break;
          case BANCONOTA50:
            banconota50 = banconota50 + 50;
            sommapar = banconota5 +  banconota10 + banconota20 + banconota50 + banconota100;
            Serial.println(" BANCONOTA 50");
            break;
          case BANCONOTA100:
            banconota100 = banconota100 + 100;

            sommapar = banconota5 +  banconota10 + banconota20 + banconota50 + banconota100;

            Serial.println(" BANCONOTA 100");
            break;
          case POSTA:
            // Blynk.email("dellipaolil.com", "CAMBIO MARIO", "VUOTO");
            postas = posta;
            blynk1_lcd.print(0, 0, postas );
            Serial.println(" POSTA");
            break;
          case PORTA:
            Blynk.notify("ATTENZIONE PORTA APERTA ");
            // Blynk.email("dellip@gmail.com", "CAMBIO MARIO", " CAMBIA MONETE \n ATTENZIONE PORTA APERTA ");
            //blynk1_lcd.print(0, 0,stato );
            Serial.println(" PORTA APERTA ");
            break;
          case RESET:
            banconota5   = 0;
            banconota10  = 0;
            banconota20  = 0;
            banconota50  = 0;
            banconota100 = 0;
            sommapar     = 0;
            postas       = posta1 ;
            Serial.println(" AZZERAMENTO TOTALI");

            blynk_lcd.clear();
            blynk1_lcd.clear();
            lcd.home(); lcd.clear();
            lcd.setCursor(0, 1);
            lcd.print("TOTALI");
            lcd.setCursor(1, 0);
            lcd.print("AZZERAMENTO");
            delay(3000);
            lcd.home(); lcd.clear();
            lcd.setCursor(1, 0);
            lcd.print("WIN GAMES");
            lcd.setCursor(0, 1);
            lcd.print("TOTALI");
            break;
        }

        Serial.print("Totale = ");
        Serial.println(sommapar);
        blynk_lcd.print(4, 0, sommapar );
        blynk_lcd.print(4, 1, " TOTALI ");
        blynk1_lcd.print(0, 0, postas );
        blynk1_lcd.print(0, 1, "HOPPER,1" );

      }
      key[i] = k;
    }

    lcd.setCursor(8, 1);
    lcd.print(sommapar);
  }
  if (Blynk.connected()) {
    Blynk.run();
    lcd.setCursor(11, 0);
    lcd.print("CONN");
    lcd.setCursor(11, 0);
  }
  else {
   // Blynk.disconnect();
    lcd.setCursor(11, 0);
    lcd.print("DISC");
  }
  Blynk.run();
  timer.run();
}
void leggidati() {
  if (Blynk.connected()) {
    WiFi.begin(ssid, pass);
  Blynk.config(auth, server, port);
    Blynk.connect();

}
else{
  Blynk.connect();
  Serial.println(sommapar);
  blynk_lcd.print(4, 0, sommapar );
}
}
void leggidati1() {
  if (Blynk.connected()) {
    Serial.println("connesso");
  }
  else {
    Serial.println("no connesso");
  }
}

[/code]

  1. La parentesi doppia è un mio errore di battitura (codice non provato, scritto di getto) Togli la doppia
  2. ti ho scritto quel pezzo di codice che legge ma ti ho scritto che nella setup() devi PRIMA aprire il file in lettura e verificare se esiste. Se non fai open del file in FILE_READ quel pezzo non funziona.

Quindi quel pezzo di codice deve essere dentro a

myFile = SD.open("totali.txt", FILE_READ);
if (myFile) 
{ // pezzo di lettura file
}
else
{ sommapar=0;
}

Buona sera ,
modificato come consigliato purtroppo non va .

[code]
  myFile = SD.open("totali.txt", FILE_READ);
  if (myFile)
  { // pezzo di lettura file
    char buf[20];
    int i = 0;
    while (myFile.available()) {
      buf[i] = myFile.read();
      i++;
      if (i >= 19) break;
    }
    buf[i] = '\0';
  }
  else {
    sommapar = 0;
  }

[/code]
Ma non devo chiudere il file?
:confused:

Facendo un pò di prove mi sono accorto che avevamo saltato una riga di codice,
ora funziona ma è comparso un 'altro problema...
la variabile viene richiamata e scritta ma il contatore riparte da zero e come se non riconoscesse il valore reale
della variabile.
Codice funzionante.

myFile = SD.open("totali.txt", FILE_READ);
  if (myFile)
  { // pezzo di lettura file
    char buf[20];
    int i = 0;
    while (myFile.available()) {
      buf[i] = myFile.read();
      i++;
      if (i >= 19) break;
    }
    buf[i] = '\0';
    sommapar = atoi(buf);// il pezzo mancante...
  }

  else {
    sommapar = 0;
  }

Piccola riscrittura del codice al volo, vedi se cibsi capisce qualcosa di iù sul problema

myfile=SD.open ("totali.txt, FILE_READ);
if (myfile)
for (char buffer [7]={0}, byte i=0;myfile.available()&&i<6;i++)
{
char c=myfile.read();
buffer [i]=c;
Serial.print (c);
sommapar=atoi (buffer);
}
else
{
sommapar=0;
Serial.println ("file non aperto ");
}
Serial.println (sommapar);
myfile.close();

Corretta dimenricanza, sei un grande

WinGamesyun:
Facendo un pò di prove mi sono accorto che avevamo saltato una riga di codice,
ora funziona ma è comparso un 'altro problema...
la variabile viene richiamata e scritta ma il contatore riparte da zero e come se non riconoscesse il valore reale
della variabile.

Ma questo pezzo è nel setup() ? (posta sempre tutto)
Si il file devi chiuderlo.
Metti un pò di serial.println per sapere se ha letto, e se ha letto buf

boh, vi seguo da un po', ma non ho capito una cosa
la veriabile viene salvata una volta sola, ovvero: nel file esiste una sola copia della variabile, oppure il file sarà pieno di righe, dove solo l'ultima è aggiornata?
comunque, senza perdersi tanto in conteggi e righe e fine stringa e atoi e compagnia bella

int leggidafile(char * filename)
{
    // così possiamo anche scegliere che file usare
    int locale = 0;
    myFile = SD.open(filename, FILE_READ);

    if (myFile)
    {
        while (myFile.available())
        {
            char cx = myFile.read();

            if ((cx == '\r') || (cx == '\n'))
            {
                // fine riga windows o linux
                if (myFile.available() > 2)
                {
                    // esclude il caso di ultimo ritorno a capo
                    locale = 0;
                    // nuova riga? allora nuovo valore
                    break;
                }

                locale = locale * 10 + cx - '0';
                // ogni nuova cifra sposta a sinistra di un posto e si aggiunge
            }
        }

        myfile.close();
    }
    else
    {
        // Errore di apertura file
    }
    return locale;
}

semplice, rapida, parametrica e funziona anche se per caso ci fossero più righe consecutive e valesse solo l'ultima