Leggere da SD card SENZA uso di String

Conosco bene i problemi dell’uso di String che tra parentesi mi hanno dato col tempo problemi di memoria.

Domanda:

  • Devo leggere dei dati da SD, posso farlo senza l’uso di String con la S maiuscola per trasferirli in variabili numeriche o tipo char?

  • C’è qualche esempio in rete che mi possa tornare comodo e che voi conoscete?

Purtroppo non sono riuscito a trovare nulla o probabilmente non ho cercato nel modo corretto.

Possono contenere o solo numeri o testo e numeri.

Grazie in anticipo a tutti.

ciao...ma questi "dati" sono formattati in un modo conosciuto o no?

I dati posso formattarli come voglio, anche usando un separatore, oppure a blocchi,

es:

10152019 che poi devo dividere in: 10 - 15 - 2019

oppure una sequenza

100,531,771 che potrei dividere in: 100 - 531 - 771

oppure

abaacdzr che posso dividere in: ab - aa - cd - zr

Sono solo esempi poi ci metto del mio.

Purtroppo non essendo esperto di C o company non parlatemi di byte ottali binari o esadecimali.
Ho insegnato per 43 anni, ma non ho voglia di rimettermi a farmi fumare il cervello anche per questo, fare qualcosa sì, ma in modo semplice, purtroppo non ho più l’elasticità mentale di un tempo.
È solo da gennaio che mi son messo a macinare per la prima volta i codici, sto imparando tutto da (quasi) zero.

In sostanza a me interessa leggere il file fino alla fine e passarlo su Arduino senza l’uso di String, ripeto con la S maiuscola.

O almeno qualcosa che non mi vada a intasare e bloccare quella parte di memoria che poi non mi consenta di avere una rielaborazione dei dati corretti.

Usando String mi va bene tutto all’inizio, poi al trasferimento di più blocchi corposi con stringhe lunghe che devono essere lette, poi scritte su SD poi rilette da SD e rimandate ad Arduino, alla fine mi intasano la memoria e i dati che vengono elaborati sono spezzettati e comunque in qualche modo corrotti.

  • La SD card è formatta in modo corretto, ho provato con più di una scheda.
  • Lo stesso tipo di stringhe su un altro sketch meno corposo funzionano correttamente.
  • Le prime elaborazioni sono sempre corrette, sia verso scheda che viceversa, al secondo o talvolta al terzo trasferimento tutto si inceppa.
  • Il file viene aperto e chiuso correttamente ad ogni lettura o scrittura.

Qualche idea o suggerimento o pezzullo di codice è sempre bene accetto.

Un paio di esempi reali di quello che trasferisco su SD, o leggo e riscrivo sono questi:

6596,6939,7117,7490,7381,7459,6673,6609
320,520,800,300,700,500,300,225
2,10,3,2,0,3,5,3
5,5,5,5,0,5,6,5
6,6,7,9,0,7,7,6
0,7,9,0,0,10,8,7
0,8,0,0,0,0,9,0
0,9,0,0,0,0,10,0
0,10,0,0,0,0,0,0
0,11,0,0,0,0,0,0
0,12,0,0,0,0,0,0
0,13,0,0,0,0,0,0
0,14,0,0,0,0,0,0
0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0
7000,7000,90000,105000,25000,70500,85000,95000
5000,14,19,2,0,15000,0,0

Sono in pratica array con otto elementi.

oppure con più elementi:

1-1-19.TXT,2-1-19.TXT,3-1-19.TXT,4-1-19.TXT,5-1-19.TXT,6-1-19.TXT,7-1-19.TXT, ecc.

Tutto questo molto semplice dichiarando qualcosa simile a:
String miaStringa = ""; e poi tutto il resto per riempirla, passarla su Sd riprenderla, rielaborarla, sostituirla, ecc. ecc. ecc.

Thanks again...

Tutto sta in cosa devi farci, puoi usare stringhe classiche (array di char) che hanno una serie di funzioni comode per poter lavorare, oppure direttamente carattere a carattere, e processarli uno ad uno, o altre cose che ora non mi vengono in mente

Ciao!Il metodo read() della classe FILE di SD , legge appunto array di char o array di byte.
Su file puoi salvare caratteri o struct.

Potresti salvare su file tutto sotto forma di testo, caratteri e poi interpretarli su arduino.

Se tu vuoi scrivere e leggere un carattere su file arduino, sappi che il metodo read() senza argomenti legge un carattere, Quali esempi studiare, se leggi e scrivi un carattere su file, il codice è identico a leggere e scrivere carattere su seriale, quindi ti puoi copiare gli esempi "come leggere stringa da seriale con array di char".

Ma senza la descrizione di cosa deve leggere come posso capire come deve fare?

C1P8 ha postato un esempio di file che si trova su SD.

6596,6939,7117,7490,7381,7459,6673,6609
320,520,800,300,700,500,300,225
2,10,3,2,0,3,5,3
5,5,5,5,0,5,6,5
6,6,7,9,0,7,7,6
0,7,9,0,0,10,8,7
0,8,0,0,0,0,9,0
0,9,0,0,0,0,10,0
0,10,0,0,0,0,0,0
0,11,0,0,0,0,0,0
0,12,0,0,0,0,0,0
0,13,0,0,0,0,0,0
0,14,0,0,0,0,0,0
0,0,0,0,0,0,0,0

