Fermare il loop con pulsante

Ciao a tutti ragazzi. Mi trovo in difficoltà nel fermare il loop tramite pulsante.
Praticamente ho fatto delle prove questo è il codice:

void loop()
{
  
  
  readButtons();  //I splitted button reading and navigation in two procedures because 
  navigateMenus();
  switch(ModCorrente){
  case StatoStart:
    navigateMenus();  //in some situations I want to use the button for other purpose (eg. to change some settings)
    
       lcd.clear();
      i++;
      lcd.print(i);
      digitalWrite(wakepin, HIGH); //turn wakeup/focus on
      delay(wakeup); //keep focus
      digitalWrite(wakepin, LOW); //turn wakeup off
      delay(wakewait); //wait
      digitalWrite(outpin, HIGH); //press the shutter
      delay(shutter_on); //wait the shutter release time
      digitalWrite(outpin, LOW); //release shutter
      delay(shutter_off); //Intervallo tra uno scatto e l'altro
      rotateDeg(360, 1); //Movimento motore
      delay(500); //delay motore per evitare vibrazioni prima dello scatto
      
     
      break;
    
    }//switch


} //loop()...

Vorrei poter fermare tramite pulsante il ciclo.
Se metto un if con una costante ad esempio

if(i<4){
lcd.clear();
i++;
lcd.print(i);
digitalWrite(wakepin, HIGH); //turn wakeup/focus on
delay(wakeup); //keep focus
digitalWrite(wakepin, LOW); //turn wakeup off
delay(wakewait); //wait
digitalWrite(outpin, HIGH); //press the shutter
delay(shutter_on); //wait the shutter release time
digitalWrite(outpin, LOW); //release shutter
delay(shutter_off); //Intervallo tra uno scatto e l'altro
rotateDeg(360, 1); //Movimento motore
delay(500); //delay motore per evitare vibrazioni prima dello scatto
} break;

Il tutto funziona alla perfezione. una volta arrivato a 4 si ferma.
Mentre se faccio una cosa di questo genere:

if(digitalRead(Bottone) == LOW){
lcd.clear();
i++;
lcd.print(i);
digitalWrite(wakepin, HIGH); //turn wakeup/focus on
delay(wakeup); //keep focus
digitalWrite(wakepin, LOW); //turn wakeup off
delay(wakewait); //wait
digitalWrite(outpin, HIGH); //press the shutter
delay(shutter_on); //wait the shutter release time
digitalWrite(outpin, LOW); //release shutter
delay(shutter_off); //Intervallo tra uno scatto e l'altro
rotateDeg(360, 1); //Movimento motore
delay(500); //delay motore per evitare vibrazioni prima dello scatto
} break;

Funziona soltanto se tengo il pulsante pigiato. Come dovrei fare per farlo funzionare al click del pulsante?

Devi usare la funzione millis, guarda l'esempio BlinkWithoutDelay presente nell'IDE, e fare un check sul trascorrere del tempo. I delay bloccano il codice.

PS:
cmq questa è una cosa stradetta sul forum, bisognerebbe usare un po' la funzione "Cerca".

leo72:
Devi usare la funzione millis, guarda l'esempio BlinkWithoutDelay presente nell'IDE, e fare un check sul trascorrere del tempo. I delay bloccano il codice.

PS:
cmq questa è una cosa stradetta sul forum, bisognerebbe usare un po' la funzione "Cerca".

ti ringrazio, anche se non riesco a trovare il nesso. In questo caso non è una questione di delay, in quanto se nel codice metto:

if(digitalRead(Bottone) == LOW){
      lcd.clear();
      i++;
      lcd.print(i);
      
} break;

Quindi nessun delay, con il pulsante non riesco a bloccare. Per bloccare devo tenerlo premuto

La funzione loop() é quella che si ripete di continuo. Se intendi quella come "loop" Ti ripondo che non si deve fare (si puó, ma blocchi l'esecuzione del Tuo programma).

Per fare che il codice viene eseguito solo 1 volta memorizzi che é stato premuto un pulsante e fai quello che vuoi fare. Poi cancelli la variaabile quando il pulsante viene rilasciato.

if (digitalRead(pulsante) ==1 && premuto ==0) // viene eseguito la prima volta che vede il pulsante premuto
{
premuto =1
fai quello che devi fare)
}

if (digitalRead(pulsante) ==0 && premuto ==1) premuto =0

Ciao Uwe

grazie uwe. Ma per esempio. se nel loop ho un timer che voglio fermare, come potrei fare se dici che non dovrei bloccare l'esecuzione del loop?

Non ho detto che non puoi uscire dalla funzione loop() per esempio con un break(). Puoi fermarla con un delay() oppure eseguire in modo condizionato quello che vuoi fare:

void loop()
{
if (pulsante premuto ) accendi LED
}

Ciao Uwe

Perfetto. Sono riuscito a bloccare come voglio il loop. Adesso però, mi si presenta un altro problema ovvero, una volta uscito non mi permette di ripartire.

manda il codice
Ciao Uwe

allora metto la semplificazione con un if numerico come controllo:

