Buonasera a tutti, nel progetto che sto portando avanti sto monitorando una temperatura, inserendola in un array di 720 indici in modo da avere uno storico e infine la grafico tramite un display nextion.
Ovviamente salvando la temperatura in un array, ogni volta che l'arduino mega si riavviava perdevo tutto lo storico, ed è per questo che adesso ogni volta che faccio una nuova lettura di temperatura, aggiorno l'array e vado a scriverlo in un file di testo in una microSD.
Il codice per svuotare il file di testo e per il nuovo inserimento è il seguente;
Al riavvio dell'arduino vado a leggere tutte le righe del file .txt e inserisco le temperature nell'array, e fin qui tutto bene.
Il problema che riscontro è che se per sfortuna l'arduino si spegne mentre sto sovrascrivendo i dati vecchi con quelli nuovi, perdo tutto quanto.
Volevo chiedervi quale potrebbe essere una soluzione a questa mia problematica.. Ho pensato di creare una copia e nel caso in cui all'avvio vedo che il file di testo è vuoto andare a pescarmi i dati dall'altro file ma mi sembra poco "elegante".
credo invece che sia la soluzione migliore....
ogni altra soffrirebbe del problema di una possibile interruzione
ma secondo me ci sono strade alternative, che implicano azioni differenti dal cancellare e ricreare il file tutte le volte
io eviterei di cancellare e riscrivere tutte le volte il file
mi limiteri ad accodare, su due file separati, apro, salvo una riga e chiudo, apro il secondo salvo e chiudo
mi assicuro di avere un formato dati a lunghezza fissa,
in sede di avvio leggo la dimensione dei due file, e scelgo il maggiore dei due
mi serve di ricaricare le ultime 100 righe, calcolo la posizione della prima riga che mi serve togliendo 100 * lunghezzadelformato dalla lunghezza del file
ci arrivo con una seek
leggo le righe una ad una e carico lo array
poi, se i due file erano di pari lunghezza tutto bene, altrimenti cancello quello corto, apro in lettura l'altro e copio riga a riga dentro un nuovo file dello stesso nome di quello cancellato
un po' di calcoli da fare in sede di progettazione del formato file, per "pigliarci giusto" coi calcoli della seek, ma fatto una volta fatto per sempre
Grazie per gli spunti, adesso ci studio su con calma.
Solo una domanda, io fino a che non riempio l'array con i primi 720 valori, nel file di testo continuo ad accodare..
una volta che ho raggiunto i 720 valori inizio a shiftare con una tabella a scorrimento, ed è per questo che pensavo di cancellare tutto e riscriverlo da zero, perchè tutte le righe nel file di testo saranno sfalsate di 1...
Quello che te consigli di fare invece è continuare a salvare "all'infinito" e andare sempre a pescare le ultime 720 righe oppure ho capito male?
Ok ho capito. Per quanto riguarda il file di testo c'è un limite di righe massimo oppure si può veramente continuare a scrivere in coda senza problemi?
Sto usando un mega originale, a dirla tutta ho riportato un esempio semplificato, ma in realtà mi sta gestendo 4 array di byte da 720 indici l'uno senza nessun problema
Le dimensioni massime di un file system fat sono belle grandi, casomai ogni tanto fai troncare i due file (crei copia, copi le ultime 700 e fischia righe, cancelli originale una cosa così)
bubba21:
Sto usando un mega originale, a dirla tutta ho riportato un esempio semplificato, ma in realtà mi sta gestendo 4 array di byte da 720 indici l'uno senza nessun problema
720 * 4 = 2880 byte. Il Mega ha 8 KB di RAM, nessuna sorpresa dunque.
Per il resto, puoi adottare la strategia di scrivere in un file nuovo temporaneo ogni volta e, una volta terminata la scrittura, rinominarlo con il nome del file definitivo. In un filesystem ideale dunque dovresti sempre trovarti un file intero, che è quello vecchio se è mancata alimentazione durante la scrittura, o quello nuovo se è andato tutto bene. FAT non è un filesystem così solido, comunque dovresti diminuire di molto la probabilità di corruzione del filesystem.
Però concordo che anche io accoderei sempre una linea allo stesso file, mantenendo uno storico dei dati. All'occorrenza vado a pescare quelli che servono.
Comunque non è solo che FAT non è un file system robusto, temo che anche implementazioni di, per esempio NTFS o EXT4, su arduino sarebbero povere e non robuste
Piuttosto si tiene tripla copia, oppure quando si tronca un file se ne tiene storico.
Ma se lo OP ci spiega bene bene quello che vuole fare
Ho il sospetto che non gli serve uno storico completo, ma solo le ultime letture
Nel caso al riavvio se ne approfitta per troncare a quello che serve
Provo ad essere più specifico in modo da farvi capire meglio quello che sto facendo.. Ho un grafico a cui ho fissato un asse X di 4 ore e lo riempio campionando ogni 20 secondi per 720 campionamenti. Una volta raggiunte le 4 ore aggiorno l'array perdendo il valore più vecchio e inserendo quello nuovo (è giusto il termine FIFO ?).
Sempre per essere precisi, io inizio a registrare le temperature una volta che inizio un ciclo di riscaldamento, il quale teoricamente dura all'incirca poco più 4 ore (ma potrebbe protrarsi di più in caso di problemi). Quindi la prima cosa che farò quando inizio un nuovo ciclo sarà quella sicuramente di svuotare il file e di conseguenza la dimensione massima non sarà mai "esagerata".
Ieri sera l'ultima cosa che ho fatto è stata quella di formattare la riga che salvo sul file .txt in modo da avere sempre una lunghezza fissa.
Questa sera potrei provare ad accodare continuamente le ultime righe e con il metodo seek andare a rileggermi solo le ultime 720 righe.
Rieccomi qui, ho appena finito di testare le modifiche che avete suggerito.
Ricapitolando, adesso continuo a salvare accodando le nuove temperature (ho formattato la riga in modo da avere sempre la stessa lunghezza totale), senza mai sovrascrivere o cancellare nulla.
In fase di avvio dell'arduino vado a leggere quante righe ho scritto fino a quel momento e con un semplice calcolo mi posiziono con un SEEK sulla riga dalla quale inizieranno le mie 720 temperature..
Fatto questo rileggo il file di testo ed estrapolo le temperature.
E' più facile a farsi che a dirsi, ho testato più e più volte ed è praticamente impossibile riuscire a perdere il file di testo riavviando l'arduino in fase di salvataggio dato che vado a scrivere solo una riga nuova.
Di seguito il codice che uso, mi farebbe piacere sapere se è corretto o se deve essere modificato
progressivo = 0;
posizionatore = (y - indiciCampionamento) * 6; // (numero totale di temperature salvate - numero righe da leggere) * numero di caratteri in una riga
myFile.seek(posizionatore);
while(myFile.available()) {
String subStrSD = myFile.readStringUntil('\n');
temp = subStrSD.toInt();
arrayTemp[progressivo] = temp ;
progressivo++;
}
myFile.close();
Seho capito bene, con il primo frammento conti le righe totali
con il secondo invece calcoli record a record gli ultimi 720
credo che nel primo tu ti sia dimenticato il file.close() finale, ma è peccato minore....
invece non usare, non usare mai, gli oggetti stringa, non c'è nessun caso dove sono necessari, in particolare non adesso dove hai una lunghezza fissa del record
appena passerà di qui Guglielmo ti farà un pistolotto tecnico sul perchè gli oggetti Stringa sono il male assoluto, l'anticristo, la Nemesi, Armageddon la tintoria non mi aveva consegnato il Tight, c'era il funerale di mia madre, avevo una gomma a terra, non è stata colpa mia logiurosuddio.....
Ops, scusa, avevo confuso due postolotti, sai, l'insonnia....
comunque evita gli oggetti stringa
per cominciare, come esercizio propedeutico, potresti cominciare a fare:
in 'C' non sei obbligato a usare il valore di ritorno di una funzione, quindi non crei l'oggetto Stringa che tanto non usi
ma questo è solo l'inizio,
gli oggetti stringa vanno eradicati come la gramigna, non si usano, non se ne usano le funzioni, ci si dimentica cosa sono
altri suggerimenti:
invece di readstringuntil prova a fare una read esplicita e testare se il carattere letto è un fine riga, conti i fine riga, tanto non è più lento, la readstringuntil così fa'
quando hai la posizione di inizio del primo recor che ti interessa, sapendo la lunghezza record scrivi in un array di char di dimensione adeguata i singoli caratteri e poi usi la atoi()
senza nemmeno contare, potresti farlo sempre e comunque, usando un array circolare e semplicemente scrivendo tutte le righe lette, magia quando sei arrivato all'ultima hai fatto il lavoro senza accorgertene
cominciamo con una domanda propedeutica: cme popoli attualmente l'array, durante il normale funzionamento, non durante l'avvio?
EDIT
scusa me ne ero dimenticato
il mio non è un pistolotto per dire che hai sbagliato, anzi
complimenti per quello che hai ottenuto,
se fosse su un PC sarebbe pressocchè perfetto
quindi i complimenti te li meriti
sono io che sono geneticamente incapace a farli, scusami
Standardoil:
... appena passerà di qui Guglielmo ti farà un pistolotto tecnico sul perchè gli oggetti Stringa sono il male assoluto, l'anticristo, la Nemesi, Armageddon la tintoria non mi aveva consegnato il Tight, c'era il funerale di mia madre, avevo una gomma a terra, non è stata colpa mia logiurosuddio ...
Perché contare le righe? Hai righe a lunghezza fissa, e vuoi arrivare all'ultima. Ergo basta settare a (file.size()-numerorighelunghezzariga-lunghezzariga+1).
A miofile.size() hai l'ultimo carattere dell'ultima riga, numerorighelunghezzariga prima hai l'ultimo della prima riga voluta, lunghezzariga prima hai l'ultimo carattere non voluto, ilnsuccessivo del quale é il primo voluto
Standardoil, esatto nella prima parte conto le righe e con la seconda parte estrapolo gli ultimi 720 record.
Il file.close è nella seconda parte, apro il file all'inizio e lo chiudo alla fine nella seconda parte.
Ti ringrazio per i consigli e i suggerimenti, questa sera elimino la stringa e metto tutti in un array di char (alla fine è quello che faccio quando vado ad inserire i record formattandoli), non vedo perchè non devo farlo per andare a leggerli : Guglielmo ha perfettamente ragione, per ignoranza mia tendo ad usare le stringhe come scorciatoia ma mi rendo conto che è totalmente errato ed è uno spreco assurdo, cercherò di abituarmi ad usare i char array.
Sei stato molto chiaro nei primi due punti, non ho mica capito il 3° punto, per quanto riguarda l'array circolare non ho mica capito
Questa sera posto la parte di codice dove popolo l'array fino ai 720 indici, e la parte di codice dove gestisco la tabella a scorrimenti, anche perchè sono convinto che ci potrebbe essere un modo "più intelligente" per farlo rispetto al mio.
Grazie per i complimenti, fanno sempre piacere soprattutto dai più esperti, ma ci tengo a ribadire che senza i vostri aiuti sarebbe tutto praticamente impossibile, quindi i veri complimenti devono essere fatti a voi!
Silente, grazie anche a te per il consiglio, questa sera provo a metterlo in pratica!
bubba21:
... Guglielmo ha perfettamente ragione, per ignoranza mia tendo ad usare le stringhe come scorciatoia ma mi rendo conto che è totalmente errato ed è uno spreco assurdo, cercherò di abituarmi ad usare i char array.
Attento, non è che sia in genere errato, anzi, tutt'altro; su sistemi dove c'è memoria in abbondanza, dove c'è un sistema operativo ed un garbage collector che a sua volta richiama un processo di memory compaction, va benissimo, facilitano la vita e non danno problemi.
Il guaio è che ... tu sei su Arduino e ... tutto quello che ho elencato NON c'è ... da qui tutti i problemi
Due cose:
Per lo array circolare: ne parliamo stasera, ma occorre pazienza, dopo il lavoro vado al lago, sarà sul tardi
Invece un dubbio, per chi ne sa più di me
La file.size() restituisce realmente la lunghezza del file, o solo legge lo spazio occupato nel file system? Perché mi sa ché non sarebbero lo stesso numero
Per chi ha una shield sd può fare la prova?
Sono appena tornato da lavoro (niente lago per me ) e ho subito provato il myFile.size().
Contando le righe una ad una come sto facendo mi ritrovo con "4268" righe salvate.
Il myFile.size() mi restituisce "25608".. Facendo banalmente 25608 / 6 (che sarebbero i caratteri per riga), ho come risultato "4268", mi verrebbe proprio da dire che il file.size() restituisce il numero totale dei caratteri presenti sul file (ho fatto questa prova più volte man mano che salvava nuovi valori).
Quindi direi che la lettura totale dei record si è semplificata decisamente.
gpb01, ti ringrazio per la precisazione
Standardoil:
cominciamo con una domanda propedeutica: cme popoli attualmente l'array, durante il normale funzionamento, non durante l'avvio?
Ecco qui come faccio, le 5 variabili sono globali in realtà
int indiciCampionamento = 720; // Numero di temperature necessarie per riempire il grafico
int y; // indice progressivo del numero di record salvati
byte arrayTemp[720]; // array storico
char nuovaTemperatura[10]; // temperatura inserita nel file .txt
if ( !fineCampionamento ) {
arrayTemp[y] = temperatura;
} else {
for(int p = 1; p < indiciCampionamento; p++) {
arrayTemp[p-1] = arrayTemp[p];
}
arrayTemp[indiciCampionamento - 1] = temperatura;
}
// Inserisco la nuova temperatura
myFile = SD.open("Test.txt", FILE_WRITE);
if (y < indiciCampionamento) sprintf(nuovaTemperatura, "%4d", arrayTemp[y]);
else sprintf(nuovaTemperaturat2, "%4d", arrayTemp[indiciCampionamento - 1]);
myFile.println(nuovaTemperatura);
myFile.close();
y++ ;
if (y >= indiciCampionamento) fineCampionamento = true;