Blocco software datalogger

Ciao a tutti. Sto sviluppando un progetto e recentemente ho implementato la funzione datalogger, soprattutto per verificare che tutto giri correttamente nel lungo periodo. Al primo tentativo, al mattino lo trovo impallato e senza motivo apparente. Riesegui il test e idem come sopra. A questo punto noto che l'ultimo dato salvato è sempre alle 00:11 (valore letto da dispositivo Modbus 485 esterno). Ho iniziato a fare un pò di debug ed ho visto che nella procedura che uso per scrivere il file su SD si pianta al momento di aggiungere il valore "minuti" alla stringa valore...
Non capisco perchè! durante le altre ore del giorno non da problemi (io almeno ho testato dalle 14 in poi), alle 0:12 si pianta!

void Log(int ora, int minuti, int giorno, int mese, int anno)
  {
Serial.println("sono nel log");
    String valore = "";
Serial.println("ho azzerato la stringa");
    valore += String(ora);
    valore += ":"; 
Serial.println("ho inserito l'ora");
Serial.println(minuti);
    
    valore += String(minuti);
Serial.println("ho inserito i minuti");
    valore += " "; 
Serial.println("ho aggiunto il punto e virgola");
    valore += String(giorno);
    valore += "/"; 
    valore += String(mese);
    valore += "/"; 
    valore += String(anno);
    valore += ";"; 
    valore += String(regs[0]);
    valore += ";"; 
    valore += String(regs[1]);
    valore += ";"; 
    valore += String(regs[3]);
    valore += ";"; 
    valore += String(StatoAttivaPDCUTENZA);
    valore += ";"; 
    valore += String(StatoAttivaPDCACS);
    valore += ";"; 
    valore += String(StatoAttivaCLDUTENZA);
    valore += ";"; 
    valore += String(StatoAttivaCLDACS);
Serial.println("ho creato la stringa");
    File dataFile = SD.open("datalog.txt", FILE_WRITE);

    // if the file is available, write to it:
    if (dataFile) 
      {
      dataFile.println(valore);
      dataFile.close();
      // print to the serial port too:
      Serial.println(valore);
      }  
  // if the file isn't open, pop up an error:
  else 
    Serial.println("error opening datalog.txt");
}

PS: arduino mega 2560 rev 3 con ethernet shield e IDE 1.0.3

PS: inserisco screenshot del monitor seriale
http://img571.imageshack.us/img571/5398/monitorseriale.jpg

Quella è solo la funzione che scrive, ma il resto del programma l'hai controllato?
Hai visto se per caso hai qualche contatore o indice che potrebbe andar fuori range?

(ipotizzo, non sapendo che fai nel resto del programma)

Il problema mi è familiare: ho speso giorni per capire che il problema era l'oggetto String e molti di più per risolverlo.

Molti affermano che String non funziona correttamente ed in parte hanno ragione.

Nel tuo caso, però, mi sembra di capire che memorizzi una stringa sempre diversa, ma di lunghezza costante.

Quindi la soluzione più giusta è quella di usare una stringa normale (array di caratteri) di lunghezza X (il numero di caratteri necessario più uno).

Perciò supponendo che la lunghezza sia 27:

  char valore[28];

  valore[0] = ora / 10 + 48;
  valore[1]  = ora % 10 + 48;
  valore[2] = ':';
  valore[3] = minuti / 10 + 48;
  valore[4] = minuti % 10 + 48;
...
  valore[27] = 0;   // terminatore stringa

Quello che scrivi qui è uno dei motivi del perchè ho abolito il datalogger nel mio progetto, ho riscontrato lo stesso problema quando andavo a scrivere su sd, ma non credo sia un difetto tecnico, semplicemente in alcuni casi la flash è satura e il buffer non è in grado di contenere la stringa che deve scrivere.

Prova a ridurre la lunghezza delle stringhe da scrivere
Verifica quanta mem hai ogni volta che scrivi soprattutto alle 00:11
Prova a lasciarlo così, ma commenta il //serial.begin(9600) e metti un led lampeggiante (fatto con millis) così vedi visivamente se il micro si è schiantato.
Non c'è il resto dello sketch, ma potrebbe essere utile rivedere gli spazi occupati dalle variabili e possibile spostarle da pubbliche a private

cyberhs:
Molti affermano che String non funziona correttamente ed in parte hanno ragione.

In che senso non funzionerebbe? Quali sarebbero i problemi?

Per Leo:

Essenzialmente il problema si manifesta nel concatenamento di stringhe.

Quando la stringa assume una certa dimensione e c'è uno spazio Heap limitato, il crash è dietro l'angolo.

A suo tempo ho risolto il problema inizializzando la stringa non con una stringa vuota, ma con una stringa con una decina di caratteri o più secondo la necessità, sostituendoli con quelli corretti

In qualche modo la String pare non recuperare lo spazio impiegato (garbage collection) da precedenti assegnazioni (almeno così penso io).

Domani voglio provare a fare dei test, per vedere che succede. Non mi ricordavo di questa cosa (l'avevi già detto, ora che l'hai citata).

Grazie a tutti per l'interessamento.

  • il programma legge da bus 485, comunica via i2c con un lcd 16x2, pilota 4 uscite a relè (tramite transistor), legge 4 pulsanti su ingressi analogici. quando si "pianta" nessuna di queste funzioni funziona più.
  • questione memoria: lo escluderei, in quanto il programma può girare per ore senza bloccarsi, ma se imposto l'orario alle 0:09 dopo 3 minuti non funziona più.
  • visto il debug, che si blocca tra la riga in cui accodo il ";" e la riga in cui inserisco "minuti", escluderei che la causa sia da ricercarsi altrove
  • il datalogger mi serve, in quanto devo monitorare funzionamento e temperature in case a centinaia di km di distanza
  • la lunghezza della stringa è si variabile, ma alle 0:12 ha la stessa lunghezza che alle 0:10 o alle 0:11... stasera appena torno a casa provo a definire la stringa di lunghezza fissa e poi vi aggiornerò sui risultati.

