Come uscire da un ciclo?

Salve a tutti ragazzi, ho bisogno di un piccolo aiuto.
Sto programmando un cancello per la casa che quando sta in chiusura, se le fotocellule vengono interrotte, il cancello si blocca e poi si riapre di nuovo, mentre se non vengono interrotte le fotocellule continua a chiudersi.
Esiste un istruzione che appena si verifica l'evento (in questo caso quando le fotocellule vengono interrotte) esce istantaneamente dal ciclo, e quindi senza terminarlo, e mi ritorna in un punto preciso dello sketch?
Spero di essere stato chiaro.

Con la funzione break (senza parentesi) che termina un ciclo e arrivi alla sua fine.
Se sei in una funzione a parte puoi anche usare return (con la quale puoi anche far ritornare un valore al programma base, facendo arrivare alla riga successiva rispetto alla chiamata della funzione.
Altri metodi possibili, anche se sviliscono il programmatore sono:
Rendere falsa la condizione di ciclo (impossibile per cicli infiniti)
goto ed etichette (aborrata generalmente)

Silente:
Con la funzione break (senza parentesi) che termina un ciclo e arrivi alla sua fine.
Se sei in una funzione a parte puoi anche usare return (con la quale puoi anche far ritornare un valore al programma base, facendo arrivare alla riga successiva rispetto alla chiamata della funzione.
Altri metodi possibili, anche se sviliscono il programmatore sono:
Rendere falsa la condizione di ciclo (impossibile per cicli infiniti)
goto ed etichette (aborrata generalmente)

Io avevo scritto così:

if (statom == 2) //Se lo stato dei motori indica che il cancello è aperto allora deve iniziare a chiudere il cancello
{
digitalWrite (motore1, HIGH);
delay(1000); //ho bisogno che un'anta del cancello si chiuda prima dell'altra
digitalWrite (motore2, HIGH);
delay (5000); //tempo che impiega il cancello a chiudersi del tutto
digitalWrite (motore1, LOW);
delay(1000);
digitalWrite (motore2, LOW);
}

In tutto ciò ho bisogno che, nel caso in cui la fotocellula venga interrotta, esca da immediatamente da questo ciclo, senza quindi terminarlo e mi ritorna nel ciclo di apertura del cancello (quindi esca dal ciclo di chiusura e attui il ciclo di apertura).

Ed allora il problema è un altro.
Quelle delay() sono "bloccanti" ovvero delay(5000) per 5 secondi Arduino NON può fare null'altro
Può solo essere interrotto da una gestione interrupt (argomento complesso)

Quindi devi rivedere tutta la logica usando dei temporizzatori che si basano su millis().
Se sei un principiante, non è proprio semplice. Vedi l'esempio BlinkWithoutDelay che però ha un solo contatore, mentre tu qui ne hai 3.

P.S. se la fotocellula viene interrotta come lo rilevi ? Leggendo un pin ??
In questo caso si potrebbero modificare quelle delay() con dei cicli while o for in cui dentro leggi il pin e nel caso "forzi" il non proseguire.

Non puoi uscire da delay. Devi usare millis(). GUARDA IN GIRO SUL FORUM che trovi taaaaaaaaaaaaaaaaa aaaaaaaaaaa aaaaaaaaaa aaaaaaaa aaaaa nti link e soluzioni a riguardo

E se non trovi basta scrivere "millis()" sulla barra di Google e il PRIMO link che ti esce é la sfilza di threed

nid69ita:
Ed allora il problema è un altro.
Quelle delay() sono “bloccanti” ovvero delay(5000) per 5 secondi Arduino NON può fare null’altro
Può solo essere interrotto da una gestione interrupt (argomento complesso)

Quindi devi rivedere tutta la logica usando dei temporizzatori che si basano su millis().
Se sei un principiante, non è proprio semplice. Vedi l’esempio BlinkWithoutDelay che però ha un solo contatore, mentre tu qui ne hai 3.

Bene o male mi sono informato e so come funziona l’interrupt, invece il millis() non capisco che potenzialità abbia

La questione interrupt non è complessa solo come argomento generale, ma complica la gestione del
software

Il millis() permette di avere dei "cicli" temporizzati che si basano su un contatore che viene incrementato dal un timer interno.
Se guardi esempio blink e blinkwithoutdelay non è molto significativo. Ma se hai 2 led da far lampeggiare in tempi diversi e momenti diversi... con delle delay non fai nulla.

Su queste MCU NON hai un multitasking, non puoi fare 2 cose in contemporanea. In realtà anche su un PC (tralasciamo il multicore) è il sistema operativo che divide il tempo a processi/programmi diversi.
Qui non c'e' un S.O. che lo faccia. L'unica è che tu scrivi un programma che "divida" il tempo usando un contatore (millis) e ti "simuli" un qualcosa che permette di fare delle cose in "multitasking"

L'ideale sarebbe un programma a stati finiti ed inoltre avere dei finecorsa e non basarsi su dei tempi

Se però la fotocellula quando interrotta è semplicemente un pin che diventa HIGH o LOW si potrebbero sostituire quelle delay() con una funzione tua che conta quel tempo ma controlla anche il pin ed eventualmente esce se la fotocellula viene interrotta.

if (statom == 2) 
{ ciclochiudi=1;          // dichiararla byte tra le variabili globali ad inizio
  digitalWrite (motore1, HIGH);
  // delay(1000); 
  ciclochiudi=MiaFunzChkAndWait(1000);  // attende x tempo e legge pin
  if(ciclochiudi==1)   // se fotocellula non interrotta, ciclochiudi ancora a 1 (vero)
  { digitalWrite (motore2, HIGH);
    // delay (5000); 
    ciclochiudi=MiaFunzChkAndWait(5000);  // attende x tempo e legge pin
    if(ciclochiudi==1)   // se fotocellula non interrotta, ciclochiudi ancora a 1
    { digitalWrite (motore1, LOW);
      // delay(1000);
      ciclochiudi=MiaFunzChkAndWait(1000);  // attende x tempo e legge pin
      if(ciclochiudi==1)   // se fotocellula non interrotta, ciclochiudi ancora a 1
      { digitalWrite (motore2, LOW);
      }
    }
  }
  // se qui ciclochiudi è 0 (falso) allora è stato interrotto
}
byte MiaFunzChkAndWait(int tempo)
{ for(int i=0;i<tempo;i++)        // tempo 1000, ciclo 1000 volte con attesa 1, quindi equivale a delay(1000)
  { delay(1);
     if( digitalRead(pinFotocellula)==LOW ) return 0;   // fotocellula interrotta, esco con 0
  }
  return 1;
}

… Oppure potresti cambiare tutto ebrendere il programma una macchina a stati finiti, in cui il loop gira ininterrotto, e con una serie di if fai quello che serve.
Certamente questo é un cambiamento radicale nella logica, e se optibper questa strada conviene che riparti da capo

Secondo me dovresti avere due sensori di finecorsa uno per ogni anta E NON UN TEMPORIZZATORE, e usare un ciclo do while() che continui fino a che i finecorsa sono attivi.

All'interno del while() leggi sempre lo stato delle fotocellelule, se attive fermi i motori e riapri il cancello.

// Semi pseudocodice-codice


byte finercorsa1=5;

byte finecorsa2=6;

byte sensoreAperto1=7;

byte sensoreAperto2=8;

byte fotocellula1=9;

byte motore1=10;

byte motore2=11;

byte pulsanteApertura=12;

byte pulsanteChiusura=4;

void setup(){

     //tutti i pinMode()

}

void loop(){

     if(digitalRead(pulsanteApertura)==HIGH){

           apri();
     }
     else if(digitalRead(pulsanteChiusura)==HIGH){

          chiudi();

    }

}


void apri(){


}


void chiudi(){

    digitalWrite (motore1, HIGH);
    delay(1000); //ho bisogno che un'anta del cancello si chiuda prima dell'altra
    do{
           if(digitaRead(finecorsa1)==LOW)//Se non ho raggiunto il finecorsa anta 1
               digitalWrite(motore1,HIGH);
           else 
               digitalWrite(motore1,LOW);

           /***************************************/
           if(digitaRead(finecorsa2)==LOW)//Se non ho raggiunto il finecorsa anta 2
              digitalWrite(motore2,HIGH);

           else 
              digitalWrite(motore2,LOW);
           if(digitaRead(fotocellula)==HIGH){

                digitaWrite(motore1,LOW);
                digitalWrite(motore2,LOW);
                delay(3000);
                apri();
                break; // Esce dal ciclo

           }
           

    }while(digitalRead(finecorsa1)==LOW || digitalRead(finecorsa2)==LOW); // Se uno dei due finecorsa
    // non  è attivo continua il while()

    // Raggiunto la chiusura fermo i motori
    digitaWrite(motore1,LOW);
    digitalWrite(motore2,LOW);
}

Ho modificato, ho aggiunto un break; che esce dal ciclo dopo l'apertura

PREMESSA:
Spero che sia per un plastico, per un modellino, specialmente se hai questi dubbi.

io userei un while unico, che legge finecorsa e fotocellula

attiva motore chiusura

while (finecorsa off e fotocellula off) leggi finecorsa e leggi fotocellula, se fotocellula on imposta una variabile globale di allarme fotocellula

spegni motore chiusura

se allarme fotocellula, apri

insomma, se usi un ciclo while, esce dal ciclo quando la condizione è falsa e la condizione può essere una combinazione di altre condizioni come "se il finecorsa è off e la fotocellula è off".

oltre all'allarme fotocellula, comunque, dovrebbero esserci altri allarmi come quello - importantissimo - di presenza ostacoli che causa il blocco del movimento sia in apertura che in chiusura
visto che tutto il discorso è a fini didattici, come lo imposteresti questo allarme di presenza ostacoli?

Ho modificato il codice del mio post sopra :), ho aggiunto un break; che esce dal ciclo dopo l’apertura.

Perché in caso di fotocellula attiva, ferma i motore e apre, ma senza un break; che esce dal ciclo una volta aperto riprenderebbe la chiusura del cancello :slight_smile:

Grazie a tutti per le risposte esaustive!
In realtà abbiamo cablato io e mio padre un cancello automatico.
Tornati a casa, ci è venuto lo sfizio di provare a ricreare con arduino la funzione del cancello senza però utilizzare i finecorsa. É solo una questione di imparare a programmare scoprendo nuove funzioni

E senza i fine corsa cone fai? Misuri il consumo del motore o vai a tempo?