Colour cross-fading with buttons forward and reverse

Hi All

WHAT I AM TRYING TO DO: fade rgb with 2 buttons first button goes to next colour in sequence, second button does the same but in reverse order

WHAT THE CODE DOES IN ITS CURRENT FORM:
FADES RGB COLOURS WITH ONLY ONE BUTTON GOING TO NEXT COLOUR IN LOOP

Does anybody know how to add a second button to this code to fade colours in reverse to the first button??

any help appreciated
thanks

 // colour fader


//pin connections
int red = 3;
int green = 5;
int blue = 6;
int buttonPin = 7; //button on pin 7 triggers move to next colour
int buttonPin = 2, // button on pin 2 set but not working!!!

boolean currentState = LOW;//stroage for current button state
boolean lastState = LOW;//storage for last button state
int currentColor = red;//storage for current color

void setup(){
  pinMode(buttonPin, INPUT);//this time we will set the pin as INPUT
  pinMode(red, OUTPUT);
  pinMode(blue, OUTPUT);
  pinMode(green, OUTPUT);
  Serial.begin(9600);//initialize Serial connection
  digitalWrite(currentColor, HIGH);//initialize with currentColor on (full brightness)
}

void loop(){
  currentState = digitalRead(buttonPin);
  if (currentState == HIGH && lastState == LOW){//if button has just been pressed
    Serial.println("pressed");
    delay(1);//crude form of button debouncing

    int nextColor = getNextColor(currentColor);
    fader(currentColor, nextColor);
    currentColor = nextColor;

  }

  lastState = currentState;

}

int getNextColor(int color){//helper function that gives us the next color to fade to
  if (color == red) return green;
  if (color == green) return blue;
  if (color == blue) return red;
}

void fader(int color1, int color2){
    for (int brightness=0;brightness<256;brightness++){
        analogWrite(color1, 255-brightness);
        analogWrite(color2, brightness);
        delay(1);
    }
}

Did you write this code? Do you understand how it works?

Can you imagine a function like this one but called getPreviousColor instead?

int getNextColor(int color){//helper function that gives us the next color to fade to
  if (color == red) return green;
  if (color == green) return blue;
  if (color == blue) return red;
}
int buttonPin = 7; //button on pin 7 triggers move to next colour
int buttonPin = 2, // button on pin 2 set but not working!!!

Nonsense. You can't say that the code works (does what you want) or does not work when it won't even compile.

There is nothing magic about the name. Call the second variable fred, for all the intelligence that buttonPin conveys.

Please edit your post, select the code, and put it between [code][/code] tags.

You can do that by hitting the # button above the posting area.

Please do not cross-post. This wastes time and resources as people attempt to answer your question on multiple threads.

Threads merged.

  • Moderator

How to use this forum

perhaps you would find it easier with an array… something like this:

compiled but not tested

int colourPin[3] = {3, 5, 6};// red green blue
int buttonPin1 = 7;
int buttonPin2 = 2; 
byte lastState1;
byte lastState2;
int index = 0;
int lastIndex= 0;
//
void setup()
{
  Serial.begin(9600);
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
  for (int i = 0; i < 3; i++)
  {
    pinMode(colourPin[i], OUTPUT);
  }
 }
//
void loop()
{
  byte currentState1 = digitalRead(buttonPin1);
  if (currentState1 == HIGH && lastState1 == LOW)
  {
    Serial.println("pressed Up");
    index++;
    if (index > 2) index = 0; 
  }
  lastState1 = currentState1;

  byte currentState2 = digitalRead(buttonPin2);
  if (currentState2 == HIGH && lastState2 == LOW)//<<<<<<<<<<<<<
  {
    Serial.println("pressed Down");
    index--;
    if (index < 0) index = 2;
  }
  lastState2 = currentState2;
  
  if (index != lastIndex) moveLed();
  lastIndex = index;
}
//
void moveLed()
{
  for (int brightness=0; brightness <= 255; brightness++)
  {
      analogWrite(colourPin[index], brightness);//fade up index
      analogWrite(colourPin[lastIndex], 255-brightness);//fade down old pin
      delay(1);
  }
}

sorry im quite new to posting into this forum still learning, where do i edit my post ?

Delta G i didnt write this code, i copyied it and slightly edited it.

Thanks paulS for your code compiles okay but once upload, buttonPin2 doesn't work or even trigger the serial print, why would that be ?
button1 works just fine

thanks

Do you have it connected properly to pin2?

There was an error in my code, which I corrected above.

Thanks took a while but spotted the mistake code is working great. Was working with no internet connection so didn't see your corrected code !
Buttons are connected correctly using pull down resistor.

How would I go about adding blink without delay on two of the led pins ? Keeping third one as is, fading in and then out when buttons are pushed

you have to Fade Without Delay first... search for that...

even though you have a small delay, that for() loop is blocking

once you adjust your fade to a non-blocking version, you can blink blink blink all you want.

I still don’t quite understand how to implement that into the code, would I need to remove :

And create a fader for each pin ?

void fader(int color1, int color2){
    for (int brightness=0;brightness<256;brightness++){
        analogWrite(color1, 255-brightness);
        analogWrite(color2, brightness);
        delay(1);
    }
}

Take these two codes for instance. Let’s look at the first one, the blocking example:

DISCLAIMER: This code compiles but is untested. Sorry if I made any mistake.

int blinkLedPin = 6;
int fadeLedPin = 5;

void setup(){
  pinMode(blinkLedPin, OUTPUT);
  pinMode(fadeLedPin, OUTPUT);
}

