salir de bucle while

Hola, llevo días luchando para salir de un bucle y no logro romperlo, el ejercicio consta de 3 secuencias de encendido y apagado de un motor con diferentes tiempos y su estado indicado por 2 leds (encendido y apagado), estas secuencias deben ejecutarse infinitamente al presionar un pulsador de inicio y desactivarse todo con otro pulsador, es aquí donde tengo el problema.

para arrancar me funciona perfecto, pero al pulsar para desactivar todo no me funciona, la única forma en que pare todo es manteniendo pulsado al final de la ejecución del código.

por lo que he buscado, la función break es la mas recomendada para salir de un bucle, pero en este caso, necesito que se desactive todo inmediatamente con el pulsador de parada.

he intentado el break de varias formas, en varias partes del codigo, dentro un while, dentro de un for infinito, con switchcase y ya agote mis conocimientos, no sé que estoy haciendo mal por lo que recurro a su ayuda.

la última y mejor opción que logre hacer es la siguiente:

int lede=12;    //Led motor encendido
int leda=13;    //Led motor apagado
int iniciar=8;  //Pulsador Iniciar
int apagar=9;   //Pulsador Apagar
int motor=6;    //Motor
bool bi;
bool ba;

void setup() {
    pinMode(lede,OUTPUT);
    pinMode(leda,OUTPUT);
    pinMode(motor,OUTPUT);
    pinMode(iniciar,INPUT);
    pinMode(apagar,INPUT);
}

void loop() {
  bi  = digitalRead(iniciar);
  ba  = digitalRead(apagar);
 
  if (bi){
      while(true){
  for(int sec1=1;sec1<=3;sec1++){
  analogWrite(motor,40);
  digitalWrite(lede,1);
  digitalWrite(leda,0);
    delay(8000);
  analogWrite(motor,0);
  digitalWrite(lede,0);
  digitalWrite(leda,1);
    delay(3000);}
  
  for(int sec2=1;sec2<=2;sec2++){
  analogWrite(motor,40);
  digitalWrite(lede,1);
  digitalWrite(leda,0);
    delay(4000);
  analogWrite(motor,0);
  digitalWrite(lede,0);
  digitalWrite(leda,1);
    delay(4000);}
  
  for(int sec3=1;sec3<=1;sec3++){
  analogWrite(motor,40);
  digitalWrite(lede,1);
  digitalWrite(leda,0);
    delay(2000);
  analogWrite(motor,0);
  digitalWrite(lede,0);
  digitalWrite(leda,1);
    delay(8000);}
                        
            ba = digitalRead(apagar);
            if (ba){
                digitalWrite(lede,LOW);
                digitalWrite(leda,HIGH);
                analogWrite(motor,0);
                break;}
      }
  }
  else if (!bi) {
        digitalWrite(lede,LOW);
        digitalWrite(leda,HIGH);
        analogWrite(motor,0);
  }
}

de antemano muchas gracias.

Bienvenido al foro y mi enhorabuena por postear correctamente el código.

Tu código solo tiene un problema: delay por todos sitios. Te hago un analisis de tu código para que veas que pasa.

int lede=12;    //Led motor encendido
int leda=13;    //Led motor apagado
int iniciar=8;  //Pulsador Iniciar
int apagar=9;   //Pulsador Apagar
int motor=6;    //Motor
bool bi;
bool ba;

void setup() {
    pinMode(lede,OUTPUT);
    pinMode(leda,OUTPUT);
    pinMode(motor,OUTPUT);
    pinMode(iniciar,INPUT);
    pinMode(apagar,INPUT);
}

