Loop nel Loop

Ma c'è forse una legge di murphy per cui, più si va avanti con il progetto più iniziano a dare problemi anche le cose semplici? :slight_smile:
La frustrazione qua incombe...

Ho il void loop che mostra i dati dei sensori e fa il logging.
Se il loop principale è a 2 secondi, vorrei che il logging fosse ogni 30secondi.

Ho scritto una robina semplicissima ed innocente con un if(now.unixtime() >= ecc e va tutto in palla.
Prima di stare ad ammorbarvi con pagine di codice, mi dite semplicemente come fareste voi?
La cosa più semplice in assoluto :slight_smile:

Poi se volete farvi del male le pagine di codice ve le posto pure :
Help.

Il modo più semplice per creare un loop è while(1){ tuo codice } oppure for( ; ; ){ non so se questo va in C }
poi per uscire dal ciclo infinito poni una variabile che quando assume un dato valore trmite un if ti fa fare un salto alla posizione del programma che vuoi te :slight_smile:

unsigned long contatore;

void setup() {
  ...
  contatore=millis()+30000; //30000 ms -> 30 s
}

void loop() {
  ....
  if (millis()>contatore) { //sono passati 30 s
    contatore=millis()+30000;
    fai_quel_che_devi_fare;
  }
}

Inizializzi una variabile unsigned long. Nel setup, cioè nel primo avvio gli dai il valore di millis+30000, ossia metti un "fermo" temporale a 30s.
Nel loop, in fondo, controlli se millis è maggiore di contatore: se sì, vuol dire che sono passati i tuoi 30 s. Quindi reimposti il fermo temporale e poi esegui il codice che devi eseguire.

Leo, dammi una martellata in testa, ti prego :slight_smile:
Il codice che avevo scritto io era simile al tuo (usavo unixtime al posto dei mills)... tuttavia grazie a te adesso ho scoperto che cose crea il problema.
Non ho la più pallida idea del perché però, tu lo sai?

Con questo codice, funziona tutto.

 if (millis()>contatore) { //sono passati 55 s
    contatore=millis()+55000;
    Serial.println ("Dati Loggati.");

    //DataLogging
    myFile = SD.open(filename, 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(frq); // light
    myFile.print(", ");
    if (A3 == HIGH) { //status pin A3 - SSR
      myFile.println("1");
    }
    else {
      myFile.println("0");

    }
    myFile.close();
  }

Però, se a seguire aggiungo queste due righe, che volevo mettere solo per debug e sapere che il ciclo if era stato eseguito... tutto si pianta!. Schermo vuoto, seriale bloccata al debug della sd nel setup.

 else {
    Serial.println ( "File non loggati" );
  }

Erano SOLO queste due righe che mi hanno bloccato tutto per ore! Perché??

ratto93:
Il modo più semplice per creare un loop è while(1){ tuo codice } oppure for( ; ; ){ non so se questo va in C }
poi per uscire dal ciclo infinito poni una variabile che quando assume un dato valore trmite un if ti fa fare un salto alla posizione del programma che vuoi te :slight_smile:

@ratto93
Questo é un stile di programazione brutto. Sia while (1) che for ( ; ; ) funzionano come cicli infiniti. Ma come delay() bloccano il codice. A quel punto é meglio usare delay();

@Daniela
Non credo che now.unixtime() esiste su Arduino. La funzione corrispondente é millis()
PS: non credo che Leo picchia delle ragazze.

Ciao Uwe

@Daniela:
non so da cosa possa dipendere. Non avendo pubblicato il tuo codice interamente, non so dirti se c'era qualcos'altro a bloccare i cicli.

@Uwe:
now.unixtime appartiene a questa libreria e restituisce l'orario in formato timestamp unix-like

leo72:
@Uwe:
now.unixtime appartiene a questa libreria e restituisce l'orario in formato timestamp unix-like

Se non ho capito male, per quella libreria serve un RTC DS1307 nel sitema. Ma Daniela ce l'ha?
Ciao Uwe

Dovrebbe avercelo perché nell'altro thread, quello dove parlava dei problemi nello scrivere su una SD, diceva appunto che voleva fare un logging dei dati con ora/data di rilevazione.

in quello hai ragione, ma non dice ancora niente su quale modello di RTC.

Mi erano capitati dei problemi con un RTC perché lo bombardavo di richieste. A ogni main loop controllavo se l'ora era maggiore di un tot, e tutto andava in malora.

Per avere sempre il tempo ma non chiederlo compulsivamente all'RTC chiedevo a quest'ultimo l'ora, per un secondo nel loop principale la facevo aumentare usando millis() e dopo questo tempo tornavo a sincare l'ora con l'RTC per non perdere definizione.

Anch'io suggerivo sul thread relativo alla swRTC di sincronizzarsi con un RTC ogni tot e poi tenere il tempo sul micro con un contatore agganciato a millis. Anche secondo me bombardare di richieste l'RTC non è salutare.

Eccomi qua :slight_smile:
Si ho un RTC DS1307, Lib adafruit.
Probabilmente sono un po' confusiva quando cerco aiuto, quindi provo a fare chiarezza.

Il codice di leo if (millis()>contatore)... funziona.
Il mio codice if (now.unixtime()>contatore)... funziona. // questo mi fa pensare che non sia un problema di RTC

Se aggiungo un else a seguire del if.
Il codice di leo smette di funzionare e l'arduino si blocca.
Il mio codice smette di funzionare e l'arduino si blocca.

L'else incriminato è:

else {
    Serial.print("Log non aggiornato");
  }

Due banalissime righe che, se sono presenti, bloccano tutto il codice. Se vengono tolte, tutto funziona alla perfezione, sia con mills che unixtime.
Per bloccare intendo: l'arduino sembra incastrato in un loop infinito nel setup dove inizializza, con apparente successo ("done"), l'SD card.
Ho scoperto questa cosa perché il mio codice unixtime lo scrivevo sempre con l'else (per il debug) mentre quello di leo la prima volta l'ho messo dentro senza else.

Ora, se volete posso pure postarvi tutto il codice, ma sono 400righe, non credo abbiate voglia di leggerlo :
In più la compilazione avviene senza problemi, quindi senza arduino e sensori c'è poco da vedere.
Tuttavia se siete masochisti come me... ben venga :smiley: datemi il permesso e ve lo posto.

Inizio veramente a pensare che sia un bug, oggi mi è successo in un altro ciclo if... stesso blocco dell'arduino in loop nel setup. Ho tolto due righe di Serial.print e tutto funziona che è una meraviglia.

Per una ossessiva come me sarebbe bellissimo capire perché ... ma forse devo solo abituarmi che certe risposte non le avrò mai :stuck_out_tongue:

A me basterebbe vedere la routine che contiene quel blocco di codice if-then-else. Potresti mettere quella?

leo72:
A me basterebbe vedere la routine che contiene quel blocco di codice if-then-else. Potresti mettere quella?

Per te questo ed altro :slight_smile:

void loop () {
...
...

Serial.println (contatore);
  if (millis()>contatore) { //sono passati 55 s
    contatore=millis()+55000;
    Serial.println ("Dati Loggati.");

    //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(frq); // light
    myFile.print(", ");
    if (A3 == HIGH) { //status pin A3 - SSR
      myFile.println("1");
    }
    else {
      myFile.println("0");

    }
    myFile.close();
  }

 else {                     
    Serial.println("Log non aggiornato");  //con else tutto si blocca, senza tutto funziona
  }

  delay(1000); // Attendo 1 secondi per ricominciare

}

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

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.

Ma infatti non metto in dubbio il tuo codice :slight_smile:
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 :slight_smile:

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 :slight_smile:

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.

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

Con questo codice, funziona. Il ciclo stampa a seriale "Non Loggato".
LCD mostra i sensori e via dicendo.

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 è:

Initializing SD card...initialization done.

e poi basta, lcd vuoto ecc.

Bello eh? ammettilo che sei perplesso :stuck_out_tongue:

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 :slight_smile:

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? :slight_smile:

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.

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 :sweat_smile: