Aiuto per funzione di auto reset

Buongiorno a tutti,
sono alle prese con alcuni Arduino MKR1010 WIFI che dovranno permettermi di controllare tramite Blynk alcune periferiche a 3km da casa. Purtroppo spesso si verificano disconnessioni che, nella maggior parte dei casi si risolvono da sole nel giro di pochissimi secondi, ma posso anche diventare definitive senza che ne capisca il motivo.
Per questo motivo ho aggiunto una funzione di auto reset nello sketch in modo da eliminare il problema (ho già previsto un arduino a parte che gestisca, tramite serie di relè, l'alimentazione delle varie schede per un ulteriore livello di controllo).
Qui la parte interessata dello sketch (vi risparmio le parti non attinenti)

void setup() {
  pinMode(14, OUTPUT);       //il pin 14 è collegato al pin RESET che riavvia arduino quando non viene
  digitalWrite(14, HIGH);    //fornita corrente. fornirgli corrente è la prima operazione da fare
}

void autoReset() {
if (millis() >= 44000000) {
    digitalWrite(14, LOW);   //riavvio in qualsiasi caso ogni circa 12h
  }
  if (WiFi.status() != WL_CONNECTED) {           //se Blynk rileva disconnessione
    unsigned long disconnectedTimer = millis();  //parte un timer
    if (millis() - disconnectedTimer >= 60000) { //e se supera 60 secondi
      digitalWrite(14, LOW);                     //reset
    }
  }
}

void loop() {
autoReset();
}

la parte del riavvio ogni 12h funziona bene e spesso risolve problemi di pregresse "disconnessioni definitive", non funziona la parte del "se disconnesso per più di 60 secondi" anche se a me sembra corretta a livello di codice.
C'è qualcuno che possa aiutarmi a capire il perché?
Grazie

ciao

è sbagliato come assegni il millis nell'if del "se non connesso"...prova a ragionarci

Se fai il reset collegando l'I/O 14 al reset, devi almeno aggiungere un condensatore e una resistenza per prolungare l'impulso, perché già se ne è parlato e si è detto che è concettualmente sbagliato, in quanto il reset termina l'impulso in uscita prima che abbia resettato completamente il microcontrollore. In realtà anche l'RC non è una buona soluzione, perché il microcontrollore si resetta appena la tensione sul condensatore va al di sotto del valore necessario e ci mette un istante, poi, a tornare su! Dovresti usare un trigger di Schmitt, come il CD40106...

Non puoi fare il reset solo tramite software?

ORSO2001:
ciao

è sbagliato come assegni il millis nell'if del "se non connesso"...prova a ragionarci

sinceramente ci ho ragionato proprio poco. ho trovato tra gli esempi della libreria "HandleDisconnect" che contiene questo codice

void loop()
{
  // check WiFi connection:
  if (WiFi.status() != WL_CONNECTED)
  {
    // (optional) "offline" part of code

    // check delay:
    if (millis() - lastConnectionAttempt >= connectionDelay)
    {
      lastConnectionAttempt = millis();

      // attempt to connect to Wifi network:
      if (pass && strlen(pass))
      {
        WiFi.begin((char*)ssid, (char*)pass);
      }
      else
      {
        WiFi.begin((char*)ssid);
      }
    }
  }
  else
  {
    Blynk.run();
  }
}

e l'ho modificato un pochino per fare quello che mi interessava. sinceramente non saprei proprio dove potrebbe essere il problema... forse disconnectedTimer dovrebbe essere una variabile globale?

Datman:
Se fai il reset collegando l'I/O 14 al reset, devi almeno aggiungere un condensatore e una resistenza per prolungare l'impulso, perché già se ne è parlato e si è detto che è concettualmente sbagliato, in quanto il reset termina l'impulso in uscita prima che abbia resettato completamente il microcontrollore. In realtà anche l'RC non è una buona soluzione, perché il microcontrollore si resetta appena la tensione sul condensatore va al di sotto del valore necessario e ci mette un istante, poi, a tornare su! Dovresti usare un trigger di Schmitt, come il CD40106...

Non puoi fare il reset solo tramite software?

interessante... si può fare solo tramite software?? se c'è una funzione che permette di farlo, mi basta cambiarlo nello sketch e dovrei risolvere

koten90:
interessante... si può fare solo tramite software?? se c'è una funzione che permette di farlo, mi basta cambiarlo nello sketch e dovrei risolvere

NO, non si può fare ed è concettualmente e praticamente sbagliato farlo.

Hai provato a vedere se invece le schede MKR prevedono una gestione del watchdog ?

Guglielmo

... ecco, QUI c'è una libreria per implementare il Watchdog ... c'è scritto per Arduino Zero e MKR1000, ma essendo la MCU del MKR1010 la stessa (ATSAMD21) dovrebbe funzionare anche sul MKR1010.

Guglielmo

ciao,

per quanto riguarda la parte del "se non connesso"...ragiona sulla visibilità (scope) delle variabili e quando assegni alla variabile il valore millis()...ti do due suggerimenti...uno si chiama "static" ed il secondo "else".

gpb01:
... ecco, QUI c'è una libreria per implementare il Watchdog ... c'è scritto per Arduino Zero e MKR1000, ma essendo la MCU del MKR1010 la stessa (ATSAMD21) dovrebbe funzionare anche sul MKR1010.

Guglielmo

Grazie Guglielmo, l'ho vista e mi stavo documentando su cosa fosse questo Watchdog... ancora non ho capito per bene come funziona, ma insisterò.

ORSO2001:
ciao,

per quanto riguarda la parte del "se non connesso"...ragiona sulla visibilità (scope) delle variabili e quando assegni alla variabile il valore millis()...ti do due suggerimenti...uno si chiama "static" ed il secondo "else".

static serve per memorizzare un valore che non è variabile, ma nel mio caso non è l'approccio corretto (credo) perché il più delle volte la disconnessione si risolve da sola con la funzione HandleDisconnect (che ho nello sketch pari pari).
else crea un'alternativa all'if, ma se non esplicitata significa banalmente "vai avanti con il loop".
Non riesco a capire cosa dovrei modificare secondo te.... non voglio la pappa pronta, ci mancherebbe, ma così non ci arrivo proprio. O sto dando io qualcosa per scontato, o stai presumendo che io sia più bravo di quanto sono in realtà :frowning:

Nel frattempo ho modificato la variabile disconnectedTimer da locale a globale, che era la cosa che mi pareva fuori posto rispetto al solito.

ciao,

la tua funzione dovrebbe essere una cosa tipo (pseudo codice):

 void miaFunziona(){
    static tempoPassato=millis();
    se disconnesso{
        se passato tempo{
            resetto
        }
    }
    diversamente{
        tempoPassato=millis();
    }   
}

in questo modo la variabile "tempoPassato" rimane con visibilità locale e non accessibile in tutto il programma...ma la inizializzi una vilta sola e non viene distrutta ad ogni giro loop...per cocludere il suo valore (tempo) lo aggiorni solo se la connessione c'è...se non c'è connessione verifichi per quanto tempo non è connesso.

ORSO2001:
in questo modo la variabile "tempoPassato" rimane con visibilità locale e non accessibile in tutto il programma...ma la inizializzi una vilta sola e non viene distrutta ad ogni giro loop...

ok, quindi posso usare anche un variabile locale. interessante la funzione di static che inizializza una volta sola, credo che il vantaggio sia far risparmiare tempo nel loop, giusto?

ORSO2001:
per cocludere il suo valore (tempo) lo aggiorni solo se la connessione c'è...se non c'è connessione verifichi per quanto tempo non è connesso.

se la connessione c'è non mi interessa aggiornare la variabile: è inutile. quando avviene la disconnessione assegno il tempo millis() e da lì faccio il calcolo. è un'operazione in meno da fare nel loop se non ci sono problemi e in caso di disconnessione l'effetto è identico, no?

koten90:
... credo che il vantaggio sia far risparmiare tempo nel loop, giusto?

NO, il suo scopo è mantenere tra una chiamata e la successiva il valore memorizzato in essa.

Una variabile locale esiste SOLO quando viene chiamata la funzione, una variabile statica invece esiste sempre ... il comportamento è quello di una globale, ma rimane visibile SOLO all'interno della funzione in cui è dichiarata e NON al di fuori.

Guglielmo

Ho trovato una spiegazione al problema: il comando

if (WiFi.status() != WL_CONNECTED)

controlla solo che Arduino sia connesso al WiFi, ma la maggior parte delle disconnessioni sono causate da una disconnessione dal server di Blynk, quindi ho implementato un ulteriore comando

if (!Blynk.connected) {
  Blynk.connect();
}

Ho anche aggiunto un timer non bloccante per evitare il controllo in continuo (ho letto che può essere problematico perché l’operazione richiede diversi secondi).
A quanto pare, sono già 4h che il codice gira senza disconnessioni definitive. Vi tengo aggiornati

gpb01:
... ecco, QUI c'è una libreria per implementare il Watchdog ... c'è scritto per Arduino Zero e MKR1000, ma essendo la MCU del MKR1010 la stessa (ATSAMD21) dovrebbe funzionare anche sul MKR1010.

Guglielmo

l'idea non è male.
Il watchdog (letteralmente cane-da-guardia) controlla che il programma "giri" regolarmente e se il ciclo supera X secondi resetta autonomamente il processore. Questo lo può fare perchè è una parte "indipendente" della MCU e non dovrebbe venire interessata da malfunzionamenti o disturbi elettromagnetici.

Il modo più "basico" per farlo intervenire è.... mettere un delay :slight_smile:

Si, perché il delay è una istruzione bloccante mentre il watchdog controlla che il programma segua a "circolare"

Quindi se al watchdog diamo un valore di 4 secondi (per esempio) e poi mettiamo all'interno del programma un delay (8000), cioè di 8 secondi, va da sé che il watchdog interviene resettando tutto

Quindi basta "accendere" un delay quando serve resettare...

Molto interessante anche questa soluzione!

potresti chiamare un reset via software utilizzando watchdog e funzione del tipo

void reset() {
 wdt_enable(WDTO_250MS);
 while(1):
}

gpb01:
NO, non si può fare ed è concettualmente e praticamente sbagliato farlo.

Hai provato a vedere se invece le schede MKR prevedono una gestione del watchdog ?

Guglielmo

Ho trovato un suggerimento dal creatore della libreria per la gestione del watchdog su processori SAMD qui Re: WatchDog Timer in MKR1000


"for reset use function

NVIC_SystemReset();

*
*
**Nested Vectored Interrupt Controller is a feature of ARM chips and the function is part of ARM SDK.
you use it, as it is. call NVIC_SystemReset() and the MCU resets*"*

effettivamente funziona ed è solo una riga di codice. una volta chiamata la funzione c'è il riavvio automatico, senza librerie o altro.

Rimane concettualmente SBAGLIATO ... i problemi si risolvono facendo debug, e non, non sapendo da dove arrivano, facendo un reset e lasciando i "buchi" nel programma o nell'harware che si è costruito!

Il watchdog, difatti, ha un compito ben differente ... se, per una cosa NON prevista (es. un forte disturbo elettromagnetico) la MCU sbaglia e il programma impazzisce ... il watchdog ha il compito, SOLO in casi come questo, di fare il reset.

Guglielmo

Assolutamente d'accordo con Guglielmo, prima bisogna, quantomeno, cercare l'errore.
Poi capisco anche che "ci sono cose che voi umani..." e che quindi non si riesce a cavare un ragno dal buco e, per togliersi da questo impasse, si preferisca "andare sul pulito".

Io per esempio spengo sempre il cellulare tutte le notti per poi riaccenderlo la mattina e non ho tutti quei problemi di persone che non lo spengono mai...

Sono d’accordissimo anche io.
Purtroppo non ho modo di capire cosa c’è che non va: l’arduino continua a scollegarsi da Blynk, forse perché sto inviando una quantità di dati troppo elevata, ma anche allungando i tempi di invio non ottengo risultati.
Ho provato a collegare un led per ogni invio dati e tutti blinkano nei tempi previsti anche dopo la disconnessione, quindi il problema è solo il collegamento al wifi/server. Ho rimediato sul collegamento via cavo per l’unico dato veramente critico (chiudi tetto osservatorio in caso di pioggia, pioggia rilevata da stazione meteo e comando dato da un secondo arduino a distanza tollerabile).
Forse dovrei provare a mettere il codice completo sul forum Blynk e vedere se loro trovano il problema.

Sinceramente non ho mai avuto una "completa" stabilitá neppure io con tutti gli esperimenti che ho fatto con Blynk, mi verrebbe da pensare che siano i loro server...?
Ti confermo invece che la parte WiFi non mi ha mai dato problemi, soprattutto con l'ESP32 (con l'8266 c'era un po da litigarci invece...).

Per il reset tramite watchdog sono d'accordo sulla teoria del debug.... ad esempio il mio problema erano le interferenze date da pompe, elettrovalvole e relé che non piacevano proprio a MEGA e ancora meno al display nonostante i vari filtri che avevo messo. La soluzione era fare una scheda a parte collegata al controllore tramite fotoaccoppiatori, separando de-facto l'alimentazione di potenza da quella di controllo ma.... voleva dire smontare il mondo, creare una scheda da zero, rimontare e riprogrammare (cose che sto facendo ora che ho piú tempo). Il watchdog a 4 secondi nonostante tutti i riavvii, mi ha tenuto il kit in funzione per dei mesi piú o meno senza problemi