void loop() {
  bi  = digitalRead(iniciar);
  ba  = digitalRead(apagar);
 
  if (bi){
    while(true) {
      // Aquí empieza la secuencia con delay. Se va a ejecutar siempre.
      // Calculemos cuanto tiempo esta en cada secuencia, solo los delay ignorando
      // las otras sentencias que son "instantaneas"
      // Esto tarda en ejecutarse 3*(8+3)=33 segundos.
      for(int sec1=1;sec1<=3;sec1++){
        analogWrite(motor,40);
        digitalWrite(lede,1);
        digitalWrite(leda,0);
        delay(8000);
        analogWrite(motor,0);
        digitalWrite(lede,0);
        digitalWrite(leda,1);
        delay(3000);
      }
      // Esta secuencia se va a ejecutar en 2*(4+4)=16 segundos.
      for(int sec2=1;sec2<=2;sec2++){
        analogWrite(motor,40);
        digitalWrite(lede,1);
        digitalWrite(leda,0);
        delay(4000);
        analogWrite(motor,0);
        digitalWrite(lede,0);
        digitalWrite(leda,1);
        delay(4000);
      }
      // Esta secuencia se va a ejectuar en 3*(2+2)=12 segundos.
      for(int sec3=1;sec3<=1;sec3++){
        analogWrite(motor,40);
        digitalWrite(lede,1);
        digitalWrite(leda,0);
        delay(2000);
        analogWrite(motor,0);
        digitalWrite(lede,0);
        digitalWrite(leda,1);
        delay(8000);
      }
      // Aqui termina la secuencia. Toda la secuencia anterior lleva 33+16+12=61 segundos.
      // Durante este tiempo aunque pulses el boton no lo va a leer porque esta ocupado.
      // Cuando sale de la secuencia compruebas el botón apagar, pero como no lo tengas apretado
      // antes de que pasen esos 61 segundos, se va a ejectuar y muchisimo más rápido (imperceptible).
      ba = digitalRead(apagar);
      if (ba){
        digitalWrite(lede,LOW);
        digitalWrite(leda,HIGH);
        analogWrite(motor,0);
        // Puede que ocurra o no, depende de si estas entre los 61 segundos de un paso y otro.
        break;
      }
      // Si tenias el botón pulsado entonces parará, si no lo tenias pulsado volverá al inicio
      // del bucle con lo que volverá a tardar otros 61 segundos.
    }
  }
  else if (!bi) {
        digitalWrite(lede,LOW);
        digitalWrite(leda,HIGH);
        analogWrite(motor,0);
  }
}

Esto es lo que se llama codigo bloqueante ya que no te permite hacer otra cosa hasta que termine.

La solución pasa por usar millis.

Gracias por la aclaración victorjam, aún no conozco la función millis, investigare como funciona y volveré para decir que tal me fue.

Y busca además por “finite state machine”
Mírate el ejemplo “blink without delay” y estúdialo hasta que lo has entendido de todo.

En este foro tenemos en Documentación buenos tutoriales al respecto para el uso de millis() y máquinas de estados.
Ve a Documentación => Indice de temas tutoriales y encontrarás ambos.

@BRIO
Interrupciones en un ejercicio de un par de pulsadores?

el ejercicio consta de 3 secuencias de encendido y apagado de un motor con diferentes tiempos y su estado indicado por 2 leds (encendido y apagado), estas secuencias deben ejecutarse infinitamente al presionar un pulsador de inicio y desactivarse todo con otro pulsador, es aquí donde tengo el problema.

donde colocarías las interrupciones?

A ver mi estimado @BRI0, se donde se definen las interrupciones, se que se pueden usar en cualquier caso, ahora, TODOS te diremos que usar interrupciones en un ejercicio como este, es una tontería.
Tu los quieres usar, usalos pero las interrupciones se pensaron para otra cosa, no para accionar pulsadores que prenden LEDs.
Repito x enésima vez, las quieres usar, úsalas. Es lo mas aconsejable? NO.

Fueron pensadas para reaccionar a eventos rápidos. Tienes ese problema aquí? NO.
Fueron pensadas para reaccionar a problemas de hardware específicos, tienes unproblema semejante aquí? Claramente no.

Lo puedes hacer con millis()? claro, y te sobra tiempo.

Ahora si haces un programa usando delay() y luego resulta que un pulsador debe interrumpir la secuencia, el recurso de quien mal aprendio a programar es usar interrupciones con el segundo pulsador.

Lo que acá se te propone es que des un salto de calidad en tu programación, dejes de usar delay() e interrupciones para estas situaciones y crees un programa donde todo sea fluido tal que una simple pulsación no debe esperar a tu secuencia de delay() para ser reconcida.

Se comprende BRIO de lo que hablo?

En el setup agregas el pin interruptor y la función a agregar al ISR. Dicha función se llama automáticamente cuando cambia el estado del pin interruptor.

Estoy de acuerdo con Surbyte. Quizás porque uso mucho millis (y estoy cansado) no se me ocurre como.

Por ejemplo:

// Pone la variable apagar a cierta cuando pulsamos el boton.
void isr_ba(){
  ba = true;
}

