Problema loop principale ora RTC intermittente

Salve a tutti del forum.
Sono ritornato in cerca del vostro aiuto per un problema alquanto strano e da qui non ne vengo a capo.

Ho creato un piccolo sistema di serra automatizzata e funzionava tutto alla perfezione, poi ho voluto integrare un menu che mi consenta di settare alcuni parametri tra cui ora di accensione, spegnimento e regolaggio data e ora di un RTC Ds1302. Tutto funziona perfettamente. l'unica cosa che non va e che quando il sistema è in funzione nel loop principale l'ora dettata dal DS1302 si vede ad intermittenza, quindi vedo oltre ad altri parametri come temperatura, umidità e temperatura impostata, l'ora es. 16:06 e 00:00 ad intermittenza di mezzo secondo circa. Di conseguenza il relè collegato all'ora impostata si attiva e si disattiva alla stessa frequenza della visualizzazione dell'ora.

Vi invio sketch completo per vedere se qualcuno riesce a capire il problema.

Ps. Sto usando un Arduino Uno con collegato LCD, 4 pulsanti per la navigazione del menu, RTC DS1302, 3 relè per l'attivazione dei vari carichi.

Ringrazio anticipatamente per le risposte.

Serra_Automatizzata.ino (14.9 KB)

Dato una occhiata, difficile da capire cosa fa il programma;

  1. hai dei pin che non sappiamo cosa facciano 13,7,5 e 6
    Tra l'altro ti conviene creare una define per tutti e quattro, con un nome che spiega cosa fanno e lo usi ovunque (sono i tasti dx/sx/su/giu ??)
  2. gli stati sono dei semplici numeri, tu magari sai cosa significano ma noi che dobbiamo leggerlo ?
    Anche per questi crea delle define che diano un pò più di chiarezza es. #define K_STATO_MAIN 0
  3. anche i nomi delle variabili di quel che memorizzi in eeprom, dagli nomi più significativi:
    y = EEPROM.read(2);
    w = EEPROM.read(3);
    Sono ora minimo e massimo luce ?

P.S. inoltre elimina dal codice quelle due righe inutili ed errate come inizializzazione:
int temp = dht.readTemperature();
int h = dht.readHumidity();

Di base, quando gira e non tocchi nulla esegue sempre e solo mainloop(),giusto ??

Allora intanto grazie per la risposta.

I pin 13, 7, 5, 6 sono rispettivamente i tasti sinistra, destra, su e giu.

In poche parole di base, quando gira e non tocco nulla esegue sempre e solo mainloop().

Gli altri stati vengono attivati in primis dal pulsante 7 che mi fa entrare nel "menu" e poi navigo grazie agli altri tasti. Mainmenu1, Mainmenu2, Mainmenu3 ecc... sono le altre voci o pagine del menu e sub1, sub2, sub3 ecc... sono le sottopagine del menu principale....

Comunque io credo che il problema sia da ricercare nel Mainloop, non so perchè ma ho questa impressione.

Può essere il problema il bool FIRST??

Io mi sono confuso e non ci sto capendo più niente...

La variabile FIRST non viene mai "usata" nel codice della mainloop() a meno che non premi tasto pin 7

Prova a mettere in commenti tutto il loop() e fare solo
void loop()
{ mainloop();
}
e vedere se fa ancora difetto (secondo me si);
Non ci sono pause, in base alla velocità delle istruzioni dentro alla mainloop() tu di continuo e moolto velocemente fai lettura rtc, lettura temp/umidità, display su lcd e lettura digitali

P.S. per favore poi segui i miei consigli al mio post #1, tra 30 giorni rileggerai quel codice e non ci capirai nulla, senza nomi chiari alle variabili/costanti

Ho provato a commentare tutto il loop() ed ho messo nel loop() sono Mainloop() e il difetto lo fa ugualmente.... quindi il problema è da ricercare nel mainloop(), giusto?

Dopo seguirò sicuramente il tuo consiglio di mettere le define ma in questo momento penso di no altrimenti mi confonderò molto di più... :slight_smile:

Secondo me il problema è che leggi il rtc di continuo, senza "pause" e forse lui non è in grado di rispondere così velocemente oppure il display lcd non riesce ad essere disegnato così in fretta.

Se puoi collegare usb, prova a buttare su seriale con Serial.println ora del rtc

Ho provato a scrivere nella seriale l'ora ma mi da lo stesso risultato dell'lcd, una serie di 17 (ora) e una serie di 0 con la stessa frequenza dell'aggiornamento dell'lcd. Ho provato pure a mettere un delay alla fine del mainloop ma non faccio altro che ritardare di 500ms la frequenza di aggiornamento...

