Problema con funzione Millis - [RISOLTO]

Buonasera a tutti,
sono Luca e sono nuovo del Forum, lo so che della funzione Millis si è parlato e riparlato, ho letto molti articoli e seguito tutti i suggerimenti che ho trovato qui sul Forum, ma purtroppo non riesco ad uscirne fuori, sto realizzando un igrometro, funziona tutto ma non riesco a settare bene la temporizzazione, chiedo cortesemente una mano per risolvere questo problema:

Hardware:
Arduino Uno;
SHT21;
Display OLED 128x64;
Pulsanti di aumento e decremento del settaggio di intervento del deumidificatore;

vorrei che una volta raggiunto il valore di umidità impostato, ci fosse una pausa di 15 secondi prima di dare il consenso di accensione, la pausa deve avvenire anche quando il valore torna sotto quello impostato,
lo faccio per evitare continue accensioni e spegnimenti dovuti a variazioni di pochi secondi del valore rilevato, se non erro si chiama "differenziale", ma non ne sono sicuro.

il codice è questo:

void loop () {

  pul_p = digitalRead (PULSANTEP);
  pul_m = digitalRead (PULSANTEM);

  diminuisci();
  aumenta();
  salva();

  t = SHT2x.GetTemperature();
  h = SHT2x.GetHumidity();

  if (valore <= h) {
    if (millis() - tempo_1 > (pausa_1)) {
      digitalWrite (LED, HIGH);
    }
  }

  if (valore > h) {
    if (millis() - tempo_2 > (pausa_1)) {
      digitalWrite (LED, LOW);
    }
  }
}

Ovviamente le variabili globali tempo_1 , tempo_2 e pausa_1 le ho dichiarate come unisigned long
la temporizzazione funziona in accensione solo la prima volta (neanche precisa a dire il vero) e quando il valore torna sotto la soglia impostata si spegne subito senza temporizzare, dopo non funziona più neanche in accensione.
Dove sbaglio?

Mi auguro di aver scritto bene il post rispettando tutte le regole, non vorrei suscitare le ire del moderatore Guglielmo che ho imparato a conoscere in questi giorni leggendo tanti post e che ormai temo come "l'uomo nero" quando avevo 3 anni :slight_smile:

Dimenticavo, ho provato anche ad inserire questo codice:

 if (valore <= h) {
    if (millis() - tempo_1 > (pausa_1)) {
        tempo_1 = millis();
        digitalWrite (LED, HIGH);
    }
  }

  if (valore > h) {
    if (millis() - tempo_2 > (pausa_1)) {
        tempo_2 = millis();
      digitalWrite (LED, LOW);
    }
  }
}

ma funziona comunque male, i tempi sono sempre sballati.

Grazie ancora.

Un timer si compone di più parti:
I un pezzo di codice carichi la vatiabile assegnandoli millis() e ti segni che il timer "vale"
In un pezzo di codice controlli che il timer sia passato e che valga. Se entrambe allora fai determinate cose (lo scopo del timer) e togli il segno.
Come farr questo? Aggiungendo l'uso di una variabile "vale" da verificare.
Capito?

Secondo me devi scambiare tra di loro i tempi
L'intervento a scendere setta il tempo a salire e viceversa

Ciao, io userei una variabile flag che assume i valori 0 e 1, e un timer con millis() che riporta la variabile flag allo stato iniziale.

Faccio un piccolo esempio :

byte flag=1; //Variabile globale

unsigned long tempo;


 
void loop(){

    if(flag){ // Eseguo o non eseguo a seconda del valore di flag 1 eseguo, 0 non eseguo

         

   }// End if
   
    if(condizione di pausa){

                  flag=0; // Interrompe l'esecuzione del codice dall if(flag)
                  tempo=millis();
    }

   /***********************************/
   
   if(flag==0){// Esegue solo se è in pausa

           if(millis()-tempo>=Pausa){ // Se la pausa è trascorsa
          
                flag=1; // La pausa è finita il programma ripete
                           // e questo pezzo di codice non viene eseguito fino alla prossima pausa
          }

   }// End if
}

Se hai bisogno di due pause distinte, ti creerai due variabili flag, esempio flag1 e flag2, e due tempo1 tempo2, con due codici coem esempio postato.

Se ti è stato di aiuto metti per favore un punto di carma :slight_smile:

Silente:
Un timer si compone di più parti:
I un pezzo di codice carichi la vatiabile assegnandoli millis() e ti segni che il timer "vale"
In un pezzo di codice controlli che il timer sia passato e che valga. Se entrambe allora fai determinate cose (lo scopo del timer) e togli il segno.
Come farr questo? Aggiungendo l'uso di una variabile "vale" da verificare.
Capito?

