Fade IN and Fade OUT with Button

I am using the following code as a starting point:

//  Example 05: Turn on LED when the button is pressed 
//  and keep it on after it is released
//  including simple de-bouncing.
//  If the button is held, brightness changes. 
//
// Copy and paste this example into an empty Arduino sketch

#define LED 9     // the pin for the LED 
#define BUTTON 7  // input pin of the pushbutton

int val = 0;      // stores the state of the input pin

int old_val = 0;  // stores the previous value of "val" 
int state = 0;    // 0 = LED off while 1 = LED on

int brightness = 128;        // Stores the brightness value
unsigned long startTime = 0; // when did we begin pressing?

void setup() { 
  pinMode(LED, OUTPUT);   // tell Arduino LED is an output 
  pinMode(BUTTON, INPUT); // and BUTTON is an input 
} 

void loop() {
 
  val = digitalRead(BUTTON); // read input value and store it 
                             // yum, fresh 

  // check if there was a transition 
  if ((val == HIGH) && (old_val == LOW)) {
 
    state = 1 - state; // change the state from off to on
                       // or vice-versa

    startTime = millis(); // millis() is the Arduino clock
                          // it returns how many milliseconds
                          // have passed since the board has
                          // been reset.

    // (this line remembers when the button
    // was last pressed)
    delay(10);
  }

  
// check whether the button is being held down 
  if ((val == HIGH) && (old_val == HIGH)) {

    // If the button is held for more than 500ms.
    if (state == 1 && (millis() - startTime) > 500) {

      brightness++; // increment brightness by 1
      delay(10);    // delay to avoid brightness going
                    // up too fast

      if (brightness > 255) { // 255 is the max brightness

        brightness = 0; // if we go over 255
                        // letâ??s go back to 0
      }
    }
  }

  old_val = val; // val is now old, letâ??s store it 

  if (state == 1) {      
    analogWrite(LED, brightness); // turn LED ON at the                                               // current brightness level
  } else { 
    analogWrite(LED, 0); // turn LED OFF 
  } 
}

What I would like to do is make the LED fade IN and then once it has reached its maximum brightness (255) fade back out (0). The code I have written is not getting the job done and I am starting to get quite confused by what should be a pretty straight forward little project.

//  Example 05: Turn on LED when the button is pressed 
//  and keep it on after it is released
//  including simple de-bouncing.
//  If the button is held, i changes. 
//
// Copy and paste this example into an empty Arduino sketch

#define LED 9     // the pin for the LED 
#define BUTTON 7  // input pin of the pushbutton

int val = 0;      // stores the state of the input pin

int old_val = 0;  // stores the previous value of "val" 
int state = 0;    // 0 = LED off while 1 = LED on

int i = 0;        // Stores the i value
int brightness = 32;
unsigned long startTime = 0; // when did we begin pressing?

void setup() { 
  pinMode(LED, OUTPUT);   // tell Arduino LED is an output 
  pinMode(BUTTON, INPUT); // and BUTTON is an input 
} 

void loop() {
 
  val = digitalRead(BUTTON); // read input value and store it 
                             // yum, fresh 

  // check if there was a transition 
  if ((val == HIGH) && (old_val == LOW)) {
 
    state = 1 - state; // change the state from off to on
                       // or vice-versa

    startTime = millis(); // millis() is the Arduino clock
                          // it returns how many milliseconds
                          // have passed since the board has
                          // been reset.

    // (this line remembers when the button
    // was last pressed)
    delay(10);
  }

  
// check whether the button is being held down 
  if ((val == HIGH) && (old_val == HIGH)) {

    // If the button is held for more than 500ms.
    if (state == 1 && (millis() - startTime) > 500) {

      for (i = 0; i < 255; i++) { // loop from 0 to 254 (fade in)
        brightness = i;
        delay(10); // Wait 10ms because analogWrite
               // is instantaneous and we would
               // not see any change
      }

      for (i = 255; i > 0; i--) { // loop from 255 to 1 (fade out)
        brightness = i;
        delay(10);           // Wait 10ms
      }
    }
  }

  old_val = val; // val is now old, let's store it 

  if (state == 1) {      
    analogWrite(LED, brightness); // turn LED ON at the current i level
  } else { 
    analogWrite(LED, 0); // turn LED OFF 
  } 
}

Any assistance to get me headed in the right direction would be greatly appreciated. Thank you.

About this:

for (i = 0; i < 255; i++) { // loop from 0 to 254 (fade in)
        brightness = i;
        delay(10); // Wait 10ms because analogWrite
               // is instantaneous and we would
               // not see any change
      }

This will execute for about two and a half seconds before continuing with further execution. And in effect, your brightness will never be analogWrite()'d because analogWrite is actually not instantaneous, in a multithreaded mutex kind of way.