:o :o :o

EVVAIIIIII.....
Ho trovato il problema!!!

Facendo delle ricerche su google ho trovato una discussione in cui si parlava di mettere in alcuni casi una resistenza da 220ohm tra il pin DAT del DS1302 e il pin di ingresso di arduino.

Ho provato e si è risolto il problema....

Grazie tante per l'aiuto e la disponibilità di nid69ita.

E un grazie al forum di Arduino...

Ma una cosa del genere no? Inutile stampare sempre l'ora se non cambiano almeno i minuti...

...
int t0 = 0;

void mainloop() {

  t = rtc.getTime();
  
  int h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  int te = dht.readTemperature();

  if ( t.hour()*60+t.minute() != t0 ) {
    lcd.setCursor(11, 1);
    if (t.hour < 10)
      lcd.print("0");
    lcd.print(t.hour, DEC);
    lcd.print(":");
    if (t.min < 10)
      lcd.print("0");
    lcd.print(t.min, DEC);
  }
  t0 = t.hour()*60+t.minute();
...

@docdoc lui legge troppo velocemente anche il sensore temperatura dht. Secondo me pure quello dovrebbe leggerlo solo ogni tanto. Magari metterlo dentro a quell'if che hai suggerito tu

Ah ok ottima soluzione, ma tanto per essere curioso, se legge continuamente l'ora o la temperatura o altro, o la legge ogni 250ms cosa cambia a livello di funzionalità?

Che potrebbe succedere?

nid69ita:
@docdoc lui legge troppo velocemente anche il sensore temperatura dht. Secondo me pure quello dovrebbe leggerlo solo ogni tanto.

Si, concordo, tra l'altro che variazioni di temperatura e umidità potrà mai avere anche in un quarto di secondo? Io la leggerei ogni 5-10 secondi, non di meno, e senza usare tutti quei delay() ma con millis().

E tra l'altro, per dirla tutta, un po' tutto il codice si potrebbe/dovrebbe ottimizzare, oltre a cercare di rendere pià leggibile e gestibile il listato togliendo tutte quelle inutili righe vuote, sfilze di if else if, poi dare nomi decenti alle variabili (come y, w e z, i nomi da una lettera li si usa per gli indici...), dare un nome ai codici di stato invece di usare il numero, impostare delle costanti per i pin, eccetera eccetera... :wink:

orzowilde:
Ah ok ottima soluzione, ma tanto per essere curioso, se legge continuamente l'ora o la temperatura o altro, o la legge ogni 250ms cosa cambia a livello di funzionalità?
Che potrebbe succedere?

In generale nulla di particolare (tranne il fare cose inutili o inutilmente più spesso di quanto serva non è mai il massimo, come scrivere sull'lcd una cosa che è già presente), ma dato che usi estensivamente i delay() non hai il controllo del timing delle azioni, mentre usando millis() puoi fare le cose solo quando serve veramente. Questo si fa, insieme a millis(), implementando una macchina a stati finiti che mi sembra tu abbia cercato di implementare.

Ma al di là di tutto, ti consiglio di ottimizzare il codice intanto facendo le cose che ho scritto sopra, come: togli le righe vuote inutili, lasciane solo una tra blocchi in qualche modo da "evidenziare", imposta dei #define per i codici degli stati, imposta delle "const byte" per la configurazione dei pin (entrambi questi blocchi mettili insieme in testa al programma così sono ben visibili e gestibili), poi per codici più lunghi di qualche decina di righe metti la graffa di apertura insieme allo statement (es. non "if (condizione)" e poi a capo la graffa, ma "if (condizione) {"), la gestione dei dati sullo schermo mettila in una funzione "aggiornaLcd()" al limite con un parametro per dire cosa visualizzare, e così via.
Come altre cose "secondarie" ma sempre per migliorare la leggibilità, direi invece di "lcd.print((char)223);" crea una "#define GRADI 223" quindi fai "lcd.write(GRADI);".

Ovviamente sono tutti consigli non "operativi" ma ti assicuro che all'aumentare della complessità del codice, un listato poco leggibile (da te ma anche per noi) genera una difficoltà di debug esponenzialmente maggiore...

Docdoc hai completamente ragione.
Il fatto è che questo progetto è nato molto semplice con la sola accensione e spegnimento di un relè secondo temperatura. Man mano poi ho inserito l'rtc per farlo funzionare ad ora, poi ho voluto inserire il menù e così via. Tutte queste revisioni e modifiche hanno portato alla confusione più totale. :slight_smile: Adesso mi concentrerò a sistemare il più possibile lo sketch per ricaricarlo sul forum così che potrebbe servire anche ad altri...
Comunque ancora grazie per tutto...

orzowilde:
Ah ok ottima soluzione, ma tanto per essere curioso, se legge continuamente l'ora o la temperatura o altro, o la legge ogni 250ms cosa cambia a livello di funzionalità?

Che potrebbe succedere?

Magari il dht no, ma alcuni sensori non "rispondono" in maniera immediata, hanno bisogno di un certo tempo per rispondere a due letture successive.
Anche l'ADC della MCU ha bisogno di tempo (piccolissimo) tra una lettura e l'altra (la lettura analog per intendersi)

orzowilde:
Facendo delle ricerche su google ho trovato una discussione in cui si parlava di mettere in alcuni casi una resistenza da 220ohm tra il pin DAT del DS1302 e il pin di ingresso di arduino.

Ho provato e si è risolto il problema....

Sicuro?
Che cosa dovrebbe fare una resistenza collegata così?
Non è che mi potresti girare il link al sito?
Scusa se mi sono intromesso ma mi sa che mi sono perso qualcosa perchè questa cosa non mi torna molto.

grazie mille
Maurizio

maubarzi:
Sicuro?
Che cosa dovrebbe fare una resistenza collegata così?
Non è che mi potresti girare il link al sito?
Scusa se mi sono intromesso ma mi sa che mi sono perso qualcosa perchè questa cosa non mi torna molto.

grazie mille
Maurizio

Sinceramente non so a cosa serve questa resistenza, ma il fatto è che funziona....

Questo è il link che ho visto

Se capisci qual'è il motivo fammelo sapere, sono curioso...

orzowilde:
Sinceramente non so a cosa serve questa resistenza, ma il fatto è che funziona....

Sono contento che tu abbia risolto, ma anche a me non convince la cosa, ossia:

  1. il problema di quell'articolo non mi pare sia esattamente lo stesso che hai anche tu (a lui dava letture alternate differenti di cui una con orario "09:54", mentre tu lamenti di vedere "00:00" alternato);

  2. in quell'articolo si vede che il modulo RTC ossia la breakout board di quello che ha problemi è differente dall'altro, in quanto si vede che ha 3 resistenze in più (non riesco a leggere i valori e non so come siano connesse), e non le ho mai viste e in quella che ho anche io non ci sono;

  3. una resistenza in serie alla linea dati limita la corrente ed abbassa la tensione, ma non può influire sulla comunicazione dati, a meno che QUELLA board o QUEL chip sia in qualche modo fallato o non adatto o collegato male;

  4. il blink sul display si evita sicuramente evitando di riscrivere l'ora quando ore e minuti non sono cambiati, come ti avevo consigliato di fare;

  5. in quella pagina che hai linkato, il tizio che ha problemi ne ha anche altri perché mostra un valore di secondi irrealistico (ti pare che le ore "19:59:79" o le "09:54:85" siano valori corretti?) quindi mi sa che aveva (anche) ben altri problemi e non mi fiderei.

Per curiosità, metti in allegato una foto nitida della tua board, fronte retro, e di tutti i collegamenti, e vediamo di capire. Ad esempio la board come l'alimenti? A 5 o 3.3V? Io penso che tu l'abbia messa a 5V devi provare a collegare QUELLA board (forse le resistenze indicano proprio che è un tipo diverso..) all'uscita 3.3V di Arduino, senza quella resistenza quindi.

Quoto docdoc.
Poi, se a te ha risolto, meglio, ma secondo me è probabile che sia dovuto più al caso che alla resistenza.
Oppure a effetti indiretti di qualche tipo che però al momento non saprei spiegare.
Nel link non è che dia molte informazioni in merito.
Non è che oltre alla resistenza hai fatto anche qualche altra operazione, che magari spiega meglio il risultato?

Maurizio

Allora, penso di aver risolto l'arcano della resistenza e dell'RTC DS1302 intermittente...

Giorni fa, per comodità e per velocizzare un pò l'andamento del mio progetto avevo preso un caricabatterie del telefonino vecchio e avevo saldato l'uscita 5v del caricabatterie su una piccola piastra millefori e li avevo collegato tutti i carichi a 5volt, quindi positivo e negativo del display LCD, dei relè, del DS1302 e pure l'alimentazione dell'arduino visto che ho fatto entrare l'alimentazione stessa nei pin 5v e GND di Arduino.

Ora ho fatto delle prove, ho tolto la resistenza di 220ohm del pin DAT, e così se collego VCC e GND dell'RTC sulla piastra millefori l'ora mi viene sempre rappresentata ad intermittenza, se invece collego il VCC e GND dell'RTC ai pin 5v e GND direttamente di arduino tutto funziona alla perfezione...

Può essere??