Hay detectas que se ha pulsado, luego en el código te tienes que acordar de volverla a poner a false para que pueda iniciarse de nuevo. Pero que ocurre, que la secuencia se detendrá solo cuando termine (cuando analice el if (ba). Si es lo que se pretende, quizás valga, pero si se pretende detener la secuencia independientemente de la secuencia en la que esté no le va a valer.

Yo estoy relajado, te pido lo mismo a ti, okay?
Y no porque sea el moderador se deba hacer lo que yo diga, lo repetí varias veces eb la respuesta de porque no se debe usar interrupciones.

Lee a victorjam o a ElEspanol, acaso ellos tambien te imponen sus ideas? Dime quien opina como tu en las 10 respuestas que hay en este hilo?

Sabes porque no pongo un código, porque el interesado no ha hecho una sola devolución (solo dijo que se va a informar), entonces no se que piensa, y como no se que piensa he aprendido a esperar a la gente a que de su opinión, pero hablo del intersado no de ti, porque si mal he leído el que tiene la duda es @CamiloZ94.

No soy moderador, pero pido que haya paz.

Si quereis debatir sobre el uso de millis, delay e interrupts os propongo que habráis un hilo en la sección de software o debate y no altereis el curso de este hilo.

@BRIO: tu puedes programar como te da la gana. Pero si en serio propones solucionar fallos grave de programación con una ISR, creo que no sepas bien las reglas básicas de programación.
He hecho en los últimos años ya muchos sketches, y todo solucionado con millis. Hasta el multitasking con INTERVAL.h (gracias a Combie para esta fantástica Lib).
ISR solo tenia que emplear en casos muy especiales como contar rpm o interpretar y crear señales de PPM.
Y delay() no se usa fuera de setup(), excepto si sabes muy bien que haces.

Buenas tardes y gracias por las ayudas, perdón por mi ausencia, debido a la contingencia en Chile, marchar, cortes de luz, internet, etc, he tenido muy poco tiempo.

he logrado comprender como funciona millis aunque aún me falta, buscando en este foro me tope con un codigo que pude adaptar para realizar la secuencia que necesito, sin embargo, no logro hacer que funcione todo al pulsar "bi" (botón inicio) ni parar al pulsar "ba" (botón apagar).
tampoco he logrado repetir las secuencias como pide el ejercicio:
8s encendido - 3s apagado (3 veces)
4s encendido - 4s apagado (2 veces)
2s encendido - 8s apagado (1 vez)

por lo que finalmente agregue un caso por cada acción, esto es lo que llevo hasta el momento:

const byte lede = 12;      //Led motor encendido
const byte leda =13;       //Led motor apagado
int bi=8;                  //Boton inicio
int ba=9;                  //Boton apagar
const byte button1 = 8;    
int motor=6;               //Motor DC
byte time=1;                         //Declarar el valor de la variable time (case
unsigned long previusMillis=0;       // Funcion millis
unsigned long interval;

//TIEMPOS 
unsigned long tiempo8s=8000,
              tiempo3s=3000,
              tiempo4s=4000,
              tiempo2s=2000;
              
bool buttonState1=0;                   //Declarar el valor de la variable boton S1

void setup() {
pinMode(leda,OUTPUT);
pinMode(lede,OUTPUT);
pinMode(motor,OUTPUT);
pinMode(bi,INPUT);
pinMode(ba,INPUT);
}

void loop()
{
  digitalRead(ba);
  buttonState1 = digitalRead(button1);
  
  if(buttonState1 && time==2)
  previusMillis=millis();
                   
  switch(time){
  case 1:
      digitalWrite(lede,HIGH);
      digitalWrite(leda,LOW);
      analogWrite(motor,40);
      interval=tiempo8s;
      previusMillis=millis();
      time=2;
            break;
          
  case 2:
        if(millis() -previusMillis>=interval){
      digitalWrite(lede,LOW);
      digitalWrite(leda,HIGH);
      analogWrite(motor,0);
      time=3;
      previusMillis=millis();
      interval=tiempo3s;}
          break;

  case 3:
        if(millis() -previusMillis>=interval){   
      digitalWrite(lede,HIGH);
      digitalWrite(leda,LOW);
      analogWrite(motor,40);
      time=4;
      previusMillis=millis();
      interval=tiempo8s;}             
          break;

  case 4:
        if(millis() -previusMillis>=interval){   
      digitalWrite(lede,LOW);
      digitalWrite(leda,HIGH);
      analogWrite(motor,0);
      time=5;
      previusMillis=millis();
      interval=tiempo3s;}             
          break;
          
  case 5:
        if(millis() -previusMillis>=interval){   
      digitalWrite(lede,HIGH);
      digitalWrite(leda,LOW);
      analogWrite(motor,40);
      time=6;
      previusMillis=millis();
      interval=tiempo8s;}             
          break;

  case 6:
        if(millis() -previusMillis>=interval){   
      digitalWrite(lede,LOW);
      digitalWrite(leda,HIGH);
      analogWrite(motor,0);
      time=7;
      previusMillis=millis();
      interval=tiempo3s;}             
          break;

  case 7:
        if(millis() -previusMillis>=interval){   
      digitalWrite(lede,HIGH);
      digitalWrite(leda,LOW);
      analogWrite(motor,40);
      time=8;
      previusMillis=millis();
      interval=tiempo4s;}             
          break;

  case 8:
        if(millis() -previusMillis>=interval){   
      digitalWrite(lede,LOW);
      digitalWrite(leda,HIGH);
      analogWrite(motor,0);
      time=9;
      previusMillis=millis();
      interval=tiempo4s;}             
          break;

  case 9:
        if(millis() -previusMillis>=interval){   
      digitalWrite(lede,HIGH);
      digitalWrite(leda,LOW);
      analogWrite(motor,40);
      time=10;
      previusMillis=millis();
      interval=tiempo4s;}             
          break;

  case 10:
        if(millis() -previusMillis>=interval){   
      digitalWrite(lede,LOW);
      digitalWrite(leda,HIGH);
      analogWrite(motor,0);
      time=11;
      previusMillis=millis();
      interval=tiempo4s;}             
          break;

  case 11:
        if(millis() -previusMillis>=interval){   
      digitalWrite(lede,HIGH);
      digitalWrite(leda,LOW);
      analogWrite(motor,40);
      time=12;
      previusMillis=millis();
      interval=tiempo2s;}             
          break;

  case 12:
        if(millis() -previusMillis>=interval){   
      digitalWrite(lede,LOW);
      digitalWrite(leda,HIGH);
      analogWrite(motor,0);
      time=13;
      previusMillis=millis();
      interval=tiempo8s;}             
          break;

  case 13:
      if(millis() -previusMillis>=interval)
               time=1;
        break; 
  }
}

Bien!!! valorable tu esfuerzo.

Ahora reviso lo que hiciste y veo como ayudarte.

Al comenzar el loop pones

digitalRead(ba);

eso no tiene sentido.
La idea de digitalRead(pin) es leer un estado y pasarlo a una variable o usarlo en un condicional.
Asi no sirve de nada.

Tal vez haya algun leve error porque no lo he probado.. nada que no puedas resolver.
Use una variable flag de tipo bool que se pone en TRUE cuando accionas bi, y se pone en FALSE cuando accionas ba. Simple..todo lo demas se ejutará sin probleamas. AL final el ultimo estado se pone con el valor del primer case y todo reinicia.

const byte lede = 12;       // Led motor encendido
const byte leda = 13;       // Led motor apagado
const byte bi   =  8;       // Boton inicio
const byte ba   =  9;       // Boton apagar
const byte button1 = 8;   
int motor = 6;               //Motor DC
byte time = 1;                         //Declarar el valor de la variable time (case
unsigned long previusMillis=0;       // Funcion millis
unsigned long interval;

//TIEMPOS
unsigned long tiempo8s = 8000,
              tiempo3s = 3000,
              tiempo4s = 4000,
              tiempo2s = 2000;
             
bool butInicioAnt = false, butInicio;                 
bool butApagadoAnt = false, butApagado;

void setup() {
  pinMode(leda,OUTPUT);
  pinMode(lede,OUTPUT);
  pinMode(motor,OUTPUT);
  pinMode(bi,INPUT);
  pinMode(ba,INPUT);
}

void loop()
{
  butInicio = digitalRead(bi);
  butApagado = digitalRead(ba);

  if (butInicio && !butInicioAnt)
      flag = true;

  if (butApagado && !butApagadoAnt)
      flag = false;
                  
  butInicioAnt = butInicio;                 
  butApagadoAnt = butApagado;

  if (flag) {
      switch(time){
            case 1:
                    digitalWrite(lede,HIGH);
                    digitalWrite(leda,LOW);
                    analogWrite(motor,40);
                    previusMillis = millis();
                    time = 2;
                    break;
                   
            case 2:
                  if (millis() -previusMillis>=tiempo8s){
                      digitalWrite(lede,LOW);
                      digitalWrite(leda,HIGH);
                      analogWrite(motor,0);
                      time = 3;
                      previusMillis = millis();
                    }
                    break;

            case 3:
                  if (millis() -previusMillis>=tiempo3s){   
                      digitalWrite(lede,HIGH);
                      digitalWrite(leda,LOW);
                      analogWrite(motor,40);
                      time = 4;
                      previusMillis = millis();
                    }             
                    break;

            case 4:
                  if (millis() -previusMillis>=tiempo8s){   
                      digitalWrite(lede,LOW);
                      digitalWrite(leda,HIGH);
                      analogWrite(motor,0);
                      time=5;
                      previusMillis = millis();
                    }             
                    break;
                   
            case 5:
                  if (millis() -previusMillis>=tiempo3s){   
                      digitalWrite(lede,HIGH);
                      digitalWrite(leda,LOW);
                      analogWrite(motor,40);
                      time=6;
                      previusMillis = millis();
                    }             
                    break;

            case 6:
                  if (millis() -previusMillis>=tiempo8s){   
                      digitalWrite(lede,LOW);
                      digitalWrite(leda,HIGH);
                      analogWrite(motor,0);
                      time=7;
                      previusMillis = millis();
                      interval=;
                    }             
                    break;

            case 7:
                  if (millis() -previusMillis>=tiempo3s){   
                      digitalWrite(lede,HIGH);
                      digitalWrite(leda,LOW);
                      analogWrite(motor,40);
                      time=8;
                      previusMillis = millis();
                      interval=;
                    }             
                    break;

            case 8:
                  if (millis() -previusMillis>=tiempo4s){   
                      digitalWrite(lede,LOW);
                      digitalWrite(leda,HIGH);
                      analogWrite(motor,0);
                      time=9;
                      previusMillis = millis();
                    }             
                    break;

            case 9:
                  if (millis() -previusMillis>=tiempo4s){   
                      digitalWrite(lede,HIGH);
                      digitalWrite(leda,LOW);
                      analogWrite(motor,40);
                      time=10;
                      previusMillis = millis();
                    }             
                    break;

            case 10:
                  if (millis() -previusMillis>=tiempo4s){   
                      digitalWrite(lede,LOW);
                      digitalWrite(leda,HIGH);
                      analogWrite(motor,0);
                      time=11;
                      previusMillis = millis();
                    }             
                    break;

            case 11:
                  if (millis() -previusMillis>=tiempo4s){   
                      digitalWrite(lede,HIGH);
                      digitalWrite(leda,LOW);
                      analogWrite(motor,40);
                      time=12;
                      previusMillis = millis();
                    }             
                    break;

            case 12:
                  if (millis() -previusMillis>=tiempo2s){   
                      digitalWrite(lede,LOW);
                      digitalWrite(leda,HIGH);
                      analogWrite(motor,0);
                      time=13;
                      previusMillis = millis();
                    }             
                    break;

            case 13:
                if (millis() -previusMillis>=tiempo8s)
                    time=1;
                  break;
            } // fin de switch(time)
    
  } // fin de if
}

Buenas,

Tal vez no sea la solución ideal pero puedes hacer un "delay a la carta" donde compruebe la condición de salida.

Lo he usado varias veces, y como digo a lo mejor no es la mejor solución pero me ha funcionado

bool wait(unsigned long ms) {
	//espera ms msec y si pasa algo, sale con true
	unsigned long end = millis() + ms;
	do {
		if(Aqui colocar la condición) return true;
                //o más condiciones
	} while (millis() < end);
	return false;
}

Luego dentro del while sustituir los delays por (ejemplo delay(50);

do {
....
if (wait(50)) return;
....
}while();

La ultima vez que lo usé fue como retardo en una animación infinita en una dotmatrix. Cuando le llegaba algo por el serial la interrumpía y ejecutaba otra animación infinita según lo enviado.

La mia quedó así:

bool wait(unsigned long ms) {
	//espera ms msec y si hay algo en el serial sale e interrumpe la animación
	unsigned long end = millis() + ms;
	do {
		if (Serial.available()) return true;
	} while (millis() < end);
	return false;
}

Lógicamente tiene sus limitaciones, pero para aplicaciones que no necesiten una alta exactiud en los tiempos, vale.

Espero que sirva.

Saludos