:slight_smile:

You could use the analogWrite() function and connect the LED to a pin that supports pwm. (For this: see you Sketchbook: Examples->Analog->Fading)

Or if you don’t want to use pwm, you can try the following code:

uint8_t ledPin = 8;

uint8_t brightness;
uint8_t counter;

void setup()
{
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  for(brightness = 0; brightness<255; brightness++)
  {
    for(counter = 0; counter <255; counter++)
    {
      digitalWrite(ledPin, counter<brightness);
    }
    delay(1);

  }

  for(brightness = 255; brightness>0; brightness--)
  {
    for(counter = 0; counter <255; counter++)
    {
      digitalWrite(ledPin, counter<brightness);
    }
    delay(1);
  }
}

the counter variable is used to divide time into 256 time slots. In each time slot the LED can be on or off.
Example: brightness = 100
then the led is on for the first 100 time slots and off for the remaining 155 time slots.

By increasing brightness (outer loop) from 0 to 255 and then decreasing it, the LED is fading.

delay(1); makes sure that this fading isn’t too fast. If you need a slower fading, simply change the delay value.

Sorry, I did not scroll to the bottom of your code and missed these lines:

if (state == 1) {      
    analogWrite(LED, brightness); // turn LED ON at the current i level
  } else {
    analogWrite(LED, 0); // turn LED OFF
  }

so you are using analogWrite()... simply move the code block to the place where you set the brightness and your code should work.

So after

 brightness = i;

you must do the analogWrite()

Forgive my ignorance but when I update the code as I think you suggest I get strange results. When I momentarily press the button, the light comes on as it should however, when I press and hold the button, the light goes up and then down and then shuts off and no longer actuates at all.

Here is the code as it now stands:

//  Example 05: Turn on LED when the button is pressed 
//  and keep it on after it is released
//  including simple de-bouncing.
//  If the button is held, i changes. 
//
// Copy and paste this example into an empty Arduino sketch

#define LED 9     // the pin for the LED 
#define BUTTON 7  // input pin of the pushbutton

int val = 0;      // stores the state of the input pin

int old_val = 0;  // stores the previous value of "val" 
int state = 0;    // 0 = LED off while 1 = LED on

int i = 32;        // Stores the i value
unsigned long startTime = 0; // when did we begin pressing?

void setup() { 
  pinMode(LED, OUTPUT);   // tell Arduino LED is an output 
  pinMode(BUTTON, INPUT); // and BUTTON is an input 
} 

void loop() {
 
  val = digitalRead(BUTTON); // read input value and store it 
                             // yum, fresh 

  // check if there was a transition 
  if ((val == HIGH) && (old_val == LOW)) {
 
    state = 1 - state; // change the state from off to on
                       // or vice-versa

    startTime = millis(); // millis() is the Arduino clock
                          // it returns how many milliseconds
                          // have passed since the board has
                          // been reset.

    // (this line remembers when the button
    // was last pressed)
    delay(10);
  }

  
// check whether the button is being held down 
  if ((val == HIGH) && (old_val == HIGH)) {

    // If the button is held for more than 500ms.
    if (state == 1 && (millis() - startTime) > 500) {

      for (i = 32; i < 255; i++) { // loop from 0 to 254 (fade in)
        analogWrite(LED, i);
        delay(10); // Wait 10ms because analogWrite
               // is instantaneous and we would
               // not see any change
      }

      for (i = 255; i > 0; i--) { // loop from 255 to 1 (fade out)
        analogWrite(LED, i);
        delay(10);           // Wait 10ms
      }
    }
  }

  old_val = val; // val is now old, let's store it 

  if (state == 1) {      
    analogWrite(LED, i); // turn LED ON at the current brightness level
  } else { 
    analogWrite(LED, 0); // turn LED OFF 
  } 
}

How about this?

// Example 05:
// Turn on LED when the button is pressed
// Keep LED on after button is released
// including simple de-bouncing.
// If the button is held, i changes.
//
// This uses a Finite State Machine.
// http://en.wikipedia.org/wiki/Finite_state_machine
//
// Copy and paste this example into an empty Arduino sketch

//program config
#define SERIAL_DEBUG false
#define BAUDRATE 9600

//pin declarations
#define LED 9 // the pin for the LED
#define BUTTON 7 // input pin of the pushbutton

//button config
#define PULLUP_RESISTOR 1 //set to 0 if pulldown is used
#define BUTTON_PRESSED (!PULLUP_RESISTOR)

//time variabels
#define BUTTON_HOLD_LIMIT 500 //how long does the button need to be pressed
#define LED_ON_AFTER_RELEASE 300
#define DEBOUNCE_DELAY 20
#define FADE_DELAY 5

