2 votos

Cómo salir del estado if que está dentro del bucle for y volver al bucle void en Arduino

Mi código:

#define MAX 10
const int LED1 = 2;
const int LED2 = 8;
const int LED3 = 4;
const int LED4 = 5;
int val;
int array[MAX];
int counter = 0;
int i;
int old_b = 0;
int error;

void setup() { 
 Serial.begin(9600);
 pinMode(A5, INPUT_PULLUP); 
}

int readButtons(int pin) {
 int b,c;
 c=analogRead(pin);
 Serial.print("analogRead = ");
 Serial.println(c); 
 delay(100);
 if (c>1015) b = 0; 
 else if (c>70 && c<76) b = 1; 
 else if (c<128 && c>122) b = 2; 
 else if (c>169 && c<175) b = 3; 
 else if (c>209 && c<217) b = 4;
 else if (c>247 && c<256) b = 5;
 else if (c>280 && c<291) b = 6;
 else b = 0;
 if (b == old_b) {
  return 0;
  old_b = b;
 } else {
   return b;
   stari_b = b;
 }
}

void loop() {
 while ((val = readButtons(5)) != 5) {
  if (val == 1) {
   array[counter] = 1;
   counter++;
   Serial.print("In ");
   Serial.print(counter);
   Serial.print(" saving ");
   Serial.println("1");
   delay(500);
  } else if (val == 2) {
     array[counter] = 2;
     counter++;
     Serial.print("In ");
     Serial.print(counter);
     Serial.print(" saving ");
     Serial.println("2");
     delay(500);
  } else if (val == 3) {
     array[counter] = 3;
     counter++;
     Serial.print("In ");
     Serial.print(counter);
     Serial.print(" saving ");
     Serial.println("3");
     delay(500);
  } else if (val == 4) {
     array[counter] = 4;
     counter++;
     Serial.print("In ");
     Serial.print(counter);
     Serial.print(" saving ");
     Serial.println("4");
     delay(500);
  }
  if (counter == MAX) {
   counter = 0;
  }
 }

 for (i = 0; i < MAX; i++) {
  if (array[i] == 1) {
     digitalWrite(LED3, HIGH);
     digitalWrite(LED4, HIGH);
     delay(1000);
     digitalWrite(LED3, LOW);
     digitalWrite(LED4, LOW);
     delay(1000);
     Serial.print("Executing ");
     Serial.print(i);
     Serial.print(" ");
     Serial.println(array[i]);
     delay(500);
  }
  if (array[i] == 2) {
     digitalWrite(LED1, HIGH);
     digitalWrite (LED2, HIGH);
     delay(1000);
     digitalWrite(LED1, LOW);
     digitalWrite(LED2,LOW);
     delay(1000);
     Serial.print("Executing ");
     Serial.print(i);
     Serial.print(" ");
     Serial.println(array[i]);
     delay(500);
  }
  if (array[i] == 3) {
     digitalWrite(LED2, HIGH);
     digitalWrite(LED4, HIGH);
     delay(1000);
     digitalWrite(LED2, LOW);
     digitalWrite(LED4, LOW);
     delay(1000);
     Serial.print("Executing ");
     Serial.print(i);
     Serial.print(" ");
     Serial.println(array[i]);
     delay(500);
  }
  if (array[i] == 4) {
     digitalWrite(LED1, HIGH);
     digitalWrite(LED3, HIGH);
     delay(1000);
     digitalWrite(LED1, LOW);
     digitalWrite(LED3, LOW);
     Serial.print("Executing ");
     Serial.print(i);
     Serial.print(" ");
     Serial.println(array[i]);
     delay(500);
  }

 } 
}

Así que tengo botones conectados como este , excepto que yo los tengo 5. Cuando uno de los primeros cuatro es presionado el sketch almacena 1,2,3 o 4 para denotar que botones fueron presionados y lo almacena en un array de enteros. Cuando el quinto (el botón "GO") es presionado el bucle while termina y comienza el bucle for que de acuerdo a los botones presionados parpadea los LEDs. Quiero hacer que mientras el Arduino parpadea los LEDs, es decir, mientras se ejecuta el bucle for, si en algún momento se pulsa el quinto botón "GO" debe dejar de parpadear los LEDs y comenzar el programa desde el principio ( void loop { ... } ) es decir, esperar de nuevo a las pulsaciones de los cuatro primeros botones.


Me las arreglé para hacer esto:

#define MAX 50
const int LED1 = 2;
const int LED2 = 3;
const int LED3 = 4;
const int LED4 = 5;
int array[MAX];
int old_b = 0;
int val;
int counter = 0;
int i;
int temp;
int L1;
int L2;

void setup () {
  pinMode (A5, INPUT_PULLUP);
  Serial.begin(9600);
}

int readButtons (int pin) {
  int b, c;
  c = analogRead(pin);
  Serial.print("analogRead =  ");
  Serial.println(c);
  delay(100);
  if (c > 1015) b = 0;
  else if (c > 70 && c < 76) b = 1;
  else if (c > 122 && c < 128) b = 2;
  else if (c > 169 && c < 175) b = 3;
  else if (c > 209 && c < 217) b = 4;
  else if (c > 247 && c < 256) b = 5;
  else if (c > 280 && c < 291) b = 6;
  else b = 0;
  if (b == old_b) {
   return 0;
   old_b = b;
  } else {
    return b;
    old_b = b;              
    }                           
}

