exiting a loop on button press

Hello,

I have a sketch working as it should but I want to have a button (active high on pin 3) to break the loop cycle. This should be pretty straight forward and I think I am close but yet no cigar. I have tried while, do while and if statement tests. I think the if statement is the key here as it tests the button press "rstButtonState" within the main loop but for some reason it doesn't want to drop out. I have a function I have called bailout which simply makes the counter "top out" to its full value so when it re-enters the loop it should fall through as it shoould test true.

Any insights appreciated.

Thanks.

//The 1st array contains five pin designators (replicated twice) and the 2nd array is used to avoid replications of the same element

const int actButton = 2;
const int rstButton = 3;
const int readyLed  = 9;
const int ledPinArray [] = {4, 4, 5, 5, 6, 6, 7, 7, 8, 8};
int actButtonState = 0;
int rstButtonState = 0;
bool arrayMirror [10];  
int bp_counter = 0;

void setup(){

  Serial.begin (9600);
  randomSeed (analogRead(0));
  pinMode (readyLed, OUTPUT);
  pinMode (4, OUTPUT);
  pinMode (5, OUTPUT);
  pinMode (6, OUTPUT);
  pinMode (7, OUTPUT);
  pinMode (8, OUTPUT);
  pinMode (actButton, INPUT);
  pinMode (rstButton, INPUT);

// Function which sets each byte (array length is 10) pointed to by the arrayMirror to a value of zero. The value is then returned
    memset(arrayMirror, 0, 10);
}

void loop(){
// Check the state of the push button & run the routine if pressed   
         
           if (bp_counter == 0){
             digitalWrite(readyLed, HIGH);
           }
             else{
             digitalWrite(readyLed, LOW);
             }
         
             actButtonState = digitalRead(actButton);
             [color=red]rstButtonState = digitalRead(rstButton);[/color]
             
             if (actButtonState == HIGH){
               digitalWrite (readyLed, LOW);
               beacon_select();
               bp_counter ++;                
             
                [color=red] if (rstButtonState == HIGH){
                 bailout();
                 }[/color]
                 
                 if(bp_counter == 10)
                 {

// Start over again by clearing the elements in the array
                 memset(arrayMirror, 0, 10);
                 bp_counter = 0;
                 }
             }
}         
             
// Routine for choosing a random LED and check for duplications
void beacon_select(){            
  int r = random (0,10);               
  while(arrayMirror [r])
        r = random (0,10);
  int beacon = ledPinArray [r];
  arrayMirror [r] = true;  
  digitalWrite (beacon, HIGH);              
  delay (500);
  digitalWrite (beacon, LOW);
}
[color=red]// ----- Check if the reset button has been pressed -----
void bailout(){
  bp_counter == 10;
}[/color]

Where is the loop you want to drop out of?

Also this function does nothing:

void bailout(){
  bp_counter == 10;
}

And what are these random tags surrounding your code?

[color=red]rstButtonState = digitalRead(rstButton);[/color]

Hi Tammytam,

I realise that although I am not in a for or while loop. The program is calling a function routine called "beacon_select" which does something then returns to the top, checks for next actButtonState condition, increments the counter and repeats ten times. This is essentially my loop.

So I am testing to see if the rstButtonState is 10. If it is then the condition is met and it can drop through to clear the arrayMirror and start over.

The routine "bailout" was just supposed to set the bp_counter to 10 when the button on pin 3 was pressed and would thus comply with the if statement condition.

The things were an attempt to highlight the code in question as red font in colour but this doesn't seem to have worked.

Hope this helps clear the confusion.

Ok I'll take another read through, in the meantime solve this situation with that function. When I said it did nothing, I was being quite literal, it does nothing.

You are using an equality operator == instead of an assignment operator, change it to:

void bailout()
{
  bp_counter = 10;
}

Edit: Looks fine other than the above.

The usual way to exit a function is return; and loop() is just a regular function.

Inside a WHILE of FOR loop you can use continue; to skip the rest of the code and continue with the next iteration.

...R

tammytam: Ok I'll take another read through, in the meantime solve this situation with that function. When I said it did nothing, I was being quite literal, it does nothing.

You are using an equality operator == instead of an assignment operator, change it to:

void bailout()
{
  bp_counter = 10;
}

Edit: Looks fine other than the above.

Yes well I tried = too. But didn't have luck with that either.

The reason I created a Function is that from what I've read about C++ it seems to have been designed for functions. Although I agree with you that when I did this I thought it seemed a bit pointless.

I suppose I have just run out of ideas and need a fresh approach to what I am sure is a simple solution.

I appreciate your help again.

Robin2: The usual way to exit a function is return; and loop() is just a regular function.

Inside a WHILE of FOR loop you can use continue; to skip the rest of the code and continue with the next iteration.

...R

Cheers for the advice.

I did have a play with Return but didn't have much success either. Perhaps I will persevere with this some more. I think part of my problem is really getting to grips with how these {} work and where the program re-enters once it's done a task. I come from the good old days of Basic when everything was solved with IF, THEN and GOTO statements.