no :-(, perdonatemi, ma continua a sfuggirmi,

tu mi stai dicendo che nel setup devo mettere una variabile es. "vale" e fargli leggere l'altra variabile millis che sta nel loop?

e comunque grazie a tutti per le risposte.

torn24:
Ciao, io userei una variabile flag che assume i valori 0 e 1, e un timer con millis() che riporta la variabile flag allo stato iniziale.

Faccio un piccolo esempio :

byte flag=1; //Variabile globale

unsigned long tempo;

void loop(){

if(flag){ // Eseguo o non eseguo a seconda del valore di flag 1 eseguo, 0 non eseguo

}// End if
 
    if(condizione di pausa){

flag=0; // Interrompe l'esecuzione del codice dall if(flag)
                  tempo=millis();
    }

/***********************************/
 
  if(flag==0){// Esegue solo se è in pausa

if(millis()-tempo>=Pausa){ // Se la pausa è trascorsa
         
                flag=1; // La pausa è finita il programma ripete
                          // e questo pezzo di codice non viene eseguito fino alla prossima pausa
          }

}// End if
}



Se hai bisogno di due pause distinte, ti creerai due variabili flag, esempio flag1 e flag2, e due tempo1 tempo2, con due codici coem esempio postato.

Se ti è stato di aiuto metti per favore un punto di carma :)

Grazie della risposta, ma non riesco a capire i passaggi:

if(flag){                                 //devo inserire questo?
    if (valore <= h) { 
      digitalWrite (LED, HIGH);
    }. 

   }// End if
   
    if(condizione di pausa){ // devo anche dichiarare questa variabile?

                  flag=0; // Interrompe l'esecuzione del codice dall if(flag)
                  tempo=millis();
    }

l'unico messaggio che non hai quotato è lungo 2 righe e ti dice esattamente cosa fare.
presbiopia?

Riflettendo sul tuo codice iniziale, mi sembra che il problema che non lo fa funzionare correttamente sia la mancata aggiornamento della variabile tempo con la funzione millis()

Non so se è corretto prova a vedere, potrebbero esserci degli errori.

byte flag1=1,flag2=1;

void loop () {

  pul_p = digitalRead (PULSANTEP);
  pul_m = digitalRead (PULSANTEM);

  diminuisci();
  aumenta();
  salva();

  t = SHT2x.GetTemperature();
  h = SHT2x.GetHumidity();

  if (valore <= h) {
    if(flag1){// Eseguo una sola volta
       
        tempo_1=millis(); 
        flag1=0; //evita che venga ripetuto questo codice

    }
    if (millis() - tempo_1 > (pausa_1)) {
      digitalWrite (LED, HIGH);
      flag2=1; // Predispone la pausa a umidità maggiore
    }
  }

  if (valore > h) {
    if(flag2){// Eseguo una sola volta
         tempo_2=millis();
         flag2=0;

   }
    if (millis() - tempo_2 > (pausa_1)) {
      digitalWrite (LED, LOW);
      flag1=1; // predispone la pausa a umidità minore
    }
  }
}

torn24:
Riflettendo sul tuo codice iniziale, mi sembra che il problema che non lo fa funzionare correttamente sia la mancata aggiornamento della variabile tempo con la funzione millis()

Non so se è corretto prova a vedere, potrebbero esserci degli errori.

byte flag1=1,flag2=1;

void loop () {

pul_p = digitalRead (PULSANTEP);
  pul_m = digitalRead (PULSANTEM);

diminuisci();
  aumenta();
  salva();

t = SHT2x.GetTemperature();
  h = SHT2x.GetHumidity();

if (valore <= h) {
    if(flag1){// Eseguo una sola volta
     
        tempo_1=millis();
        flag1=0; //evita che venga ripetuto questo codice

}
    if (millis() - tempo_1 > (pausa_1)) {
      digitalWrite (LED, HIGH);
      flag2=1; // Predispone la pausa a umidità maggiore
    }
  }

if (valore > h) {
    if(flag2){// Eseguo una sola volta
        tempo_2=millis();
        flag2=0;

}
    if (millis() - tempo_2 > (pausa_1)) {
      digitalWrite (LED, LOW);
      flag1=1; // predispone la pausa a umidità minore
    }
  }
}




Perfetto, funziona, con le variabili flag il problema si risolve, ho capito dove stava il problema ed ho imparato una nuova cosa. 

torn24, grazie ancora per avermi aiutato in maniera chiara, la capacità di saper dare nozioni in modo funzionale all'apprendimento non è da tutti.

Grazie, ho imparato qualcosa anch'io

Mi sembra un po' complesso, due variabili tempo e due flag. In fondo la richiesta iniziale è un debounce di 15 secondi sia in attacco che in rilascio: «una pausa di 15 secondi prima di dare il consenso di accensione, la pausa deve avvenire anche quando il valore torna sotto quello impostato»

Un timer per debounce si fa con una riga ('tout' segue 'tin' con un ritardo di 'pausa' millisecondi solo se la variazione di 'tin' dura almeno 'pausa'):

if(tin == tout) tempo = millis(); else if(millis() - tempo >= pausa) tout = tin;

