Button mode not functioning as expected

Hi guys,
I am building a simply fish tank light that uses two led color strings. I have red and blue LEDs. Currently I have code that can set the modes to be solid red, solid blue, solid red+blue (violet), or fade in brightness from red to blue to violet and back to red. I am attempting to setup a button that will switch between these modes however my code does not appear to be working properly. Below is my code:

/*
 Fade red LED's up then down
 Fade blue LED's up then down
 Fade red and blue LED's up then down
 repeat
 */
//unchangeing variables
const int ledR = 9;           // the pin that the red LED is attached to
const int ledB = 10;          // the pin that the blue LED is attached to
const int buttonPin = 2;         // the pin that the button is attached to
const int ledPin = 13;  // pin for the onboard LED

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

// the setup routine runs once when you press reset:
void setup()  { 
  Serial.begin(9600);
  // declare pin modes
  pinMode(ledR, OUTPUT);
  pinMode(ledB, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
} 

// Initial Loop for RED LED
void loop()  { 
 // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // 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 += 1;
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
    } 
    else {
      // if the current state is HIGH then the button
      // went from on to off:
      Serial.println("off"); 
    }
  }
 
   
  // save the current state as the last state, 
  //for next time through the loop
  lastButtonState = buttonState;

  
  if (buttonPushCounter == 0){
      analogWrite(ledR, 255);
    }
  else if (buttonPushCounter == 1) {
      analogWrite(ledB, 255);
    }
  else if (buttonPushCounter == 2) {
      analogWrite(ledR, 255);  
      analogWrite(ledB, 255);
    }
  else if (buttonPushCounter == 3) {
  cycle(ledR);
  cycle(ledB);
  cycle(ledR, ledB);
    }
  else 
    buttonPushCounter = 0;  
}

void cycle(int ledColor1){

    for (int u=0; u <= 255; u++){
          analogWrite(ledColor1, u);
          delay(10);
       } 
      
    for (int d=255; d >= 0; d--){
          analogWrite(ledColor1, d);
          delay(10);
       } 
}

void cycle(int ledColor1, int ledColor2){

    for (int u=0; u <= 255; u++){
          analogWrite(ledColor1, u);
          analogWrite(ledColor2, u);
          delay(10);
       } 
      
    for (int d=255; d >= 0; d--){
          analogWrite(ledColor1, d);
          analogWrite(ledColor2, d);
          delay(10);
   } 
}

The following is the serial output:
off
on
number of button pushes: 1
off
on
number of button pushes: 2
off
on
number of button pushes: 3
off

If I push again it does not reset back to 0 as I would expect. Secondly, after I push the button once it seems to immediately change to mode 2 instead of mode 1 (from 0). Pushing again after that does indeed only increment by 1 and moves on to mode 3. Can't wrap my head around why this is not working... I am far from being even someone proficient in C languages though :frowning: Working to change that!

tri_color_led_fade_v1JN_Button_ino.ino (2.53 KB)

jeyton:
If I push again it does not reset back to 0 as I would expect.

Because it's most likely stuck in one of the delay() calls you make in the cycle functions, and it's not reading switch state information when it's twiddling its thumbs.

Secondly, after I push the button once it seems to immediately change to mode 2 instead of mode 1 (from 0).

Sounds like a bouncy switch.

Arrch:

jeyton:
If I push again it does not reset back to 0 as I would expect.

Because it's most likely stuck in one of the delay() calls you make in the cycle functions, and it's not reading switch state information when it's twiddling its thumbs.

Secondly, after I push the button once it seems to immediately change to mode 2 instead of mode 1 (from 0).

Sounds like a bouncy switch.

Hmm a 10ms delay would cause that? I swapped the switch just in case but the behavior is still the same. Here is a video of it in action. https://www.youtube.com/watch?v=DgOsvAsvCdA

Edit* I guess it would actually be a 2550ms delay per color. meaning I'd have to catch it at exactly the right time when the violet fade function ends and the red fade function starts, which is likely impossible due to how quickly the arduino is going to restart the loop. Hmmm... I have no idea how to make this work.

jeyton:
Edit* I guess it would actually be a 2550ms delay per color.

2550 mS times 2 loops per function call times 3 function calls means 15 seconds per cycle.

jeyton:
meaning I'd have to catch it at exactly the right time when the violet fade function ends and the red fade function starts

You would have to push the switch down during one cycle, release it during the second, and wait for the cycle to finish.

jeyton:
I have no idea how to make this work.

It isn't trivial. It will require state machine, and liberal use of millis() to create non-blocking code that will properly adjust the fade values.

Ok, you're absolutely right this is due to the delay, but you knew that already :wink: I found the following and have placed it in my libraries: Under Construction

Reading through it I can understand how to fade one LED, or multiple LEDs but I'm not sure how to fade 1, then another, then multiple, then repeat back to 1.

This demo several things at a time might help to illustrate the use of millis() to control timing.

...R