Adesso potrebbe essere del testo, si legge riga per riga e con la funzione C strtok() si separano tutti gli elementi ottenendo 8 sottostringhe, con la funzione C atoi() trasformiamo le otto sottostringhe in numeri interi :wink:

se proprio non vuoi usare readStringUntil('\n'), visto che restituisce una String, credo che l'unica alternativa sia leggere char per char (file.read()) e accumularli in un array fino a quando non trovi il line feed (\n), a quel punto la splitti direttamente in un array o in singole variabili con strtok, naturalmente se sono interi vanno convertiti con atoi.

strtok funziona cosi:
prima lettura, strtok(line, ";"), dove line è l'array di char e ";" il separatore, quindi ottieni il primo campo
per ottenere tutti i successivi, non devi più passare array, cioè strtok(NULL, ";") per ogni ogni campo che vuoi leggere

Nota:
attenzione, in ogni caso verifica qual'è il terminatore di riga, in quanto dipende da come e con cosa scrivi il file

Federico

PS
Spero di non aver detto castronate, nel qual caso qualcuno mi correggerà, grazie

io ero rimansto a questo:

patdepri:
I dati posso formattarli come voglio, anche usando un separatore, oppure a blocchi,

es:

10152019 che poi devo dividere in: 10 - 15 - 2019

oppure una sequenza

100,531,771 che potrei dividere in: 100 - 531 - 771

oppure

abaacdzr che posso dividere in: ab - aa - cd - zr

Sono solo esempi poi ci metto del mio.

ecco, se mettendoci del suo ci spiegasse il formato, invece di lasciarcelo indovinare mettendoci tre esempi che non si guardano tra loro
magari dire: tutti campi numerici, tutti obbligatori, a lunghezza variabile, il N N N float, gli altri interi, righe separate da $primoseparatore$, campi tra di loro separati da $secondoseparatore$, parte frazionaria separata da $separatoredeidecimali$
ecco, io magari capirei e potrei intervenire
altrimenti ho impressione di pressappocchismo

Detto fatto vado in replica spiegandomi meglio:

// Problema: Registrare questi dati su SD e ritrasferirli su queste variabili.
// ATTENZIONE questi dati mi cambiano di ora in ora per cui devo aggiornarlli sempre su sd,
// ma ho bisogno di prelevarli nel momento in cui ne avessi necessità per questo vengono salvati su diversi file.
// uso come separatore la - , - virgola
 
// Primo esempio caratteri 'Tipo Stringa' salvataggio della data col nome del file
meglio questo:
char nome_Del_File[3][12] = {"01012019.TXT", "02012019.TXT", "03012019.TXT"}; 

oppure questo per una scrittura e riscrittura?:
char nome_Del_File2 = "01012019.TXT,02012019.TXT,03012019.TXT";

// Separatore virgola non superano i fatidici 32,767.

int variabile_1       [8]        = {30005,  32423,  25000,  10797,  5744,  6456,  5656,  21656};
int variabile_2       [8]        = {6,  6,  6,  6,  0,  7,  7,  6};
int variabile_3       [8]        = {0,  7,  7,  7,  0, 10,  8,  7};
int variabile_4       [8]        = {0,  8,  8,  8,  0,  0,  9,  0};
int variabile_5       [8]        = {0,  9, 10,  9,  0,  0,  10, 0};

// Separatore virgola non superano i fatidici 255.

byte variabileByte_1       [8]        = {5,  5,  5,  5,  0,  5,  6,  5};
byte variabileByte_2       [8]        = {6,  6,  6,  6,  0,  7,  7,  6};
byte variabileByte_3       [8]        = {0,  7,  7,  7,  0, 10,  8,  7};
byte variabileByte_4       [8]        = {0,  8,  8,  8,  0,  0,  9,  0};
byte variabileByte_5       [8]        = {0,  9, 10,  9,  0,  0,  10, 0};

Tengo a precisare che non ho mai usato istruzioni tipo strtok ecc.
Per ora sono solo parole che mi suonano arcane. Ho bisogno di esempi pratici per capire e poi modificarli.

Ultima precisazione che è il mio obiettivo, devo fare tutto questo per evitare di intasare la memoria che non è volatile, dato che Arduino non è un PC.

Spero di essere stato più chiaro.

Grazie ancora per gli aiuti.

patdepri:
Detto fatto vado in replica spiegandomi meglio:

Per me era già chiarissimo prima, e quindi resta valido quello che ho scritto :wink:

Su file SD scrivi tutto sotto forma di testo usando il metodo println(), in modo che hai il terminatore riga \n.

Per la lettura andrai a leggere riga per riga in modo analogo a come si fa per la seriale.