Quindi basta dare il giusto valore all'ingresso del timer per ottenere il giusto valore ritardato all'uscita:

byte tin = (valore <= h);
if(tin == tout) tempo = millis(); else if(millis() - tempo >= pausa) tout = tin;
digitalWrite(LED, tout);

é geniale, complimenti

Claudio_FF gli hobbisti della programmazione si inventano una soluzione usando le loro conoscenze limitate "e il mondo arduino è fatto per la maggir parte da non addetti ai lavori" :slight_smile: , non trovo una tua presentazione ma sono quasi convinto che hai a che fare con l'informatica a livello professionale :slight_smile:

Concludo, e non mi riferisco a te ma in generale, vedo che professionisti che poi si affacciano al mondo ardunio non comprendono appieno la filosofia di arduino e della sua comunità, il forum arduino non è un normale forum di informatica dove si parla di programmazione, c'è "cera" uno spirito di tolleranza, educazione e rispetto verso gli utenti meno esperti. Sottolineo il forum arduino non è un normale forum di informatica, bisogna essere più tolleranti e "gentili" :slight_smile:

per come la vedo io, qui no è questione di conoscenze
la soluzione proposta da me, e bellamente ignorata, richiedeva solo di scambiare tra di loro due variabili, non era richiesta alcuna conoscenze aggiuntiva in questo, anzi, si limitava a "correggere" bonariamente il rpogramma postato, che per quanto "mal concepito" si poteva ancora raddrizzare
la soluzione proposta da Claudio_FF è geniale, è più emplice addirittura del propgramma originale e richiede ancora meno conoscenza, sono due if e una else, nulla di trascendente e che lo OP conosceva certamente
la ragione per la quale un "differente programma" puo' essere comntemporanemante piu' semplice e meglio funzionante di un'altro sta non nella conoscenza del linguaggio, e nemmeno in quella del problema
sta nel diverso modo di cercare la soluzione, io lo chiamo "pensiero laterale"
si possono trarre varie conclusioni da questo, anche considerando chi ha espresso critiche e chi no

Standardoil evidentemente non ha capito la soluzione dalle tue parole, a volte a noi sembra molto chiaro una cosa ma gli altri non capiscono, se avesse compreso lo avrebbe applicato perché era la cosa più rapida :slight_smile:

No!
Le cose che non ha capito le ha nuovamente chieste
ha quotato con la carriola, SALVO la soluzione
certe cose non sono una coincidenza

>Standardoil: Ripeto che sono abbastanza stanco di sentire commenti negativi sugli utenti da parte tua e non vorrei dover (di nuovo) prendere provvedimenti ...

Ti rammento il punto 16.2 e 16.4 del REGOLAMENTO, per cui ... un utente non segue i tuoi consigli e non risponde a tono? Smetti di aiutarlo, vai su un altro thread ed astieniti da commenti, giudizi sullo stesso e quant'altro.

Grazie,

Guglielmo

Prima che degeneri in un flame :slight_smile:

Sono consapevole che i vari codici e spiegazioni vanno "tarati" in base alla richiesta/richiedente. Non vorrei che un'esposizione troppo "sbrigativa" sia sembrata una critica o un pontificare su come le cose devono essere fatte, in tal caso faccio ammenda :stuck_out_tongue:

Dopo una soluzione trovata tra le tante possibili, basata sul codice originale, ho proposto con finalità didattica un'alternativa molto diversa (perché secondo me più semplice), che l'op o chiunque altro, se vuole, può studiare (forse la cosa più complessa da comprendere inizialmente è l'assegnamento di quell'espressione booleana).


La presentazione ohibò, probabilmente non l'ho (ri)fatta quando l'accesso con il vecchio user si è bloccato per problemi al forum (comunque era questa).

di nuovo?

Claudio_FF:
Prima che degeneri in un flame :slight_smile:

Sono consapevole che i vari codici e spiegazioni vanno "tarati" in base alla richiesta/richiedente. Non vorrei che un'esposizione troppo "sbrigativa" sia sembrata una critica o un pontificare su come le cose devono essere fatte, in tal caso faccio ammenda :stuck_out_tongue:

Dopo una soluzione trovata tra le tante possibili, basata sul codice originale, ho proposto con finalità didattica un'alternativa molto diversa (perché secondo me più semplice), che l'op o chiunque altro, se vuole, può studiare (forse la cosa più complessa da comprendere inizialmente è l'assegnamento di quell'espressione booleana).

Leggo ora, anche questa soluzione è perfetta e l'esposizione non è stata assolutamente "sbrigativa",anzi tutt'altro.
Ben vengano le esortazioni a trovare soluzioni alternative, l'importante è che vengano fatte nei modi giusti ed argomentando in maniera funzionale, d'altronde le "conoscenze" possiamo accumularle più o meno tutti, saperle "trasmettere" invece è roba per pochi... Grazie ancora a tutti, specialmente a Claudio_ff e torn24.