Go Down

Topic: Loop nel Loop (Read 4403 times) previous topic - next topic

DanielaES

Ma infatti non metto in dubbio il tuo codice :)
e nemmeno l'else! è una cosa talmente elementare che non ha senso che impalli tutto il sistema.

La mia ipotesi?
che centri la libreria SD, questi errori si stanno verificando sempre quando trovo queste quattro condizioni:

c'è un ciclo if else
c'è un operazione sulla SD nel ciclo (open/close/write)
il file su cui si opera NON è in root
all'interno del ciclo c'è un Serial.print / lcd.print

Per ora questo problema mi è capitato 2 volte.
Con la creazione del file di log: avevo un ciclo if/else, una operazione sd, il file non in root ed un lcd.print
Con il loop del datalogging: idem come sopra ma con un Serial.print

O molto più semplicemente magari mi sfugge qualcosa nel mio codice, ma non saprei proprio cosa.
Tolgo quel else, tutto funziona. Metto quel else tutto si blocca.

Per il momento, ho tolto l'else e vivo felice, dubbiosa ma felice.
Credimi, penso che arriverei a pagare per togliermi la curiosità, ma suppongo mi resterà il dubbio a vita :)

riquito

Leo ha dato un ottimo codice di test. Se ti funziona come dovrebbe, mi chiedo se per caso, visto che il tuo codice non era intero, tu non abbia lasciato il
delay(1000)
fuori dal blocco di codice che contiene l'else incriminato (così facendo inonderesti la seriale di dati).

Da quello che hai postato non si direbbe, ma meglio chiedere :)

leo72

Non volevo dire che il mio codice era perfetto, volevo rimarcare il fatto che non penso ad un bug dell'IDE.

Adesso analizziamo il problema.
Il costrutto if-then-else come viene analizzato?

SE condizione ALLORA
 blocco1
ALTRIMENTI
 blocco2
FINE SE

blocco2 NON può essere influenzato da blocco1 se condizione non è vera. C'è un test e se il test è negativo, semplicemente il processore salta il codice dopo ALLORA per eseguire il codice introdotto da ALTRIMENTI.

Non capisco perché dovrebbe influenzare la presenza della gestione dell'SD... mannaggia....

Ascolta, fai una prova. Commenta TUTTO quello contenuto nel blocco1 (ossia la scrittura sulla SD) e lascia solo un Serial.println("Cucu") e vediamo cosa succede.

DanielaES

Leo, siccome sei tu, ti faccio la prova, anche se so già i risultati irreali che verranno fuori :D
ed infatti...

Con questo codice, funziona. Il ciclo stampa a seriale "Non Loggato".
LCD mostra i sensori e via dicendo.
Code: [Select]
Serial.println (contatore);
  if (millis()>contatore) { //sono passati 55 s
    contatore=millis()+55000;
    /*
    Serial.println ("Dati Loggati.");
    lcd.setCursor(2, 0); // localizzazione per segno logging
    lcd.write(0); // richiamo carattere custom 0, grado ° - indice log

    //DataLogging
    myFile = SD.open(nomefilelog, FILE_WRITE);
    myFile.print(now.unixtime()); // seconds since 2000
    myFile.print(", ");
    myFile.print(now.year(), DEC);
    myFile.print("/");
    myFile.print(now.month(), DEC);
    myFile.print("/");
    myFile.print(now.day(), DEC);
    myFile.print(" ");
    myFile.print(now.hour(), DEC);
    myFile.print(":");
    myFile.print(now.minute(), DEC);
    myFile.print(":");
    myFile.print(now.second(), DEC);
    myFile.print(", ");
    myFile.print(tout); // tout DHT
    myFile.print(", ");
    myFile.print(hout); // rh out DHT
    myFile.print(", ");
    myFile.print(tin); // tin DHT
    myFile.print(", ");
    myFile.print(hin); // rh in DHT
    myFile.print(", ");
    myFile.print(T1); // h20
    myFile.print(", ");
    myFile.print(T2); // hot
    myFile.print(", ");
    myFile.print(mediaHz); // media dei valori di luce dall'ultimo log
    myFile.print(", ");
    if (A3 == HIGH) { //status pin A3 - SSR
      myFile.println("1");
    }
    else {
      myFile.println("0");

    }
    myFile.close();
    */
  }

else {
  Serial.println ("Non loggato");
}


Se tolgo il commento, si blocca tutto.
L'unica cosa che appare in seriale è:
Quote
Initializing SD card...initialization done.

e poi basta, lcd vuoto ecc.

Bello eh? ammettilo che sei perplesso :P

Prossimamente dovrò fare un "porting" e passare dalla lib SD dell'IDE al SDfat, perché tinywebserver utilizza quella e non ha senso averne due ad occupare spazio.
Ovviamente proverò anche con la nuova libreria per vedere se si riproduce l'errore.
Ed ora vado a farmi un bel bagno caldo :)