void loop(){
  
  digitalWrite(blinkLedPin, HIGH);
  
  for(int i = 0; i < 255; i++){
    analogWrite(fadeLedPin, i);
  }
  
  digitalWrite(blinkLedPin, LOW);
  
  for(int i = 255; i>0; i--){
    analogWrite(fadeLedPin, i);
  }
}

Follow down this code through the loop function. First it turns one LED on, then it does what is in that for loop 255 times over, THEN it turns the blinking LED back off. The fading in this example is blocking. Nothing outside that for loop is going to happen until it has gone through the for loop 255 times. So what you’d see is a light turn on, then the other one fades up, then the one turns off, then the other one fades back down. Then repeat.

Now consider the non-blocking example. Here nothing gets hung up in any loops. The loop function keeps turning over and over and through each iteration we check to see if it is time to blink or time to do a fade step and if it is then we do one step and move on to running the rest of the code. I know it doesn’t do things exactly the same way, but it isn’t as easy to write non-blocking code. But follow through the loop function one line at a time thinking about what happens at each step, at no point are we stuck inside one part of the code without letting the rest of the code do its thing.

unsigned long previousBlinkMillis = 0;
unsigned long previousFadeMillis = 0;

int fadeLevel = 0;
int fadeStep = 1;
int fadeDelay = 30;

int blinkDelay = 250;

int fadeLedPin = 5;
int blinkLedPin = 6;

int blinkLedState = LOW;


void setup(){
  pinMode(fadeLedPin, OUTPUT);
  pinMode(blinkLedPin, OUTPUT);
}


void loop(){
  unsigned long currentMillis = millis();
  
  if(currentMillis - previousBlinkMillis >= blinkDelay){
    blinkLedState = !blinkLedState;
    digitalWrite(blinkLedPin, blinkLedState);
    previousBlinkMillis = currentMillis;
  }
  
  if(currentMillis - previousFadeMillis >= fadeDelay){
    fadeLevel = fadeLevel + fadeStep;
    analogWrite(fadeLedPin, fadeLevel);
    if(fadeLevel == 255 || fadeLevel == 0){
      fadeStep = -fadeStep;
    }
    previousFadeMillis = currentMillis;
  }
}

Now, using those two examples, can you see the difference? Do you think you could write a non-blocking code to do what you want?

The fading in this example is blocking.

On the other hand, since there are no delay()s, it'll rip through that for loop in nothing flat.

It also doesn't help that I forgot to update previousMillis anywhere. Going back to correct that now.

PaulS:

The fading in this example is blocking.

On the other hand, since there are no delay()s, it'll rip through that for loop in nothing flat.

I did it that way on purpose. You're right it won't block for long, but I didn't want the OP thinking that the delay call was what was causing it to block.

Rakrak:
I still don’t quite understand how to implement that into the code, would I need to remove :

And create a fader for each pin ?

void fader(int color1, int color2){

for (int brightness=0;brightness<256;brightness++){
       analogWrite(color1, 255-brightness);
       analogWrite(color2, brightness);
       delay(1);
   }
}

try this, which compiles but I cannot test.

Note Pin 13 flashes at an interval of 200ms… that part works :blush:

byte colourPin[3] = {3, 5, 6};// red green blue
byte buttonPin1 = 7;
byte buttonPin2 = 2; 
byte onBoardLed = 13;
byte lastState1;
byte lastState2;
int index = 0;
int lastIndex= 0;
boolean fading;
//
void setup()
{
  Serial.begin(9600);
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
  pinMode(onBoardLed, OUTPUT);//<<<<<<<<<<<< your LED on Pin13 (sorry PaulS for the silly comment)
  for (int i = 0; i < 3; i++)
  {
    pinMode(colourPin[i], OUTPUT);
  }
}
//
void loop()
{
  byte currentState1 = digitalRead(buttonPin1);
  if (currentState1 == HIGH && lastState1 == LOW)
  {
    Serial.println("pressed Up");
    index++;
    if (index > 2) index = 0; 
  }
  lastState1 = currentState1;

  byte currentState2 = digitalRead(buttonPin2);
  if (currentState2 == HIGH && lastState2 == LOW)
  {
    Serial.println("pressed Down");
    index--;
    if (index < 0) index = 2;
  }
  lastState2 = currentState2;
  if (index != lastIndex) fading = true;
  moveLed();
  blinkyBlinky();//<<<<<<<<<<<<<<<<<<< BlinkWithoutDelay sample
  lastIndex = index;
}
//
void moveLed()
{
  static byte brightness = 0;
  static unsigned long lastLedChange;
  if (fading)
  {
    if (millis() - lastLedChange >= 1UL)
    {
      analogWrite(colourPin[index], brightness);//fade up index
      analogWrite(colourPin[lastIndex], 255-brightness);//fade down old pin
      brightness++;
      lastLedChange += 1UL;
    }
    if (brightness >= 255)//<<<<<<< oops... I fixed the overflow
    {
      brightness = 0;
      fading = false;
    }
  }
}
//
void blinkyBlinky()
{
  static unsigned long lastToggleTime;
  if (millis() - lastToggleTime >= 200UL)
  {
    digitalWrite(13, !digitalRead(13));
    lastToggleTime += 100UL;
  }
}

but I didn't want the OP thinking that the delay call was what was causing it to block.

But that IS what is blocking. I understand the point that you are trying to make, that a completely different philosophy is needed for iterating to create non-blocking code than for creating blocking code. But, the factor that decides which philosophy to use is the presence, or absence, of delay()s in the for loop.

One would never advocate dispensing with for loops for printing the elements of an array, because any other method is going to take as long, and no matter what, you really aren't going to do anything else while printing the data.