P.S. It's interesting that you got the blue font to work. When I tried it with red it didn't work, hence why it is in my code as text.

Seems to work now ;-)

the {} just define a block of code, so using an if statement:

if( i == 0 )
{
  // there can be many lines of code within this block
  // All lines in this block are executed if the statement in the 'if' is true
}

Work very much like your IF THEN ENDIF in your BASIC, ENDIF marking the end of the block.

Btw I don't think the delay( 500 ) is doing you any favours for detecting your keypress.

Walltree: P.S. It's interesting that you got the blue font to work. When I tried it with red it didn't work, hence why it is in my code as text.

You cannot colour text that is within code tags. If you want to draw attention to a line use a comment such as //=====Problem here===

Using functions is a great way to keep the details away from the logic so that you can see the overall picture without being confused by details. Have a look at planning and implementing a program

...R

Robin2: You cannot colour text that is within code tags. If you want to draw attention to a line use a comment such as //=====Problem here===

Using functions is a great way to keep the details away from the logic so that you can see the overall picture without being confused by details. Have a look at planning and implementing a program

...R

Yes thanks Robin2. I kind of figured that was the case with the comments in the code window. Hence my cheeky red text bit.

I have read your planning and implementing a program once b4 and it is very detailed and very well structured.

tammytam: the {} just define a block of code, so using an if statement:

if( i == 0 )
{
  // there can be many lines of code within this block
  // All lines in this block are executed if the statement in the 'if' is true
}

Work very much like your IF THEN ENDIF in your BASIC, ENDIF marking the end of the block.

Btw I don't think the delay( 500 ) is doing you any favours for detecting your keypress.

Thanks. I get that and think part of this (my) confusion might be when one uses too many nested IF statements which should be avoided.

It's a pitty that Arduino 1.6.4 IDE compiler doesn't have a "step-through" debugger to check code blocks for correct operation. This would help with the learning process. The only way to do this is to comment out some lines of code and see how it affects the operation.

P.S. My delay was actually 2000 but I chose 500 as testing was becomming tiresome but I can set it back to 2000. Do you think an interrupt might be a better approach here?

Nested IFs shouldnt really be avoided, in fact they are almost un-avoidable.

Easiest way to debug on the arduino is litter your code with serial prints.

And no, don't make the delay longer, take it out and replace it with non-blocking code:

// global
unsigned long previous_millis = 0;

// wherever you need to trigger the delay ...
previous_millis = millis();

// wherever you need to wait for the delay ...
if(millis() - previous_millis > 500) 
{
    // do stuff
}

That ensures your program keeps running and checks for input instead of waiting.

tammytam: Nested IFs shouldnt really be avoided, in fact they are almost un-avoidable.

Easiest way to debug on the arduino is litter your code with serial prints.

And no, don't make the delay longer, take it out and replace it with non-blocking code:

// global
unsigned long previous_millis = 0;

// wherever you need to trigger the delay ... previous_millis = millis();

// wherever you need to wait for the delay ... if(millis() - previous_millis > 500) { // do stuff }




That ensures your program keeps running and checks for input instead of waiting.

I have just discovered that you were right about bp_counter being a lone = sign.

I also realise now that my code as it stands will never work as the IF statement (in question) never gets a chance to execute on it's own unless the rstButton is pressed at the same time (during the cycle) as the actButton is pressed.

I think it needs more thought to find an elegant solution and for what it's worth here is the code so far.

pinMode (actButton, INPUT_PULLUP);
  pinMode (rstButton, INPUT_PULLUP);

// ----- Function which sets each byte (array length is 10) pointed to by the arrayMirror to a value of zero. The value is then returned -----
    memset(arrayMirror, 0, 10);
}

void loop(){
//----- Check the state of the push button & run the routine if pressed -----   
         
           if (bp_counter == 0){
             digitalWrite(readyLed, HIGH);
           }
           else{
             digitalWrite(readyLed, LOW);
           }
         
             actButtonState = digitalRead(actButton);
             rstButtonState = digitalRead(rstButton);
             
             if (actButtonState == LOW){
               digitalWrite (readyLed, LOW);
               beacon_select();
               bp_counter ++;                
             
                   if (rstButtonState == LOW){ // ***** HERE IS THE PROBLEM CODE *****
                     bp_counter = 10;
                   }
                 
                   if(bp_counter == 10){
                     memset(arrayMirror, 0, 10); // start over again by clearing the elements in the array
                     bp_counter = 0;
                   }
             }
}         

// ----- Routine for choosing a random LED and check for duplications -----
void beacon_select(){            
  int r = random (0,10);               
  while(arrayMirror [r])
        r = random (0,10);
  int beacon = ledPinArray [r];
  arrayMirror [r] = true;  
  digitalWrite (beacon, HIGH);              
  delay (500);
  digitalWrite (beacon, LOW);
}

Thanks