void loop () {
  while ((val = readButtons(5)) != 5) {
    if ((val == 1) || (val == 2) || (val == 3) || (val == 4)) {
      array[counter] = val;
      Serial.print("In  ");
      Serial.print(counter);                
      Serial.print(" saving ");            
      Serial.println(val);
      delay(200);
      counter++;
      if (counter == MAX) {
        counter = 0;
      } 
    }
  }

  temp = counter;
  counter = 0;

  for (i = 0; i < temp; i++) {
    if (array[i] % 2 == 0) {
      L1 = 2;
      L2 = array[i] / 3 + 3; 
    } else {
      L2 = 5;
      L1 = array[i] % 3 + 3;    
      }

    if (readButtons(5) != 5) {
     digitalWrite (L1, HIGH);
     if (readButtons(5) != 5) {
      digitalWrite (L2, HIGH);
      delay(1000);
      digitalWrite (L1, LOW);
      digitalWrite (L2, LOW);
      if (readButtons(5) == 5) {
        i = temp;
      }
     } else {
       digitalWrite (L1, LOW);
       i = temp; 
     }
    }

  }
}

Así que todavía tengo una función que detecta si un botón fue presionado. Antes de eso, he determinado en qué rango están los valores de cierto botón. En el while () {...} mientras el 5º botón no está pulsado, Arduino está "buscando" si alguno de los cuatro primeros botones fue pulsado. Si lo fue lo almacena en un array y si no sigue "buscando". Cuando el 5º botón es presionado, frenamos y almacenamos el último lugar conocido en el array en el que se almacenó el valor y ponemos el contador de lugares a cero para que al comenzar de nuevo, Arduino almacene los valores en el primer lugar del array. Luego en base a lo almacenado determino que pin/LED se encenderá. Si en cualquier momento durante el parpadeo de los LEDs se vuelve a pulsar el quinto botón, Arduino detiene el parpadeo y vuelve a esperar las pulsaciones de los cuatro primeros botones. Así es como se supone que funciona en teoría. En la práctica todavía no consigo que deje de parpadear cada vez que se vuelve a pulsar el 5º botón. Tengo que pulsarlo varias veces, a veces dos o incluso más. No creo que usar interrupciones ayude, ya que no sé cómo podría usarlas en mi problema.

3voto

Ricardo Puntos 3575

¿Estás seguro de que necesitas salir en cualquier momento donde esté el puntero de ejecución? Normalmente, podría simplemente comprobar la pulsación del botón al final de la while y for bucles y llamar a return cuando se pulsa.

A veces pensamos que nuestro programa tiene que hacer algo y salir de la ejecución, pero al examinarlo detenidamente, llegamos a la conclusión de que puede terminar una interación de bucle y luego salir.

¿Podría decirnos qué se hace dentro de los bucles, para que podamos asegurarnos de lo que se necesita?

Editar: Como sospechaba, el problema de tu programa es que tus intervalos de retardo son demasiado largos, por ejemplo delay(1000) y delay(500) y no se puede comprobar la pulsación de botones mientras el programa está en espera.

Para solucionarlo, cree la siguiente función, que sustituirá sus llamadas a la demora:

// waits for the specified miliseconds 
// or return (almost) immediately if button is pressed
// return value indicates whether button was pressed or not
boolean waitOrButtonPressed(int miliseconds) {
  for (int i = 0; i < miliseconds / 10; i++) {
    if (readButtons(5)) == 5)
      return true;
    delay(10);
  }
  return false;
}

Entonces, dentro de su for sustituya las llamadas a delay(1000) por el siguiente código:

if (waitOrButtonPressed(1000)) return;

La función que he creado hará que tu programa espere casi como delay() , pero volverá true si se ha pulsado un botón durante ese tiempo. Si eso ocurre, el if la declaración anterior saldrá loop() que será llamado de nuevo por el código generado por Arduino.

Recuerde mantener los milisegundos de espera cuando reemplace sus llamadas a delay() para mantener el comportamiento de espera de su programa sin cambios.

Edición 2: Divagaciones

Casos como este me recuerdan a la película Tron en la que el protagonista se ve arrastrado a un ordenador en el que el tiempo pasa mucho más despacio que en la vida real. Así que, como en la película, 1000 milisegundos (1s) es MUCHO TIEMPO para el MCU. Puedes hacer mucho más que esperar en ese tiempo. Intenta romper las largas esperas y haz cosas útiles con los ciclos de tu MCU.

Además, aprende a usar las interrupciones, como otros mencionaron en sus comentarios y respuestas. Es sólo otra forma (un poco más complicada) de hacer cosas mientras esperas. En tu caso, las interrupciones podrían servir para detectar la pulsación del botón sin necesidad de comprobarlo cada vez en todas partes. Aquí tienes un lugar para empezar a aprender sobre las interrupciones con Arduino .

2voto

alexan_e Puntos 8256

Un método que se puede utilizar y que tiene el efecto de reiniciar la mcu (no estoy seguro si es el efecto que buscas) es utilizar una interrupción externa para el botón y dentro de la interrupción habilitar el watchdog con un pequeño timeout y dejar que expire y reinicie la mcu.

0voto

FredB Puntos 496

Por ello, C tiene el ir a declaración; para mover adelante de muchos bucles anidados.

La mayoría de la gente te dirá que no lo uses, y es probable que puedas evitarlo, pero sin duda es una solución a tu problema.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X