bloccare flusso in attesa del tasto

Salve a tutti, nello sperimentare un termostato per la mia caldaia, mi sono bloccato perchè non riesco a fermare il programma finchè non premo un tasto, mi spiego meglio :

Durante lo svolgimento dello sketch premo un tasto (BUTTONSET) e richiamo una funzione che pulisce lo schermo LCD scrive il titolo e dovrebbe fermarsi finchè non ripremo lo stesso tasto (BUTTONSET).

La funzione viene chiamata e stampa sull'lcd quello che voglio ma non riesco a bloccarlo fino alla nuova pressione dello stesso tasto. Ho provato con IF e While ma non riesco proprio.
Come fare ?
Grazie per l'aiuto

Ciao linomari, e benvenuto sul forum di Arduino.
Se tu avessi letto il regolamento, e magari anche il post che trovi all'inizio di questa sezione dal titolo 'aiutaci ad aiutarti' ti saresti già portato avanti con il lavoro. Parli di sketch, pulsanti, display, funzioni, ma non vediamo ne il codice ne i collegamenti, quindi capisci, così è difficile aiutarti.
Comunque ti posto una funzione di esempio, che puoi eventualmente riadattare per i tuoi scopi:

void set_time(){
    rtc.refresh();
    uint8_t ore = rtc.hour();
    uint8_t minuti = rtc.minute();
    uint8_t secondi = rtc.second();
    uint8_t cur_set = 0;
    int8_t e = 0;
    bool lp = true; 
    LCD_TIMER.stop();
    lcd_clear();
    lcd_print_str(0,"%s", " IMPOSTA ORARIO");
    lcd_print_str(1,"%s"," ORA MIN. SEC.");
    while(lp){
        snprintf(lcd_buf[2],LCD_COLS," %02i   %02i   %02i",ore,minuti,secondi);
        pad_buffer[2];
        upd_rows[2] ++;
        e = check_enc();
        if(enc_btn.check() == ON) cur_set++;
        if(cur_set == 3) lp=false;
        switch(cur_set){
            case 0:  //set hour
                snprintf(lcd_buf[3],LCD_COLS," %c%c",UP_ARW,UP_ARW);
                if(e > 0 && ore < 24) ore++;
                if(e < 0 && ore >= 1) ore--;
                break;
            case 1: //set minute
                snprintf(lcd_buf[3],LCD_COLS,"      %c%c",UP_ARW,UP_ARW);
                if(e > 0 && minuti < 60) minuti++;
                if(e < 0 && minuti >= 1) minuti--;
                break;
            case 2: // set sec    
                snprintf(lcd_buf[3],LCD_COLS,"           %c%c",UP_ARW,UP_ARW);
                if(e > 0 && secondi < 60) secondi++;
                if(e < 0 && secondi >= 1) secondi--;
                break;
        };
        pad_buffer(3);
        upd_rows[3] ++;
        update_lcd();
    }
    rtc.refresh();
    rtc.set(secondi,minuti,ore,0,rtc.day(),rtc.month(),rtc.year());
    LCD_TIMER.start(LCD_TIMER_SET);
}

Purtroppo ho la brutta abitudine di non scrivere commenti nel codice, comunque nel mio caso ogni volta che premo enc_btn incremento una variabile, che poi serve anche ad altre cose. Quando la variabile (cur_set) raggiunge il valore di 3 è ora di uscire, quindi setto lp a false ed esco dal while. A te basta settare a false lp quando premi il tuo bottone.
Si lo so, non sono il massimo della chiarezza, ma e tardi e sono stanco.
Spero ti possa essere d'aiuto, e, cortesemente, leggi le cose che ti ho suggerito all'inizio, così capisci come postare codice, immagini, etc.

Ciao, Ale.

ilguargua:
Se tu avessi letto il regolamento, e magari anche il post che trovi all'inizio di questa sezione dal titolo 'aiutaci ad aiutarti' ti saresti già portato avanti con il lavoro.

Grazie!

Scalda il cuore leggere queste cose

>ilguargua: ... vorrei solo ricordarti quando dice proprio il REGOLAMENTO al punto 16.1 ed al punto 16.13 ... quindi, lodevole il voler aiutare, un po' meno dare la "pappa fatta" ... meglio spiegare come fare e vedere se l'utente ci arriva da solo. Magari tienilo presente per il futuro ... grazie :slight_smile:

Guglielmo

@Guglielmo : Hai ragione, scusa, se leggi altri miei interventi è quello che cerco sempre di fare. Ieri sera ero particolarmente stanco e non ce la facevo a dare spiegazioni dettagliate (allora cosa ca!!o scrivi a fare, dirai tu...), in futuro cercherò di evitare.

Ciao, Ale.

Sera a tutti, non era mia intenzione creare diverbi, effettivamente cercavo solo un consiglio su come fare e non il codice pronto da incollare anche se ringrazio ilguarga per l'aiuto.

Comunque espongo meglio la mia richiesta incollando la parte di codice interessata e descrivendo il problema di nuovo:
appena parte il loop premendo il tasto "BUTTONTIME" richiamo la funzione "setClockdisplay" che pulirà lo schermo LCD, accende la luce, setta il cursore e stampa la scritta.
Ovviamente fin qui funziona tutto.

La mia richiesta di aiuto consiste nel bloccare la funzione, quindi non deve tornare nel "void loop", fin quando ripremerò di nuovo il tasto BUTTONTIME. Spero di essere stato più chiaro:

void setClockdisplay()                     
{ 
 lcd.clear();
 lcd.backlight();
 lcd.setCursor(0,0);
 lcd.print("Set clock");
/* altro
*  codice
*  da inserire
*  dopo
*/

   }
 lcd.clear();
 }