P.s.
al solito, grazie del tempo che perdete a starmi dietro.
L'ho già detto che senza il forum probabilmente non avrei fatto nulla? :)


leo72

L'unica cosa che puoi fare è segnalare il problema nella sezione internazionale del forum.

Ti suggerisco un'ultima prova. Togli tutto il blocco del codice dopo l'if e mettilo in una subroutine.
Code: [Select]
if (millis()>contatore) {
  scriviLog();
} else {
  Serial.println ("Non loggato");
}

void scriviLog() {
  contatore=millis()+55000;
  Serial.println ("Dati Loggati.");
  .....ecc...
}


Secondo me NON cambia nulla ma siccome siamo a fare 1000 prove.... puoi fare anche questa  :smiley-sweat:

uwefed

Le 2 cose che mi vengono in mente ma che non Ti aiutano tanto nel immediato:
1) Usi troppa RAM e percui sovvrascrivi delle parti che il controller usa per le variabili di sistema.
2) Hai fatto un errore di dimensiamento di un array o di un puntatore e sei uscito dallo spazio risevato per tale variabile percui sovrascrivi altre variabili col esito che si comporta in modo stranissimo.
Ciao Uwe

DanielaES

scrivo di straforo perché se durante le feste la mia dolce metà mi becca ancora con l'arduino mi sgrida :P

Leo, sett prossima faccio la prova sicuramente.
Avevo già pensato alle subrutine ma per un motivo completamente diverso...
Come si scrive un Buon codice? subrutine fuori dal loop richiamate, oppure mettendo le cose direttamente nel loop?
ci sono diverse operazioni che potrei spostare fuori dal loop. Cambia qualcosa? Ottengo prestazioni migliori/peggiori?

Per uwefed
1) c'è un modo di vedere quanta ram uso? un qualche debug da seriale? sarebbe un info molto utile.
2) non ho capito minimamente cosa devo andare a cercare, se hai voglia di spiegarmi in modo semplice e dettagliato cosa devo guardare, mi metto volentieri a spulciare il codice :)

Buone feste!

leo72

La questione RAM è molto spinosa.

Intanto bisogna partire da un concetto, l'architettura del micro.
Non siamo di fronte alla classica architettura dei PC, dove la memoria disponibile è divisa tra codice e dati dello stesso: quindi la RAM contiene sia il programma da eseguire sia tutti i dati che lo riguardano, come le variabili e le costanti. In un microcontrollore come l'Atmel l'architettura è di tipo Harvard, ciò significa che la Flash contiene il programma dell'utente mentre la SRAM contiene l'heap, lo stack e le variabili. Il problema dei micro è che la loro dotazione di SRAM è piccola: il 328 ha solo 2 kB di RAM, dove devono risidere tutti i dati su citati.
Inoltre il micro non legge i dati (a meno di non intervenire in maniera esplicita usando PROGMEM) direttamente dalla Flash ma tutti i dati vanno copiati prima nella SRAM. Usando i display si incorre spesso nel consumo di memoria perché più stringhe di testo si mettono e più è facile consumare la memoria. Se a questo unisci array, tante variabili, buffer dei file, immagini come sia facile pensare di poter consumare memoria.

Per sapere quanta memoria disponibile resta ci sono 2 metodi: uno in runtime ed uno statico. Il primo fa uso di free(), l'altro di avr-size. Entrambi sono stati analizzati e spiegati diverse volte, se li cerchi sul forum troverai come usarli.

Detto questo, tornando al codice, non esiste un solo modo per scrivere del "buon codice". Mettere porzioni di codice in subroutine è utile quando il codice può essere richiamato da diversi punti del programma e scrivere sempre gli stessi algoritmi comporta ripetitività e consumo di memoria inutile. Ma se hai un solo punto dove un algoritmo è usato, inserirlo in una subroutine è controproducente perché per ogni salto il micro deve salvare il punto di esecuzione del tuo programma per il successivo ripristino, quindi alla fine potresti consumare più memoria di quella che risparmieresti in altri casi.

MauroTec

Anche io sono convinto che il problema sia la memoria, ma come dice leo è difficile stabbilire quanta ne stai occupando, perchè la seriale ha il suo buffer, in più durante il lavoro delle variabili locali prendono memoria che viene rilasciata all'uscita dalla funzione. Ops ho dato per scontato che sai il discorso delle variabili locali, molto in breve "le variabili locali durano e sono visibili solo dentro un blocco delimitato da {}, es una funzione è un blocco di codice con variabili locali se dichirate dentro il blocco.

La libreria Ethernet prende pure parecchia ram, così pure la sdfat.

Puoi tentare di fare economia nel tuo programma ma non puoi fare nulla per limitare l'occupazione di memoria delle librerie.

Questa cosa ti farà girare le scatole, ma ci sta tutta, perchè devi tenere conto che sei alle prese con i microcontroller da poco e anzi hai fatto tantissimo.

Come puoi risolvere: (leggilo dopo una tisana rilassante)  :D
1) Compra una arduino mega che ha più memoria ram e più flash. (svantaggio costi, e risolvi fin tanto che non esaurisci pure la memoria della mega)

2) Una soluzione da tentare è quella di creare le istanze della sdfat in una funzione, così quando termina la funzione le istanze vengono distrutte e la memoria occupata torna disponibile. (difficile da implementare, in alcuni casi impossibile, dipende dal contesto). Metti quanto più codice dentro le funzioni e dichiara le variabili locali, se una funzione deve conservare il valore di una variabile puoi dichiararla "static", ma non farne abuso perchè queste restano in memoria, come le variabili globali, cioè sempre.
Usa PROGMEM per mettere in flashrom le stringhe che devi inviare al display, purtroppo se le cose sono per come le ricordo avrai qualche problemino con LCD e PROGMEM di cui non ricordo bene, mi pare un problema di tipi.

Quote
scrivo di straforo perché se durante le feste la mia dolce metà mi becca ancora con l'arduino mi sgrida smiley-razz

Nuovo spot "Fai l'amore con controller" ]:D

Ciao.

Buone feste a tutti.
AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

leo72

Il problema di PROGMEM è che questo accetta solo i tipi classici del C, quindi non String ma char*.
Per il resto quando devi trattare 70/80 stringhe diventa INDISPENSABILE usare PROGMEM  :smiley-sweat:

DanielaES

#25
Dec 08, 2011, 07:34 pm Last Edit: Dec 08, 2011, 09:55 pm by DanielaES Reason: 1
Al solito faccio risposte velocissime mentre aspetto la pizza...
Se davvero fosse un problema di ram, non posso aggiungere della ram esterna?
Avevo visto, ma non ricordo più dove, dei moduli da 32k che potevano essere aggiunti.
Non ci si può mettere lo sketch ovviamente, ma le variabili si.
Non ricordo nemmeno il prezzo, ma lo ipotizzo minore dell'arduino mega :)

Non è quella che avevo visto, perché non sono riuscita a ritrovarla...
ma il playground ha questo link:
http://www.arduino.cc/playground/Main/SpiRAM


edit: sto messa male mi sa...
AVR Memory Usage
----------------
Device: Unknown

Program:   22556 bytes
(.text + .data + .bootloader)

Data:       1766 bytes
(.data + .bss + .noinit)

leo72

1) No. Non puoi estendere la RAM interna con moduli esterni perché il 328 non è stato progettato per supportare questa funzionalità.
2) Sì, stai messa male. Considera che in quello spazio che ti resta libero ci deve entrare anche l'heap e lo stack.

Hai 2 strade:
1) ti studi come usare PROGMEM per accedere alle stringhe dei messaggi da visualizzare sull'LCD in Flash
2) ti compri l'Atrduino Mega2560, che ha molta più memoria Flash e Ram.

superlol

#27
Dec 08, 2011, 10:32 pm Last Edit: Dec 08, 2011, 10:40 pm by superlol Reason: 1

Non può essere un bug di Arduino. Il seguente codice riproduce ciò che vuoi fare tu:

Code: [Select]
unsigned long contatore;

void setup() {
   delay(2000);
   Serial.begin(19200);
   contatore=millis()+5000;
}

void loop() {
   if (millis()>contatore) {
       contatore=millis()+5000;
       Serial.println("Ciao");
   } else {
       Serial.println("Oh...");
   }
   delay(1000);
}

E funziona perfettamente. Quindi è qualcos'altro nel tuo programma, qualcosa che magari hai tralasciato di esaminare.

credo che invece il problema sia Serial.println() in quanto finchè non trasmette blocca il codice ma tu hai messo un delay(1000) che probabilmente ha risolto il problema.

potrebbe essere?

edit:
pardon ho letto dopo tutta la continuazione sulla ram  XD
Il nuovo forum italiano sull'elettronica: http://www.electroit.tk/ <--- Nuovamente online!

leo72

Il delay(1000) ce l'ha anche nel suo codice ma non risolve nulla.

DanielaES


Hai 2 strade:
1) ti studi come usare PROGMEM per accedere alle stringhe dei messaggi da visualizzare sull'LCD in Flash
2) ti compri l'Atrduino Mega2560, che ha molta più memoria Flash e Ram.


PROGMEM non credo sia una soluzione... perché io sarei ancora a metà del mio progetto :\
Manca ancora tutta la parte web server.

Senti la mia opzione, dimmi se è una cazzata.
Ho 2 chip atmega 328p, pensavo di usarne uno farci la versione stand alone, perché mi dispiaceva lasciare l'arduino a vita nella serra.
Posso usare DUE arduini, splittando lo schetch?
Sensori ed lcd da una parte, sd log e ethernet dall'altra?

Cacchiarola, prendere un 2560 e lasciarlo li nella sera mi spiace un po', in pratica non userei la maggior parte dei pin :\

Go Up