C'è un "problema"! tu hai tanti array, per inserire i dati nei vari array, dovrei scrivere un codice per ciascun array. Se invece di usare tanti array usassi una matrice, si potrebbe tramite un contatore ridurre di molto il codice, esempio leggo la prima riga da file, inserisco i dati nel primo elemento della matrice, la seconda riga da file nel secondo elemento, cosi potresti usare lo stesso codice per tutti i dati.Viceversa se uso array con nomi diversi devo scrivere del codice per ognuno.

Proviamo a fare un esempio di lettura file di testo e estrazione dati tramite strtok();

Invece di avere tanti array sostituiamo con una matrice in modo da automatizzare e ridurre il codice.

Potrebbero esserci degli errori MA LA LOGICA è QUESTA :slight_smile:

#include <SPI.h>
#include <SD.h>

File myFile;

int MieiDati[5][8]; // Matrice che sostituisce 5 array
char stringa[80]; // Variabile dove andiamo a salvare la riga letta da file
int i=0,j=0; // Variabili contatore 
void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  Serial.print("Initializing SD card...");

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }
  

  
 
}

void loop() {
  char c;
  i=0;
  j=0;
   myFile = SD.open("test.txt");
  if (myFile) {
    Serial.println("test.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available()) { // Se ci sono dati nel file
      c=myFile.read();
      if(c!='\n'){ // Se il carattere è diverso da fine riga
        // Ricordo che la riga con println ha due terminatori \r e \n
        stringa[i++]=c;
      }else{ // Abbiamo raggiunto la fine di una riga

           stringa[--i]='\0'; // Andiamo a sostituire il carattere \r con il terminatore stringa
           char *appoggio= strtok(stringa,",");//Prendo il primo dato della stringa
           MieiDati[j][0]=atoi(appoggio); // Trasformo la stringa in intero
           for(k=1;k<=7;k++){//ripeto per 7 volte
           
              appoggio=strtok(NULL,",");
              MieiDati[j][k]=atoi(appoggio); // inserisco i dati della stringa negli elementi della matrice K
           }
           
          // Finito di leggere una riga  porto il contatore i=0 per la nuova riga, incrementi j++ 

          i=0; // Per inserire nella variabile stringa da posizione zero
          j++; // Inserisco i dati nella nuova riga
      }
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
}

Domamda, e se io tutto questo lo facessi "a mano"? Potrei farlo solo avendo una matrice:
0) mi creo una funzione che mi legge e restituisce un carattere del file, a mo di seriale (fa tutto lei, lo apre, si ricoeda dove era arrivata, aggiorna, fa, dice, disfa...)

  1. se leggo una virgola faccio salire di 1 un indice e azzero il numero puntato
  2. se leggo un a capo faccio salire di 1 l'altro indice e azzero il primo e la variabile puntata
  3. se leggo una non cifra differente dalle precedenti errore
  4. se leggo una cifra variabile=variabile*10+carattere-'0'

Può andare?

Silente, dovresti comunque riconoscere i delimitatori e ricavare la sottostringa, questo la funzione strtok() lo fa molto bene quindi non c'è motivo di trovare soluzioni alternative.
Ci sono implementazioni "fai da te" dalla funzione strtok() puoi visionare i sorgenti.
Vale la regola, faccio io se non c'è niente di pronto o se posso fare meglio :slight_smile:

torn24:
Vale la regola, faccio io se non c'è niente di pronto o se posso fare meglio :slight_smile:

Concordo :wink:

Non chiara cosa
Quante righe sono scritte nel file?
Ma le scrivi tu?
Se le scrivi tu sii più esplicito nel protocollo e/o mostra il codice di scrittura
Io di lavoro non faccio l'indovino

Io ho questi dati di base che devo inviare, come li scrivo per registrarli su SD?

int variabile_1 [8] = {30005, 32423, 25000, 10797, 5744, 6456, 5656, 21656};
int variabile_2 [8] = {6, 6, 6, 6, 0, 7, 7, 6};
int variabile_3 [8] = {0, 7, 7, 7, 0, 10, 8, 7};
int variabile_4 [8] = {0, 8, 8, 8, 0, 0, 9, 0};
int variabile_5 [8] = {0, 9, 10, 9, 0, 0, 10, 0};

È stato citato nel code:

int MieiDati[5][8]; // Matrice che sostituisce 5 array
char stringa[80]; // Variabile dove andiamo a salvare la riga letta da file

Scusate la mia ignoranza, ma 80 indica il limite massimo dei caratteri oppure sarebbe 5 * 8 in tal caso non dovrebbe essere 40?

char stringa[80].

e poi come li riporto sempre nelle variabili suddette?

int variabile_1 [8] = {30005, 32423, 25000, 10797, 5744, 6456, 5656, 21656};
int variabile_2 [8] = {6, 6, 6, 6, 0, 7, 7, 6};
int variabile_3 [8] = {0, 7, 7, 7, 0, 10, 8, 7};
int variabile_4 [8] = {0, 8, 8, 8, 0, 0, 9, 0};
int variabile_5 [8] = {0, 9, 10, 9, 0, 0, 10, 0};

Con che metodo?

>patdepri: Potrebbe esserti utile lo studio di QUESTO e dei link ad esso correlati ... ::slight_smile:

Guglielmo

All'allora il tuo problema è prima scriverli e poi leggerli..