void loop() {

 if (digitalRead(BUTTONTIME)==HIGH) {
 delay(50);                                       
 setClockdisplay();                               
 
 }

>linomari: ti ricordo che in conformità al regolamento, punto 7, devi editare il tuo post qui sopra (quindi NON scrivendo un nuovo post, ma utilizzando il bottone More -> Modify che si trova in basso a destra del tuo post) e racchiudere il codice all'interno dei tag CODE (... sono quelli che in edit inserisce il bottone con icona fatta così: </>, tutto a sinistra).

In pratica, tutto il tuo codice dovrà trovarsi racchiuso tra due tag: [code] _il _tuo_ codice_ [/code] così da non venire interpretato e non dare adito alla formazione di caratteri indesiderati o cattiva formattazione del testo. Grazie.

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non avrai sistemato il codice come richiesto, nessuno ti potrà rispondere, quindi ti consiglio di farlo al più presto. :wink:

Fatto, ho corretto il post, mi scuso se ho creato problemi anche se tutto questo fiscalismo mi sembra un po eccessivo, comunque voglio rispettare le regole !

La mia richiesta di aiuto consiste nel bloccare la funzione, quindi non deve tornare nel "void loop", fin quando ripremerò di nuovo il tasto BUTTONTIME. Spero di essere stato più chiaro:

Ok, il problema è che raramente può essere utile non tornare al loop(), comunque puoi usare il while.

comunque voglio rispettare le regole !

Bravo, ti renderai conto che un codice formattato e più leggibile di uno non formattato, per di più il forum interpreta dei simboli in modo speciale ad esempio per visualizzare una emoticon.

void loop() {

 if (digitalRead(BUTTONTIME)==HIGH) {
     while(digitalRead(BUTTONTIME));  // cicla fintanto che digitalRead(BUTTONTIME) == HIGH

     delay(50);    // esegue da qui in poi dopo il rilascio del punlsante (il delay non serve più)                                  
     setClockdisplay(); // esegue la funzione e ritorna
     while(digitalRead(BUTTONTIME)==LOW);  // trappola bloccante: cicla fintanto che il pulsante
     // è rilasciato.  Appena premi il pulsante esce dal while e ripete il loop
 
 }

Dovrebbe funzionare ma non ho provato. Mi sento di consigliarti una macchina a stati finiti
basata su switch case, qui un esempio.

Ciao.

Per le impostazioni, se posso bloccare il flusso del programma senza problemi, uso sempre una forma così (pulsante che chiude a massa):

while (digitalRead(PULSANTE))
  {
  }

In realtà, perché funzioni bisogna fare una piccola aggiunta, perciò il tutto diventa:

if (!digitalRead(PULSANTE))
  {
  // Attende che lasci il pulsante:
  while (!digitalRead(PULSANTE));
  // Rimane nel while finché non premo nuovamente:
  while (digitalRead(PULSANTE))
    {
    }
  }

Naturalmente deve esserci un condensatore (100~220nF) anti rimbalzo in parallelo al pulsante; qualora non ci fosse, serve almeno un delay(200); dopo il primo while.

Sono d'accordo sul non fornire tutto già fatto, ma è anche istruttivo leggere piccoli blocchi di base, studiarli e provare a modificarli secondo le proprie esigenze specifiche.

Standardoil:
Scalda il cuore leggere queste cose

Vero!

ilguargua:
@Guglielmo : Hai ragione, scusa, ... in futuro cercherò di evitare.

Alla fine, la pappa pronta è rimasta sul piatto ;D

linomari:
...
La mia richiesta di aiuto consiste nel bloccare la funzione, quindi non deve tornare nel "void loop", fin quando ripremerò di nuovo il tasto BUTTONTIME. Spero di essere stato più chiaro:
...

Mi permetto di suggerire un diverso modo di pensare.
Nel software il concetto di "bloccare" va interpretato più come un "non fare niente finchè".
Bloccare è male a meno di piccoli esperimenti mirati, ma in generale sarebbe da evitare come la peste.
Da qui il suggerimento

Maurotec:
...Mi sento di consigliarti una macchina a stati finiti
basata su switch case, qui un esempio.

In pratica si definisce uno stato, in quello stato si possono fare solo certe operazioni e ci sono meccanismi per permettere il cambio di stato.
Ad es. nello stato X puoi solo testare se viene pigiato BUTTONTIME senza fare altro, equivale a bloccare il programma in attesa che venga ripigiato il pulsante desiderato, ma senza bloccare il programma.
Ad es. se avessi un display che mostra l'ora, in questo modo, sarebbe ancora possibile aggiornare il display allo scorrere del tempo.

linomari:
... anche se tutto questo fiscalismo mi sembra un po eccessivo...

Sai a cosa serve tutto questo fiscalismo?
A rendere fruibile i contenuti del forum anche ad altri (maggior leggibilità dei contenuti) e a non far perdere troppo tempo alle persone volenterose che donano agli altri, in questo caso tu, il proprio tempo per cercare di aiutarli.
Non è un fiscalismo fine a se stesso ma utile a migliorare l'efficacia del forum.
Poi, sono perfettamente consapevole che il primo pensiero di molti che pongono domande su questo forum è: ho un problema e lo sparo li così altri me lo risolvono gratis e senza fare troppe storie...
Altri invece pensano: perchè perdere tempo io a fare una ricerca in internet se la possono fare altri per me... questi, in genere, si arrabbiano pure se qualcuno gli dice qualcosa...

Maurizio

Grazie a tutti ragazzi, ho capito il meccanismo e funziona alla perfezione !!! :slight_smile: