1

I have a very basic circuit setup:

  • A button connected to pin 2
  • An LED connected to pin 9

Desired Functionality:

When the button is pressed, the user can toggle through 4 LED patterns.

The Problem:

Once the first fade pattern begins, the user has to wait until it has finished running before the button can toggle to the next pattern. What I want is that the button push will move to pattern 2, even if pattern 1 has already started.

Attempted Solutions:

I've tried to insert a while function in a couple of places i.e while buttonstate =lastbuttonstate, but that doesn't seem to work.

Here's the code: (I realize all the fadeloops are the same right now, they will different in the working model)

//PROBLEM: The fade function has to complete a full loop before allowing toggle to next one


const int  buttonPin = 2;    // the pin that the pushbutton is attached to
const int ledPin = 9;       // the pin that the LED is attached to

// Variables will change:
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

int brightness = 0;    // how bright the LED is
int firstFadeAmount = 5;    // how many points to fade the LED by
int secondFadeAmount = 5;    // how many points to fade the LED by


void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  // initialize serial communication:
  Serial.begin(9600);
}


void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      buttonPushCounter++;
    } 
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  lastButtonState = buttonState;

  while (buttonPushCounter = lastButtonState) {
    if (buttonPushCounter == 1 && buttonState == HIGH) {
      fadeLoop1(); 
      delay(50);//JP Edit 
    } 

    else if (buttonPushCounter == 2 && buttonState == HIGH) {
      fadeLoop2(); 
      delay(50); 
    } 

    else if (buttonPushCounter == 3 && buttonState == HIGH) {
      fadeLoop3(); 
      delay(50); 
    } 

    else if (buttonPushCounter == 4 && buttonState == HIGH) {
      fadeLoop4(); 
      delay(50); 
    } 

  }
  if (buttonPushCounter == 4) {  //Resets back to zero after 4 presses
     buttonPushCounter = 0;
  }

}


void fadeLoop1()  
{
  for (int i = 0; i < 100; i++) {  //Set the length of the first fading cycle 
    analogWrite(ledPin, brightness);
    brightness = brightness + firstFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      delay(1000);                  //Sets the hold at the top and bottom of the cycle 
      firstFadeAmount = -firstFadeAmount;
    }
    delay(100);
  }
  for (int i = 0; i < 100; i++) {  //Set the length of second fading cycle
    analogWrite(ledPin, brightness);
    brightness = brightness + secondFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      secondFadeAmount = -secondFadeAmount;
    }
    delay(30);
  }

  digitalWrite(ledPin, LOW);
}


void fadeLoop2()  
{
  for (int i = 0; i < 100; i++) {  //Set the length of the first fading cycle 
    analogWrite(ledPin, brightness);
    brightness = brightness + firstFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      delay(1000);                  //Sets the hold at the top and bottom of the cycle 
      firstFadeAmount = -firstFadeAmount;
    }
    delay(100);
  }
  for (int i = 0; i < 100; i++) {  //Set the length of second fading cycle
    analogWrite(ledPin, brightness);
    brightness = brightness + secondFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      secondFadeAmount = -secondFadeAmount;
    }
    delay(30);
  }

  digitalWrite(ledPin, LOW);
}


void fadeLoop3()  
{
  for (int i = 0; i < 100; i++) {  //Set the length of the first fading cycle 
    analogWrite(ledPin, brightness);
    brightness = brightness + firstFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      delay(1000);                  //Sets the hold at the top and bottom of the cycle 
      firstFadeAmount = -firstFadeAmount;
    }
    delay(100);
  }
  for (int i = 0; i < 100; i++) {  //Set the length of second fading cycle
    analogWrite(ledPin, brightness);
    brightness = brightness + secondFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      secondFadeAmount = -secondFadeAmount;
    }
    delay(30);
  }

  digitalWrite(ledPin, LOW);
}


void fadeLoop4()  
{
  for (int i = 0; i < 100; i++) {  //Set the length of the first fading cycle 
    analogWrite(ledPin, brightness);
    brightness = brightness + firstFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      delay(1000);                  //Sets the hold at the top and bottom of the cycle 
      firstFadeAmount = -firstFadeAmount;
    }
    delay(100);
  }
  for (int i = 0; i < 100; i++) {  //Set the length of second fading cycle
    analogWrite(ledPin, brightness);
    brightness = brightness + secondFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      secondFadeAmount = -secondFadeAmount;
    }
    delay(30);
  }

  digitalWrite(ledPin, LOW);
}
5
  • You might want to expand on the description of the circuit. The button is connected to pin 2 and ???. Sep 24, 2018 at 12:10
  • Thanks. The button is connected to pin 2 only and is only there as a counter. Sep 24, 2018 at 12:19
  • The button is also connected to GND (or VCC) with a resistor? You might have connected a open circuit and therefore have erratic input values. Sep 24, 2018 at 16:04
  • The issue is that the fadeLoopN functions occupy the CPU. There are two approaches to solving this: (1) rewrite the fade patterns in a way that they are performed using timer interrupts; or (2) create an interrupt for the button, and set some global flag in the interrupt service routine, then check for this flag in every loop in your fade functions. The first approach is preferred, but the second approach is less invasive.
    – ex-punctis
    Sep 24, 2018 at 18:40
  • all four fade patterns are the same, so you have no way of knowing if you selected a different pattern
    – jsotola
    Sep 27, 2018 at 2:36

2 Answers 2

1

Short Answer:

Switch from using a loop for the entire animation and convert to only tracking what needs to happen at a single point in time.

Long Answer:

The 'while' approach is a good way to test out an individual pattern but for the behavior you describe, you need to limit the use of loops inside of the 'loop()' function.

Essentially, if you use a while to control the entire pattern, as you encountered, you have to wait for the while to exit before the rest of the code can check for a button press.

Here is how I've done the same thing. I don't have the code handy so I'll have to edit the answer later. The basic form is something like this:

int pattern = 0;
int brightness = 0;
int maxBrightness = 100;

setup() 
{ 
// your setup code here 
}


loop()
{
   if (pattern = 0)
   {
      //increment brightness      
      //call code to set the LED to the current brightness
      if (brightness => maxBrightness)
      {
          brightness = 0;
      }
   }
   checkforbuttonpress();
}

What you notice is I didn't use a for / while loop to do my animation, because the already existing loop() function already does that for me. All I have to do is track what needs to happen right now, with variables for which pattern and the current brightness for the code to interact with the hardware. Remember to handle the repetition manually (maxBrightness in this example) and now when the button is pressed, you can change the pattern anywhere because there is no secondary loop to wait for.

0

Rewrite the fade loops so they return immediately and instead use global state to adjust the LEDs and millis()-timestamp to set the timing.

You can use blinkwithoutdelay as inspiration.

1
  • Thanks. Please explain, what does it mean to "return immediately" and how do I include it in the code? I am reading about 'miilis' now, it looks like it's the way to go. Sep 24, 2018 at 11:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.