Rileggere variabili dalla ultima riga da una SD (Arduino MEga) [RISOLTO]

Buongiorno a tutti,
utilizzo un Arduino Mega con Ethershield + SD.

Il mio progettino è quasi concluso, vi espongo l’unico punto aperto.

Quando avviene un reset, vorrei che L’arduino andasse a leggere le variabili dell’ultima riga, memorizzate sulla SD (che sarebbero quelle attuali), in modo da poter continuare da dove ci si era fermati.

Sono in cerca di qualche tutorial in Italiano (con quelli Inglesi ho difficolta).

Qualche consiglio ?

Grazie e buona giornata
Remo

beh se salvi su file basta che leggi tutto il file finche non arrivi alla fine e poi ti recuperi l'ultima riga..oppure salvi su file "al contrario" in modo da avere l'ultimo evento sempre in cima al file

Grazie del consiglio,
dovró rileggermi e studiarmi la libreria della SD.

Il mio intento è quello di ri-settare delle variabili, in pratica dovró riconvertirle in formato INT dopo la lettura.

Saluti
Remo

Dovresti postare il formato del file, un esempio di come sono salvate le var, altrimenti sarà difficile darti un consiglio.
Quante variabili sono? sono separate da virgola, sono su più linee? una riga sola ...

ciao

I valori (a parte data e ora) sono in INT, qui sotto un esempio (a memoria, non ho qui il log).
Tutto su una unica riga

17.4.2013 ORE: 12:25:37 Consumo Attuale 1456 watt Contatore alto 123456 Kwh Contatore basso 113455 ecc......

Quelle marcate in Rosso mi interesserebbe recuperare dopo un restart.

Saluti
Remo

Dovresti salvare i dati in questo modo, il char "," fa da separatore e il "#" da l'inizio riga, ora fai uno split dell'ultima linea i valori 7,8,9 sono quelli che ti interessano

#,18,4,2013,13,25,37,1456,123466,113465
#,19,4,2013,14,25,37,1466,123476,113475
#,20,4,2013,15,25,37,1476,123486,113485
#,21,4,2013,16,25,37,1486,123496,113495
#,22,4,2013,17,25,37,1496,123506,113505

anche uno "\n" può farti da fine linea e new line, forse il # puoi non usarlo, dipende come scrivi su file
Ora mi rendo conto di averti rovinato le righe e quando vai a rileggere a video l'intero file non ci capisci nulla, ma sta a te ricostruire i dati da stampare quando vai a fare un "visualizza file" :slight_smile:

Oppure un altro modo, metti davanti a quei valori dei simboli o delle parole univoche,

es
Consumo Attuale CSA1456#
Contatore alto CNA123456#
Contatore basso CNB113455#

ora cerchi tutto quello che è contenuto tra CSA e # ecc ecc, quando legge il file ne troverà tanti, alla chiusura del file le 3 variabili che hanno letto CSA CNA CNB saranno gli ultimi

ciao

Ti Ringrazio Pablos.
Attueró questa forma, molto piu chiara e snella.

Non ho ancora capito pero come posso far saltare il cursore all'inizio dell'ultima riga, e da li fare la ricerca.
Presumo con il comando seek() ?

Saluti
Remo

i comandi della lib SD sono pochi alla fine è sempre un leggere dal char 0 all'ultimo char del file, seek ti restituisce vero-falso se è prensente un char in una determinata pos, non mi sembra che ti possa servire.