I got it!!! With some help of C coding buddy of mine. It now works fully as intended, we set the delay down to 10ms and added checkbuttonstate function to run immediately after every delay. This basically means I would have to push the button during a 10ms delay window for it to fail, not likely to happen... I added potentiometer to controll the brightness as well for the static color modes. Here is the code:

/*
 Fade red LED's up then down
 Fade blue LED's up then down
 Fade red and blue LED's up then down
 repeat
 */
//unchangeing variables
const int ledR = 9;           // the pin that the red LED is attached to
const int ledB = 10;          // the pin that the blue LED is attached to
const int buttonPin = 2;         // the pin that the button is attached to
const int ledPin = 13;  // pin for the onboard LED
const int delayTime = 10;    //time between changing intensity of LED
const int potPin = 4;        // the analog pin that the potentiometer is connected 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 fadeLevel = 1;           // current brightness of LED
int fadeState = 1;          // determines if fadeLevel is increasing or decreasing
int cycleState = 0;          // catches the cycle state for the cycleR, cycleB, and cycleRB functions
int potValue = 0;          // the brightness variable to be set by the potentiometer
int brightness = 0;

 
// the setup routine runs once when you press reset:
void setup()  {
  Serial.begin(9600);
  // declare pin modes
  pinMode(ledR, OUTPUT);
  pinMode(ledB, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP); 
}
 
// Initial Loop
void loop()  {


 
  if (buttonPushCounter == 0){
      brightness = (analogRead(potPin) / 4);
      analogWrite(ledR, brightness);
      analogWrite(ledB, 0);
      checkButtonState();
    }
  else if (buttonPushCounter == 1) {
    brightness = (analogRead(potPin) / 4);
    analogWrite(ledR, 0);  
    analogWrite(ledB, brightness);
    checkButtonState();
    }
  else if (buttonPushCounter == 2) {
      brightness = (analogRead(potPin) / 4);
      analogWrite(ledR, brightness);  
      analogWrite(ledB, brightness);
      checkButtonState();
    }
  else if (buttonPushCounter == 3) {
      analogWrite(ledB, 0);
      cycleR(ledR); 

      analogWrite(ledR, 0);
      cycleB(ledB);

      analogWrite(ledR, 0);
      analogWrite(ledB, 0);
      cycleRB(ledR, ledB);
  }
  else if (buttonPushCounter == 4) {
      cycleBlend(ledR, ledB);
    }
  else
    buttonPushCounter = 0;  
}
 
void cycleR(int ledColor1){
  if (cycleState == 0) {
	  if (fadeLevel >= 255){
		fadeState = -1;
	  }
	  else if (fadeLevel <= 0){
		fadeState = 1;
                cycleState++;
	  }
	  
	  fadeLevel += fadeState;
	  

          analogWrite(ledColor1, fadeLevel);
          delay(delayTime);
	  checkButtonState();
  }
}

void cycleB(int ledColor1){
  if (cycleState == 1) {
	  if (fadeLevel >= 255){
		fadeState = -1;
	  }
	  else if (fadeLevel <= 0){
		fadeState = 1;
                cycleState++;
	  }
	  
	  fadeLevel += fadeState;
	  

          analogWrite(ledColor1, fadeLevel);
          delay(delayTime);
	  checkButtonState();
  }
}
 
void cycleRB(int ledColor1, int ledColor2){
  if (cycleState == 2) {  
          if (fadeLevel >= 255){
		fadeState = -1;
	  }
	  else if (fadeLevel <= 0){
		fadeState = 1;
                cycleState = 0;
	  }
	  
	  fadeLevel += fadeState;
	  
        
          analogWrite(ledColor1, fadeLevel);
	  analogWrite(ledColor2, fadeLevel);
          delay(delayTime);
	  checkButtonState();
  }
}

void cycleBlend(int ledColor1, int ledColor2){

	  if (fadeLevel >= 255){
		fadeState = -1;
	  }
	  else if (fadeLevel <= 0){
		fadeState = 1;
	  }
	  
	  fadeLevel += fadeState;
	  

          analogWrite(ledColor1, fadeLevel);
	  analogWrite(ledColor2, 255 - fadeLevel);
          delay(delayTime);
	  checkButtonState();
     
}


void checkButtonState(){
 // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);
 
  // 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 += 1;
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
    }
    else {
      // if the current state is HIGH then the button
      // went from on to off:
      Serial.println("off");
    }
  }
 
   
  // save the current state as the last state,
  //for next time through the loop
  lastButtonState = buttonState;
   }

Here is a video of it in action made especially for those here on the forum, thanks so much you guys!

jeyton:
I got it!!! With some help of C coding buddy of mine. It now works fully as intended, we set the delay down to 10ms and added checkbuttonstate function to run immediately after every delay.

This is too painful to contemplate.

...R

Robin2:

jeyton:
I got it!!! With some help of C coding buddy of mine. It now works fully as intended, we set the delay down to 10ms and added checkbuttonstate function to run immediately after every delay.

This is too painful to contemplate.

...R

Oh dear... That bad?