//indicate program state
typedef enum State
{
BUTTON_PRESS,
BUTTON_HOLD,
BUTTON_RELEASED
} State;

State state=BUTTON_RELEASED;

//fade variables
boolean fadeIn = true; //keeps track of current fading when BUTTON_HOLD
boolean fadeOut = true; //fade out after BUTTON_PRESS
byte fadeState = 100;

unsigned long buttonPressTime = 0; // when did we begin pressing?
unsigned long buttonReleaseTime = 0; // when did we begin pressing?

//prototypes
void transitionTo(); //TODO - implement
void debug();

//setup
void setup() {
pinMode(LED, OUTPUT); // tell Arduino LED is an output
pinMode(BUTTON, INPUT); // and BUTTON is an input
if (PULLUP_RESISTOR) digitalWrite(BUTTON,HIGH);
if (SERIAL_DEBUG) Serial.begin(BAUDRATE);
}

void loop() {
//read button && set state
if (digitalRead(BUTTON)==BUTTON_PRESSED && state == BUTTON_RELEASED){
state = BUTTON_PRESS;
buttonPressTime = millis();
delay(DEBOUNCE_DELAY);
} else if (digitalRead(BUTTON)==BUTTON_PRESSED && state == BUTTON_PRESS){
if (buttonPressTime + BUTTON_HOLD_LIMIT < millis()){
state = BUTTON_HOLD;
}
} else if (digitalRead(BUTTON)!=BUTTON_PRESSED && state != BUTTON_RELEASED){
if (state==BUTTON_PRESS) {
//only hold LED on if button was pressed and not held
buttonReleaseTime = millis();
}
state = BUTTON_RELEASED;
}

//execute program according to state
if (state == BUTTON_PRESS) {
analogWrite(LED, fadeState); // turn LED ON at the current brightness level
} else if (state == BUTTON_HOLD){
fadeState==0 ? fadeIn = true : (fadeState==255 ? fadeIn = false : fadeIn);//set fadeIn flag according to fadeState
fadeIn ? ++fadeState : --fadeState; //fade in or out
analogWrite(LED, fadeState); // set pwm at current fadeState
delay(FADE_DELAY);
} else if (state == BUTTON_RELEASED){
if ( buttonReleaseTime + LED_ON_AFTER_RELEASE > millis() ){
analogWrite(LED,fadeState);
delay(FADE_DELAY);
} else {
digitalWrite(LED, 0); // turn LED OFF
}
}

//trigger debug routine
debug();
}

//debug to serial
//TODO - debug all variables of interest
void debug(){
//debug

//serial debug
if(SERIAL_DEBUG){ //
Serial.print("State: ");
if (state == BUTTON_PRESS) {
Serial.print("BUTTON_PRESS ");
} else if (state == BUTTON_HOLD){
Serial.print("BUTTON_HOLD ");
} else if (state == BUTTON_RELEASED){
Serial.print("BUTTON_RELEASED “);
}
Serial.print(” fadeState: ");
Serial.println(fadeState,DEC);
}
}

I’m not sure where all the complexity has come from. I modified the fading routine in examples. This fades in then out and pauses when the button is not pressed. Should do what you need.

// Fading LED 
// by BARRAGAN <http://people.interaction-ivrea.it/h.barragan> 

int value = 0;                            // variable to keep the actual value 
int ledPin = 9;    // light connected to digital pin 9
int buttonPin = 7;
int buttonVal;
int dir = 0;
 
void setup() 
{ 
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
} 
 
void loop() 
{ 
  buttonVal = digitalRead(buttonPin);
  
  while(buttonVal == HIGH)
  {
 
    if (dir == 0) // fade in (from min to max) 
    { 
      value += 5;
      analogWrite(ledPin, value);           // sets the value (range from 0 to 255) 
      delay(30);      // waits for 30 milli seconds to see the dimming effect 
      if(value == 255)
        dir = 1;
    }
 
    if (dir ==1)   // fade out (from max to min) 
    { 
      value -= 5;
      analogWrite(ledPin, value); 
      delay(30); 
      if(value == 0);
        dir = 0;
    } 
   
   buttonVal = digitalRead(buttonPin); 
  }
}

I just thought of something. Do you want to press the button, then have it fade in and out in one swoop? What is the sequence you’re trying to achieve?

What caused the complexity:

// Example 05: Turn on LED when the button is pressed // and keep it on after it is released // including simple de-bouncing. // If the button is held, i changes.(after a set interval according to his code)

Although my code might seem overly complex (which is correct I suppose) it is useful being able to debug when needed, change between pullup and pulldown buttonlogic with the change of a 0 to a 1, it might be of interest to fade out after release. (This was not ment defensive, I just wanted to be a little pro complex ;))

I see. I disregarded the comments because he said it was just an example he was working from.