Getting out of a Loop on a button press

Hello, searched all over for this cant find anything I can really tailor to my project.

Basically, I have a single button which controls about 8 LEDs.

I want the controls to be> Start with all LEDs off->push button Leds flash-> push button LEDs steady on> push button back to off.

I cant seem to figure out how to program the button to break the flashing function and move on to the steadyOn function. I have tested all the functions independently and there code is fine.

void loop()
{
  buttonState = digitalRead(switchPin);
  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == LOW) {
      buttonPushCounter++;
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter); 

      delay(20);     // delay for button debouncing (works good enough)
            if (buttonPushCounter == 0){
                  Serial.println("Light Setting 1 (off)");
                  Serial.println(buttonPushCounter);
                  switchOff();
              } 
            if (buttonPushCounter == 1){              
                  Serial.println("Light Setting 2");
                  Serial.println(buttonPushCounter);
                  wigWag(); //getting stuck in the loop
            } 
            if (buttonPushCounter == 2){
                  Serial.println("Light Setting 3");
                  Serial.println(buttonPushCounter);
                  steadyOn();
            }   
    }         
   
  }
  if (buttonPushCounter >=3) {
      buttonPushCounter = 0;
     Serial.println(buttonPushCounter);
 }  
   lastButtonState = buttonState;
}

Show all of your code. Is your wigwag code checking the button between blinks or are you using delay()?

Yeah that's my suspicion as well - the functions you're calling probably aren't exiting. This has to be the case because you aren't calling anything repeatedly that works the LEDs. Every time through the loop, whether the button state changed or not doesn't matter - you have to update the LEDs every time. If you have delays in your functions, this won't work. You need to update the LEDs and get out, letting Arduino run the loop again. You need to be using the "BlinkWithoutDelay" state management technique.

The video explains why we need to do this and how to do it... https://www.youtube.com/watch?v=3VZgaJBrZD8

Ok heres all of it, i didnt think id need to post all of it/

I know the wigwag function could probably be a loop but I just didnt get around to condensing it.

This is the first time Ive tried messing with shift registers.

int datapin = 2;  //shift register data in
int clockpin = 3; //clock pin for shfit register
int latchpin = 4; //patch pic for switch register
int switchPin = 7; //pin for button
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

byte data = 0; //needed to start shift register at 0

void setup()
{
  // Setting the Micro Processor Pins to be used

  pinMode(datapin, OUTPUT);
  pinMode(clockpin, OUTPUT);  
  pinMode(latchpin, OUTPUT); 
  pinMode( switchPin, INPUT_PULLUP);
  Serial.begin(9600); //use serial monitor for button debugging
  switchOff();  // run the all lights off function first
}

void loop()
{
  buttonState = digitalRead(switchPin);
  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == LOW) {
      // if the current state is LOW then the button
      // went from off to on:
            buttonPushCounter++;
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter); 

      delay(20);     // delay for button deboucning (ghost hits)
            if (buttonPushCounter == 0){
                  Serial.println("Light Setting 1 (off)");
                  Serial.println(buttonPushCounter);
                  switchOff();
              } 
            if (buttonPushCounter == 1){              
                  Serial.println("Light Setting 2");
                  Serial.println(buttonPushCounter);
                  wigWag();
                    
                  //getting stuck in the loop
            } 
            if (buttonPushCounter == 2){
                  Serial.println("Light Setting 3");
                  Serial.println(buttonPushCounter);
                  steadyOn();
            }   
    }         
   
  }
  if (buttonPushCounter >=3) {
      buttonPushCounter = 0;
     Serial.println(buttonPushCounter);
 }  
   lastButtonState = buttonState;
}


void shiftWrite(int desiredPin, boolean desiredState)
{
//    "desiredPin" is the shift register output pin
//    you want to affect (0-7)
//    "desiredState" is whether you want that output
//    to be HIGH or LOW
  bitWrite(data,desiredPin,desiredState);
  
  // send that data to the shift register.
  
  shiftOut(datapin, clockpin, MSBFIRST, data);
  digitalWrite(latchpin, HIGH);
  digitalWrite(latchpin, LOW);
}


void switchOff()
{
  int index;
  int delayTime = 0;
  
  for(index = 0; index <= 7; index ++)
    {
      shiftWrite(index, LOW);
      delay(delayTime);
    }
}

//Cruise Lights
void steadyOn()
{
  int index;
  int delayTime = 0; // Time (milliseconds) to pause between LEDs
                       // Make this smaller for faster switching
  
  for(index = 0; index <= 7; index++)
  {
    shiftWrite(index, HIGH);	// turn LED on
  }
}

