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
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)
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
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).
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.
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!
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.
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
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.
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.
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