Electronic – How to exit from the if statemet which is inside for loop and go back to the void loop in Arduino

cprogramming

My code:

#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);
  }

 } 
}

So I have buttons connected like this, except I have them 5. When one of the first four is pressed sketch stores 1,2,3 or 4 to denote which buttons was pressed and stores it in integer array. When the fifth (the "GO" button) button is pressed while loop ends and starts the for loop which according to the buttons pressed blinks LEDs. I want to make that while Arduino is blinking LEDs , that is while for loop is being executed, if at any time the fifth "GO" buttons is pressed it should stop blinking LEDs and start program from the beginning ( void loop { … } ) that is again wait for the presses of first four buttons.


I managed to make this:

#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; 
     }
    }

  }
}

So I still have a function which detects if a button was pressed. Prior to that, I have determined in which range are values for certain button. In the while () {...} loop, while the 5th button isn't pressed, Arduino is "looking" if any of first four buttons was pressed. If it was store it in an array and if not keep "looking". When 5th button is pressed, we brake out and store last known place in array in which value was stored and set the place counter to zero so when starting again, Arduino stores values in the first place of array. Then based on that what is stored I determine which pin/LED will light up. If at any time during blinking LEDs 5th button is pressed again, Arduino stops the blinking and again waits for the presses from first four buttons. That is how it is supposed to work in theory. In practice I still can't get it to stop blinking every time 5th button is pressed again. I have to press it multiple times, sometimes two or sometimes even more times. I don't think using interrupts will help, since I don't know how I could use them in my problem.

Best Answer

Are you sure you need to exit at ANY time wherever the execution pointer is? Normally, you could just check the button press at the end of the while and for loops and call return when it is pressed.

Sometimes we think our program has to do something and break out of execution, but upon careful examination, we conclude that it can finish one loop interation and then quit.

Could you tell us what's done inside the loops, so we can make sure what's needed?

Edit: As I suspected, the problem with your program is that your delay intervals are too long, e.g. delay(1000) and delay(500), and you can't check for button presses while the program is waiting.

To fix that, create the following function, that will replace your calls to delay:

// 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;
}

Then, inside your for loop, replace your calls to delay(1000) by the following code:

if (waitOrButtonPressed(1000)) return;

The function I created will make your program wait almost like delay(), but will return true if a button was pressed during that time. If that happens, the if statement above will exit loop() which will be called again by the Arduino generated code.

Remember to keep the miliseconds to wait when you replace your calls to delay() to keep your program waiting behavior unchanged.

Edit 2: Ramblings

Cases like this remind me of the movie Tron, in which the main character is dragged into a computer, where time passes much slowlier than in real life. So, like in the movie, 1000 miliseconds (1s) is a LOT OF TIME for the MCU. You can do a whole lot more than waiting in that time. Try and break up the long Waits and do useful stuff with your MCU cycles.

Also, learn how to use interrupts, like others mentioned in their comments and answers. It's just another (a bit more complicated) way of doing stuff while you wait. In your case, interrupts could be use to detect the button press without the need to check it everytime everywhere. Here's a place to start learning about interrupts with Arduino.