cyberhs:
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.
cyberhs, sì capisco che il problema risieda nell'occupazione di memoria (dato che variabili, stack ed heap vivono tutti nella SRAM) però tapirinho dice che ha il problema solo ed esclusivamente con la stringa 0:12. Ha detto che se il codice può girare anche per 10 ore: dopo 10 ore mi attenderei un esaurimento di memoria. Ma se fa partire l'orologio alle 0:10 e gli si blocca alle 0:12, 2 minuti contro 10 ore stonano se letti con l'occhio dell'heap collassato.
Io stesso ho difficoltà a comprendere appieno il motivo e ho dato una spiegazione basata sulla logica e la mia esperienza, ma non è detto che sia la risposta giusta.
Sta di fatto che quando si hanno situazioni del genere (tapirinho afferma di aver risolto il problema usando stringhe a lunghezza costante) si è indotti a credere che il problema sia dovuto ad altri motivi e si perde un sacco di tempo.
Tempo fa ho iniziato un manuale sull'oggetto String che dovrebbe aiutare a comprendere il problema, ma mi sono imbattuto nel tuo stesso problema: la non facile riproducibilità del crash.
superzaffo:
Se invece lo inserivo tutto in una stringa in seriale, ad un certo punto mi si bloccava tutto.
mi ha aperto gli occhi, o per meglio dire il vero modo per riprodurre forse il bug. La creazione di una stringa con concatenazioni multiple tutte su una stessa riga. Ora non ho riguardato il codice dell'oggetto String ma se non ricordo male il problema è che se la classe trova una sequenza di concatenazioni, essa ad ogni concatenamento crea una nuova stringa autorichiamandosi ricorsivamente. Quindi la memoria viene esaurita dalla continua creazione di oggetti String. Solo alla fine vengono cancellati, quando la funzione termina (perché per via della visibilità, essi non esistono più essendo terminata la funzione che li aveva creati).
Su quello che tu dici, allora ha senso l' esaurimento della memoria, perchè con la creazione di un istanza stringa per ogni "+" questa potrebbe mandare il tutto in owerflow.
Purtroppo al momento non ho un arduino mega disponibile per provare, ma in teoria dovrebbe succedere anche con un altro tipo di arduino.
Lo avevo detto fin da subito che col codice a pezzi si tirava a indovinare.
leo72:
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)
Anche perchè, ho visto ora il print screen, ci sono regolamente una serie di caratteri strani che non capisco da dove arrivano.
Esattamente dopo che ha fatto un println della stringa da salvare.
Non so se sono corretti o meno...
...La creazione di una stringa con concatenazioni multiple tutte su una stessa riga. Ora non ho riguardato il codice dell'oggetto String ma se non ricordo male il problema è che se la classe trova una sequenza di concatenazioni, essa ad ogni concatenamento crea una nuova stringa autorichiamandosi ricorsivamente...
Leo, è stata una delle prime prove che ho fatto, ma con risultati a volte positivi, a volte negativi.
Più che programmazione logica sembrava di essere scesi in quella esoterica!
Sto per mettermi a fare delle modifiche allo sketch non funzionante, poi vi aggiorno!
Quei caratteri strani sono creati dalla comunicazione Modbus sui pin digitali 0 e 1, e ci sono sempre.
Il problema l'ho risolto non usando più string, ma usando l'array di char.
Se volete vi posto tutto il codice, sono circa 1000 righe, usando svariate librerie alcune delle quali implementate da me...
Comunque ora provo a fare un mini-sketch come quello che ha provato leo!
Stay tuned!
ore 22:30
con questa piccola modifica funziona! "Inizializzando" valore con una serie di caratteri (numero a caso) vuoti non si pianta!
void Log(int ora, int minuti, int giorno, int mese, int anno)
{
String valore = " ";
valore += String(ora);
valore += ":";
valore += String(minuti);
valore += " ";
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);
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.print("error opening");
}
Ho isolato lo sketch!!! Mi sembra di essere Pasteur!
Questo sketch si pianta al valore 0:12, almeno sul mio Arduino Mega. Ho provato con l'Arduino Uno R3 e si pianta a 0:09, l'ultimo messaggio su seriale dice "error opening".
Ai moderatori l'ardua sentenza...
#include <SD.h>
int minuto=0;
int ore=0;
const int chipSelect = 4;
void setup()
{
if (!SD.begin(chipSelect))
Serial.println("Card failed, or not present");
Serial.begin(9600);
while(!Serial);
}
void loop() {
minuto++;
if (minuto > 59) {
ore++;
minuto = 0;
}
Log (ore,minuto,21,01,13);
delay(1000);
}
void Log(int ora, int minuti, int giorno, int mese, int anno)
{
String valore = "";
valore += String(ora);
valore += ":";
valore += String(minuti);
valore += " ";
valore += String(giorno);
valore += "/";
valore += String(mese);
valore += "/";
valore += String(anno);
valore += ";";
valore += String("121");
valore += ";";
valore += String("132");
valore += ";";
valore += String("122");
valore += ";";
valore += String("1");
valore += ";";
valore += String("1");
valore += ";";
valore += String("0");
valore += ";";
valore += String("1");
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");
}
tapirinho:
Ho isolato lo sketch!!! Mi sembra di essere Pasteur!
Questo sketch si pianta al valore 0:12, almeno sul mio Arduino Mega. Ho provato con l'Arduino Uno R3 e si pianta a 0:09, l'ultimo messaggio su seriale dice "error opening".
Ai moderatori l'ardua sentenza...
Su una UNO R1 l'unico messaggio che scrive per 10 volte è "error opening" perché non avendo la SD da errore in accesso.
Però qui siamo ad un punto morto. Ho integrato una lib per vedere la memoria libera e ricevo 950 byte fino al "botto", quando mi scrive curiosamente 2237 byte! Impossibile, dato che l'Atmega328 ha 2048 byte di SRAM. La cosa curiosa è che la scritta compare, quindi il "botto" si verifica quando è uscito dalla funzione Log.
beh si, se non hai la SD...
comunque con la UNO r3 anche a me da un messaggio diverso, cioè scrive la stringa 9 volte, poi alla decima da "error opening" e si pianta...come a te! ciò significa che la procedura Log viene eseguita. onestamente non ho fatto verifiche sulla memoria, volevo solo segnalare a chi sicuramente ne capisce più di me un'anomalia. Se serve per migliorare, sono ben disposto a contribuire, nel mio piccolo!
Boh, succede qualcosa nella gestione delle stringhe, è sicuro...
Ho provato usando la funzione per la restituzione della memoria libera inserita tra ogni concatenamento, e ad un certo punto inspiegabilmente la Ram schizza a oltre 2200 byte... è ovvio che si incasini ogni cosa, c'è qualche cosa interna che va a farsi benedire.
Provate a fare così, una pre-assegnazione per allocare spazio nell'Heap:
...
void Log(int ora, int minuti, int giorno, int mese, int anno) {
String valore = "inserite qui un numero di spazi o caratteri pari alla grandezza massima che occuperà la stringa"; // pre-inizializzazione
valore = ""; // inizializzazione
valore += String(ora);
valore += ":";
valore += String(minuti);
valore += " ";
valore += String(giorno);
valore += "/";
...
Quindi se questo funziona il problema sarebbe nella frammentazione delle pagine quando fa un concatenamento successivo.
Perchè se tu inizialmente allochi tutta la stringa in solo colpo, lui cerca di occupare la ram contigua.
Mi vien da pensare questo....
Sarebbe da capire se il problema sta in tutte le versioni dell' ide.
Posted on: Today at 02:20:09 PM
Posted by: cyberhs
Insert Quote
Provate a fare così, una pre-assegnazione per allocare spazio nell'Heap:
Code:
...
void Log(int ora, int minuti, int giorno, int mese, int anno) {
String valore = "inserite qui un numero di spazi o caratteri pari alla grandezza massima che occuperà la stringa"; // pre-inizializzazione
valore = ""; // inizializzazione
valore += String(ora);
valore += ":";
valore += String(minuti);
valore += " ";
valore += String(giorno);
valore += "/";
...
Io avevo provato, se quando dichiaro valore la riempio di caratteri vuoti non si blocca più