Buona giornata

cyberhs grazie, non utilizzando String funziona!
Per me resta un mistero perchè si piantasse proprio a quel determinato valore…
Ora lascio lo sketch in test per alcuni giorni, vediamo che non succedano altre sorprese!

Grazie a tutti!

Leo se ricordi riferiti anche io bug su string. Una stringa lunga, creata concatenando, per farla funzionare l'ho dovuta dividere.
Provate anche voi quando avete problemi a dibiderla, basta metterla su righe diverse e poi si sommano i risultati.

Ho fatto dei test costruendo una stringa concatendo più pezzi di testo su più righe ma non sono riuscito a mandare in crash l'Arduino.

x Leo:
La cosa che mi stupisce, è che la funzione viene chiamata centinaia di volte! e si blocca solo quando ora=0 e minuti=12! se imposto l'orologio del dispositivo da cui leggo l'ora a 0:10, si blocca dopo due chiamate, se lo imposto a 14:00 si ferma dopo 10 ore e 12 minuti...è proprio la sequenza

valore += String ("0");
valore += String (";");
valore += String ("12");

che pianta tutto. Concatenando i char invece stà funzionando da ieri sera

Ho provato questo sketch su una Leonardo:

byte minuti;
byte secondi;
void setup() {
    Serial.begin(19200);
    while(!Serial);
}

void loop() {
    String valore = "";
    valore += String (minuti);
    valore += String (";");
    valore += String (secondi);
    Serial.println(valore);
    secondi++;
    if (secondi > 59) {
        minuti++;
        secondi = 0;
    }
    delay(1000);
}

Funziona passando il punto critico "0;12"

Su suggerimento di un collega e incuriosito da questo strano caso, una volta a casa (scusate il gioco di parole) voglio provare a modificare il separatore o inserire un carattere per vedere se cambia qualcosa.

Leo: non credo cambi niente, ma io utilizzavo ":" non ";" come separatore tra ore e minuti, ho sbagliato a scrivere l'ultimo post. Inoltre la variabile era di tipo int... Stasera provo e vediamo. Più che altro per curiosità , perchè, come dicevo prima, ora che l'ho modificato lo sketch funziona.

Ho messo int al posto di byte e sostituito ":" al ";" ma il risultato non cambia, nel senso che lo sketch gira senza problemi.
Boh...

leo72:
Ho provato questo sketch su una Leonardo

Bisognerebbe provarlo su una Mega, come la sua.
Non so se la libreria e dipendente dal tipo di micro utilizzato. :roll_eyes:

PaoloP:

leo72:
Ho provato questo sketch su una Leonardo

Bisognerebbe provarlo su una Mega, come la sua.
Non so se la libreria e dipendente dal tipo di micro utilizzato. :roll_eyes:

Ieri ho provato con una UNO e non riuscivo a replicare il bug. Se è un problema software, questo dovrebbe manifestarsi con tutte le schede.

Per Leo:
Se rileggi quello che ho scritto

Quando la stringa assume una certa dimensione e c'è uno spazio Heap limitato, il crash è dietro l'angolo.

comprenderai che devi ridurre lo spazio Heap con delle assegnazioni di costanti, ad esempio, per riprodurre le condizioni di crash.

Riflettiamo insieme.
Supponiamo che la Stinga X contenga "ABCD": il puntatore punterà ad una certa locazione di memoria Y nella Heap.
Se aggiungiamo "EFG" quale sarà il nuovo puntatore? Uno nuovo Z che fa riferimento al concatenamento "ABCDEFG".
Cosa succederà alle locazioni di memoria del puntatore Y "liberate"? Saranno impiegate da una nuova assegnazione, ma solo se la nuova assegnazione contiene un numero di caratteri pari od inferiore a 4.
L'algoritmo "Garbage Collection" serve a recuperare questi spazi inutilizzati nella Heap, ricompattando le varie stringhe.
Un qualcosa di molto simile al comando "Deframmentazione dischi" di Windows.
Purtroppo è un algoritmo "costoso" in termini di tempo e non credo sia implementato in Arduino.

Mi pare che un difetto del C sia proprio l'assenza di un Garbage Collection. :frowning:

[OT]
Un articolo sull'argomento --> Garbage Collection in C Programs | Linux Journal
[/OT]

Anche io su una Mega ho avuto un problema molto simile... anche se pensavo fosse che il problema fosse il display via i2c.
Invece poi con dei test, avevo trovato che si bloccava nella scrittura del file nel SD.
Io poi ho risolto con questo concatenamento

Buffer += (now.day());
Buffer += ('-');
Buffer += (now.month());
Buffer += ('-');
Buffer += (now.year());
Buffer += (',');
Buffer += (now.hour());
Buffer += (':');
Buffer += (now.minute());
Buffer += (':');
Buffer += (now.second());
Buffer += (',');
Buffer += dtostrf(t,3,2,s);
Buffer += (',');
Buffer += dtostrf(h,3,2,s);
Buffer += (',');
Buffer += dtostrf(valLux1,3,2,s);

Se invece lo inserivo tutto in una stringa in seriale, ad un certo punto mi si bloccava tutto.