String ReadLine;
  char charBuf[80];
    
  if(file.open(&root, "miofile.txt", O_READ))  
  {
   int16_t c;
       while ((c = file.read())>0)
       {
         ReadLine += (char)c;
         
           if((char)c=='\n') 
           {
              ...
              ...
           }

quando l'while (c = file.read()) sarà = 0 ReadLine conterrà l'ultima riga su cui vai a prendere i dati

ReadLine è una stringa quindi dovrai estrarre i dati lavorandola un po' usando
ReadLine.indexOf("....")
ReadLine.substring(a, b);
ecc
cerca di fare le linee del file più corte possibili altrimenti ti ritrovi arduino piantato la ram è poca

Grazie proveró oggi e ti faro sapere.

Buona giornata.

Remo

Ancora meglio sarebbe separare i dati scritti con ; invece di ,
A questo punto la prima riga potrebbe anche essere i titoli dei campi e il file sarebbe un comodo file csv che puoi leggere con excel.

giorno;mese;anno;ora;minuti;secondi;Consumo attuale;Contatore alto;Contatore basso
18;4,2013;13;25;37;1456;123466;113465
19;4;2013;14;25;37;1466;123476;113475

I comandi Seek(), Position(), Size() sarebbero utili per leggere l'ultima riga ma SOLO se tutte le tue righe hanno la stessa lunghezza.

Con size() chiedi la lunghezza del file. Se ogni riga occupa 10 byte e il file contiene 6 righe dovrebbe essere grande 60 byte.
Con seek() vai al byte 50 e leggi 10 byte ovvero l'ultima riga.

Il file può anche essere un file testo, ma assolutamente devi essere sicuro che ogni riga occupi sempre gli stessi caratteri e tener conto del fine riga.

nid69ita:
I comandi Seek(), Position(), Size() sarebbero utili per leggere l'ultima riga ma SOLO se tutte le tue righe hanno la stessa lunghezza.

Con size() chiedi la lunghezza del file. Se ogni riga occupa 10 byte e il file contiene 6 righe dovrebbe essere grande 60 byte.
Con seek() vai al byte 50 e leggi 10 byte ovvero l'ultima riga.

Il file può anche essere un file testo, ma assolutamente devi essere sicuro che ogni riga occupi sempre gli stessi caratteri e tener conto del fine riga.

Come puoi dedurre non è così, le lunghezze dei records cambiano, comunque qualsiasi sia la funzione utility che offre la libreria è sempre una lettura dal char 0 fino all'ultimo char del file in modo sequenziale (leggi carattere e conta). Tanto vale che faccia una funzione lui dedicata alle sue necessità.

Vi ringrazio delle info, il raginamento l'ho capito.
useró le funzioni indexof e substring.

Unico dubbio , come faccio a riconvertire questi valori in INT ?
Ho letto qualcosa inerente Atol ma non so se sia la via giusta.

Saluti e grazie
Remo

remino:
come faccio a riconvertire questi valori in INT ?
Ho letto qualcosa inerente Atol ma non so se sia la via giusta.

Purtroppo si, la funzione è atoi(), il purtroppo lo capirai quando la usi :slight_smile:
esiste anche int(string) ma per numeri a 4-5 cifre mi dava valori sbagliati.

ciao

remino:
Vi ringrazio delle info, il raginamento l'ho capito.
useró le funzioni indexof e substring.

Unico dubbio , come faccio a riconvertire questi valori in INT ?
Ho letto qualcosa inerente Atol ma non so se sia la via giusta.

Saluti e grazie
Remo

atoi per ascii->int
atol per ascii->long

devi fare attenzione però al discorso signed/unsigned

http://www.cplusplus.com/reference/cstdlib/atol/

Buongiorno a tutti,
ieri sera ho fatto le prime prove (premetto che non conosco la Libreira SD).

Vi espongo un attimo la situazione.

Dopo un Reset, i dati riletti (se riletti) non vengono applicati al processo in corso.

Sono sicuro che cè qualcosa che non va nel mio Code di rilettura, mi sono appoggiato al consiglio di Pablos,adattando alcuni comandi alla Libreria SD.

Per essere piu chiaro, vi posto 3 estratti del mio codice.

Estratto 1 : Codice rilettura dopo Reset (basato su consiglio di Pablos)
Estratto 2 : Formato in cui salvo i dati su SD
Estratto 3 : Presentazione dei dati riletti dalla SD

Vi Ringrazio e abbiate pazienza con la mia confusione.
Buona giornata
Remo

Estratto 1

 // Rilettura dati in caso di Reset
 
 if (riavvio == 0) {
   
  Serial.println ("Rileggo ultimi valori.....");
   contatore = SD.open("valori2.txt"); 
   String ReadLine;
  char charBuf[80];
    
  if(contatore)  
  {
   int16_t c;
       while ((c = contatore.read())>0)
       {
         ReadLine += (char)c;
                 
           if((char)c=='\n') 
           {
int posizioneA = ReadLine.indexOf('A');
int posizioneB = ReadLine.indexOf('B');
int posizioneC = ReadLine.indexOf('C');
int posizioneD = ReadLine.indexOf('D');
int posizioneE = ReadLine.indexOf('E');
int posizioneF = ReadLine.indexOf('F');

String A = ReadLine.substring ((posizioneA+1),(posizioneB-1));
String B = ReadLine.substring ((posizioneB+1),(posizioneC-1));
String C = ReadLine.substring ((posizioneC+1),(posizioneD-1));
String D = ReadLine.substring ((posizioneD+1),(posizioneE-1));
String E = ReadLine.substring ((posizioneE+1), (posizioneF-1));


Serial.println (A);//temporanei
Serial.println (B);//temporanei
Serial.println (C);//temporanei
Serial.println (D);//temporanei
Serial.println (E);//temporanei
           }

    riavvio = 1;
    contatore.close();
  Serial.println ("ultimi valori riletti.....Done");
 }

   }}

Estratto 2:

  contatore = SD.open("valori2.txt", FILE_WRITE);
      // if the file opened okay, write to it:
  if (contatore) {
    Serial.print("scrivo valori...");
    delay(250);
   contatore.print("#");
    contatore.print(giorno);
     contatore.print(";");
     contatore.print(mese);
      contatore.print(";");
       contatore.print(anno);
         contatore.print(";");
       
         contatore.print(ora);
          contatore.print(";");
           contatore.print(minuti);
            contatore.print(";");
             contatore.print(secondi);
            
              contatore.print("A");
                contatore.print(consumo_mom,1);
                
                  contatore.print("B");
                   contatore.print(kw_giorno);
                  
                    contatore.print("C");
                     contatore.print(contatore_alto,0);
                    
                       contatore.print("D");
                        contatore.print(contatore_basso,0);
                        
                          contatore.print("E");
                           contatore.print(giri);
                            contatore.print("F");
                             contatore.println("\n");
                           
                         
                          
	// close the file:
    contatore.close();
    Serial.println("done.");

Estratto 3:

#27;4;2013;6;14;10A219.0B7.77C113165D112981E10F

#27;4;2013;6;16;10A252.1B7.78C113165D112981E11F

#27;4;2013;6;17;50A303.0B7.79C113165D112981E12F

#27;4;2013;6;19;33A291.3B7.80C113165D112981E13F

#27;4;2013;6;21;12A306.1B7.81C113165D112981E14F

#27;4;2013;6;22;57A288.5B7.82C113165D112981E15F

#27;4;2013;6;24;38A300.0B7.82C113165D112981E16F

Una prima cosa: contatore.println("\n");
Ti trovi poi le righe separate con una riga vuota. Println mette già un a capo
contatore.println("");
oppure
contatore.print("\n");

io intendevo qualcosa di meno laborioso, ma forse non molto più semplice

allora ipotizziamo che i tuoi record nel file sia fatto così, ci sono dei numeri che superano il 65*** quindi l' int non basta più ci vuole il long

18,4,2013,13,25,37,1456,123466,113465
19,4,2013,14,25,37,1466,123476,113475
20,4,2013,15,25,37,1476,123486,113485
21,4,2013,16,25,37,1486,123496,113495
22,4,2013,17,25,37,1496,123506,113505

quindi hai 9 valori per linea

imposti tutte le tue cose nel setup

void setup() {
 ...
 ...
 dichiari qui i pin e quello che ti serve
 ...
 ...
  leggi_SD(); //vai alla funzione leggi l'ultima riga da sd
}

Funzione che legge il file tenendoci l'ultima linea del file come buona

void leggi_SD(){
  String ReadLine;
  char charBuf[50];
    
  if(file.open(&root, "miofile.txt", O_READ)) {
   int16_t c;
       while ((c = file.read())>0){
         ReadLine += (char)c;
           if((char)c=='\n') {                 

                 #if DEBUG_RIGHE_FILE               
                 Serial.print(ReadLine);//debug 
                 #endif

               if(c > 0) ReadLine="";   
            }  
       }  
   } 
  Serial.print("ultima linea ");//debug
  Serial.println(ReadLine);//debug  //questa è l'ultima linea
  ReadLine.toCharArray(charBuf, 50); //metto i singoli caratteri in un array di char
  estrai_valori(charBuf);//vai alla funzione estrai dati
}

Adesso che abbiamo l'ultima linea andiamo ad estrarre i 9 valori usando la "," come separatore

void estrai_valori(char *charBuffer){ 
  unsigned long temp[]= {0,0,0,0,0,0,0,0,0};
  char *p = charBuffer;  
  byte i = 0;

  while (*p != '\0') 
  {
    if (*p == ',') { ++i;  ++p;  continue;}
    if (isdigit(*p)) 
    {
         temp[i] *= 10; 
         temp[i] += (*p - '0');            
    }    
     ++p;
  }  

Serial.println(temp[0]);Serial.println(temp[1]);Serial.println(temp[2]);Serial.println(temp[3]);Serial.println(temp[4]);
Serial.println(temp[5]);Serial.println(temp[6]);Serial.println(temp[7]);Serial.println(temp[8]);
}

void loop() { }

questa è l'output sul serial .... i tuoi valori ora sono dentro l'array temp[n] in formato long

ultima linea 22,4,2013,17,25,37,1496,123506,113505

22
4
2013
17
25
37
1496
123506
113505

ciao

Grazie delle Info,
provo e vi informero.

Buona Giornata
Remo

Non sono info, te l'ho proprio fatto il programma :smiley: :smiley: :smiley: e l'ho testato