void loop()
{
statobottone=digitalRead(buttonPinLeft);

readButtons(); //I splitted button reading and navigation in two procedures because
navigateMenus();
switch(ModCorrente){
case StatoStart:

if(i<4){
lcd.clear();
i++;
lcd.print(i);

}

break;

}//switch

Allora arrivati a 4 giustamente il conteggio s'interrompe. A questo punto io clicco il tasto esc e ritorno al menù sul lcd. quando vado per rientrare per riavviare il timer, questo non parte più una seconda volta. Ho provato a mettere anche un else con i=0; ma naturalmente il conteggio ricomincia ciclicamente. Mentre se metto nell'else break; i=0; resto bloccato.

Scusate l'intromissione, ma vedo errori di logica nel codice. Lo switch..case mi sembra usato un po' male. Inoltre senza il resto del programma, è difficile capire cosa possa non andare..

Ah.. un'altra cosa:

Mentre se metto nell'else break; i=0; resto bloccato.

un'assegnazione dopo un break non è corretto. Non fa più parte del blocco di codice dell'if..else e non puoi sapere dove e quando verrà eseguita

un'assegnazione dopo un break non è corretto. Non fa più parte del blocco di codice dell'if..else e non puoi sapere dove e quando verrà eseguita

infatti facendo un controllo ho visto che la i mi resta sempre di valore 4 e non riesco a portarla a 0. Per questo poi, successivamente, non riesco più a rientrare nell'if... come posso fare a resettare la variabile i?

leo72:
Inoltre senza il resto del programma, è difficile capire cosa possa non andare..

secondo me nel loop ci deve essere solo il controllo pulsante e relativa memoria della sua pressione

void loop()
{
controllo pulsante
if (variabile di memoria .... se è stato premuto =1) vai a il_dafare();
altrimenti non ci andare
}

void il_dafare()
{
.................................
.................................
.................................
.................................
}

dove sta il prob :smiley:

ciao

Se non vuoi darci tutto il codice non possiamo aiutarti.
Ciao Uwe

Vi metto il codice tramite link perchè nel code non me lo fa inserire perchè troppo lungo per questo non volevo mettervi tutta la pappardella:

QUI

Ho messo la parte del menù togliendo le cose tipo gestione motore che in questo caso non serviva.
Praticamente vorrei riuscire a bloccare il loop(oppure un ciclo for usando la classe menuUsed). Come da codice (in questo caso nel loop) riesco a bloccare il ciclo, ma poi una volta uscito dalla voce menù, non riesco a fare ripartire il timer.

Molto di quel codice io non ho idea di come funzioni. Mi sembra di capire che vuoi eseguire il codice sono una volta. Poi vuoi anche decidere quando è il caso di rieseguire il codice nuovamente come se fosse la prima volta.

una variabile globale oneShot = 0;

loop()
{
if (!oneShot) // se è falsa incrementa solo una volta in quanto qui non ci entrerà più
oneShot++;
if (oneShot == 1) { // oneShot non può che essere uno e quindi esegue il tuo codice
chiama "miafunzione"
terminata la funzione divi fare in modo che in questa if non ci entri nuovamente quindi
oneShot = 2;
}
}

E solo psedo code. Quando vuoi eseguire nuovamente "miafunzione", azzeri la variabile oneShot. Dai anche una guardata alla macchina a stati finiti, per capire cosa sono gli stati sequenziali, di transizione ecc. Nel playground c'è anche una lib FSM, ma non mi chiedere come funziona perchè non ho approfondito.

La cosa che rompe parecchio con Arduino è che non puoi usare la programmazione modulare dichiarando una variabile che mantiene lo stato ed è visibile solo all'interno del modulo. Quindi sei costretto a fare uso di variabili globali che consumano ram. L'altra fregatura che Arduino permette di fare cose visimamente importanti, anche a chi non si è mai scontrato con i problemi di logica di base. In pratica sei fermo per una cosa banale.

Spero ti aiuti.
Ciao.

MauroTec:
Molto di quel codice io non ho idea di come funzioni. Mi sembra di capire che vuoi eseguire il codice sono una volta. Poi vuoi anche decidere quando è il caso di rieseguire il codice nuovamente come se fosse la prima volta.

una variabile globale oneShot = 0;

loop()
{
if (!oneShot) // se è falsa incrementa solo una volta in quanto qui non ci entrerà più
oneShot++;
if (oneShot == 1) { // oneShot non può che essere uno e quindi esegue il tuo codice
chiama "miafunzione"
terminata la funzione divi fare in modo che in questa if non ci entri nuovamente quindi
oneShot = 2;
}
}

E solo psedo code. Quando vuoi eseguire nuovamente "miafunzione", azzeri la variabile oneShot. Dai anche una guardata alla macchina a stati finiti, per capire cosa sono gli stati sequenziali, di transizione ecc. Nel playground c'è anche una lib FSM, ma non mi chiedere come funziona perchè non ho approfondito.

La cosa che rompe parecchio con Arduino è che non puoi usare la programmazione modulare dichiarando una variabile che mantiene lo stato ed è visibile solo all'interno del modulo. Quindi sei costretto a fare uso di variabili globali che consumano ram. L'altra fregatura che Arduino permette di fare cose visimamente importanti, anche a chi non si è mai scontrato con i problemi di logica di base. In pratica sei fermo per una cosa banale.

Spero ti aiuti.
Ciao.

Grazie Mauro molto interessante. Intanto sono riuscito a fare quello che volevo. E' vero ero fermo per una banalità. Comunque approfondirò quegli aspetti che mi hai detto che mi torneranno sicuramente utili!

A me pare che non resetti mai "i" per cui è normale che nel ciclo non ti ci rientra più. Ho visto solo un incremento di "i" ma non un suo riazzeramento.