void wigWag()
{
  int index;
  int delayTime = 50; // Time (milliseconds) to pause between LEDs
                       // Make this smaller for faster switching
  
  
  for(index = 0; index <= 7; index++)
  {
    
    shiftWrite(index, HIGH); //First 4 LEDs on Next 4 Off
   shiftWrite(index+1, HIGH);
   shiftWrite(index+2, HIGH); 
    shiftWrite(index+3, HIGH); 
    shiftWrite(index+4, LOW);
   shiftWrite(index+5, LOW);
   shiftWrite(index+6, LOW); 
    shiftWrite(index+7, LOW); 
    delay(200);
    shiftWrite(index, LOW);  //alternate of above
   shiftWrite(index+1, LOW);
   shiftWrite(index+2, LOW); 
    shiftWrite(index+3, LOW); 
    shiftWrite(index+4, HIGH);
   shiftWrite(index+5, HIGH);
   shiftWrite(index+6, HIGH); 
    shiftWrite(index+7, HIGH);
    delay(200);
    index = -1;    //need to set index to -1 because index = 0 is actually an LED
  }  
}

I think you need to re-write the function wigwag() so it just calls shiftwrite() once in every iteration. Use a counter to ensure it calls each of them in turn. You won't notice any difference but the button will be read far more often because loop() will repeat much more quickly.

And replace the calls to delay() with the technique in Blink Without Delay. The demo several things at a time is an extended example of the technique and should give you the idea.

...R

Thanks I'll try and give that a shot!

jasmine2501: Yeah that's my suspicion as well - the functions you're calling probably aren't exiting. This has to be the case because you aren't calling anything repeatedly that works the LEDs. Every time through the loop, whether the button state changed or not doesn't matter - you have to update the LEDs every time. If you have delays in your functions, this won't work. You need to update the LEDs and get out, letting Arduino run the loop again. You need to be using the "BlinkWithoutDelay" state management technique.

The video explains why we need to do this and how to do it... https://www.youtube.com/watch?v=3VZgaJBrZD8

Ok, I think I understand the concept on why you want to change states vs. just using delay.

I figured I was trapped in the loop some how. Now I see why

You say I'll need to have the wigwag() function checking the for button. Will this occur now because I having the function execute based on intervals or will i still need some type of code to check for button press?

will i still need some type of code to check for button press?

Well it won't check anything if you don't write the code to do the checking so yes.

right, I understand that but I mean in addition to what I have? I'm pretty new to this (that sentence must get old). I'm not really sure what that other code would be

Nhoc6131: need to have the wigwag() function checking the for button

Just to clarify, you should not read the button in wigwag() - there should just be one place for reading the button.

...R

Ok so I thought making the wigWag function with the shiftWrite into a loop would be fairly easy. I was always terrible at arrays in school. Mix that with shift registers and Im really stuck. So I need to do a for Loop with an if else statement in it right?

Got part of it figured out. now my text hurdle is if have some lights flashing as a function. and then other lights flashing as a different function…

how do i do

if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

the if ledState == low portion if im not using a variable but a function instead?

Just replace the assignment with a function call.

You have now got advice from a few different people and while it is not actually conflicting they don't all fit together seamlessly. I think it would be a good idea now to rewrite and post a complete sketch drawing from what you have learned. Discussing your options in small pieces is likely to lead to confusion when you try to bring it all together.

If very consistent timing is important this

previousMillis += interval;

would be better than

previousMillis = currentMillis;

Long explanation in this Thread.

...R

Nhoc6131:
Got part of it figured out. now my text hurdle is if have some lights flashing as a function. and then other lights flashing as a different function…

how do i do

if(currentMillis - previousMillis > interval) {

// save the last time you blinked the LED
    previousMillis = currentMillis;

// if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;




the if ledState == low portion if im not using a variable but a function instead?

to toggle a LED without a variable you can use this:

if(currentMillis - previousMillis > interval) 
{
  previousMillis = currentMillis;   
  // if the LED is off turn it on and vice-versa:
  digitalWrite(yourLed, !digitalRead(yourLed);  // toggles without a variable by reading the yourLed pin, and writing the opposite of its state ( !state )
}

is that what you wanted?

Thanks for the advice everyone. I think some are right and it may be wise to just sit down and rewrite then to try and piece things together. I sincerely do appreciate the help this far! Thanks!!!

Bingo got it. I used everyones suggestions on cleaning up the code.

As far as the button calling... It came down to having an unbalanced If statement....

I was checking on what do when the button state changes but not what to do if the button state remained the same! duh! lack of sleep!