Single fade out after button press

This is my first program so please, be gentle, my goal is to set up the code so that once I press the button, it glows at full brightness, then fades out after I let go, this is just a test code until I feel confident enough to move on to my real project, which is to wire my arduino Uno to the sound system of my car so that a set of LED lights pulse along with the bass of the music, I plan to use the same basic principle as with this code, but replace the button input with a parallel line running from the subwoofers so that the electrical impulse sets off the arduino lighting the LEDs so that the bass hits light the LEDs and then fade off smoothly, so if you have any input on that as well that would be fantastic, I'll post what I have so far, but in all honesty its really just a copy and paste scrap book from the reference section of the website. Right now with this code, my Arduino fades continuously from high to low when the button is not pressed and glows solid when it is pressed, any help you could offer would be immensly appreciated!

const int buttonPin = 2;
const int ledPin = 9;
int buttonState = 0;
int led = 9;
int brightness = 0;
int fadeAmount = 5;
void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}
void loop() {
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
     digitalWrite(ledPin, HIGH);
  }
  else {
     analogWrite(led, brightness);
     brightness = brightness - fadeAmount;
     if (brightness == 0) {
      fadeAmount = -fadeAmount ;
}
delay(10);
  }
}

How is the switch wired?
It looks to me like the input pin could be floating.

Try this

const byte buttonPin = 2;
const byte ledPin = 9;
byte buttonState = HIGH;
boolean OKtoFade = false;
byte brightness = 0;
byte fadeAmount = 5;

void setup() 
{
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  Serial.begin(112500);
}

void loop() 
{
  Serial.println(brightness);
  if (digitalRead(buttonPin) == LOW) 
  {
    digitalWrite(ledPin, HIGH);
    brightness = 255;
    OKtoFade = true;
  }
  else if (OKtoFade)
  {    
    brightness = brightness - fadeAmount;
    if (brightness < 0)
    {
      brightness = 0;
      OKtoFade = false; 
    }
    analogWrite(ledPin, brightness);
  }
  delay(10);
}

I have used bytes instead of ints, which is good practice, and have used the internal pullup resistor for the input pin to simplify wiring. The code sets a variable to indicate that it is OK to fade the LED only once when the button has been released. I have also changed the code layout to put each brace on its own line, which I find much easier to read.

byte brightness = 0;
...
    if (brightness < 0)

brightness will never be less than zero, being unsigned.

I use something similar in an effects board. Press a button and an LED fades from full to off. This would be only a slight modification.

The way I do it is to always fade regardless, and set the brightness to what I want when I want:

void loop() {
  static bright = 0;
  static unsigned long ts = millis();

  if (digitalRead(button) == LOW) {
    bright = 255;
  }

  analogWrite(led, bright);

  if (millis() - ts >= 10) { // or whatever delay you want
    ts = millis();
    if (bright > 0) bright--;
  }
}

True.
I originally wrote the code with ints and wanted to avoid negative numbers in the pwm output if fadeAmount was changed such that brightness - fadeAmount could go negative. So, what is the best way to deal with this using a byte value for brightness or would it be better to switch to an int in this instance ?

A few ways spring to mind, using an int would be the easiest. Or count up and just subtract the result from 255. Or test for <= 0 if that would be acceptable.

I see that no one has yet mentioned that you (OP) should have a look at the state change detection example, if you really want the LED to fade only (once) when you release the switch.

Or test for <= 0

brightness will never be less than zero, being unsigned.

:slight_smile:

I was trying to cope with the situation where the decrement value would not allow the brightness to be equal to zero, or at least not for many iterations of the fade cycle. All in all an int sounds easiest.

Try this
Code:
const byte buttonPin = 2;
const byte ledPin = 9;
byte buttonState = HIGH;
boolean OKtoFade = false;
byte brightness = 0;
byte fadeAmount = 5;

void setup()
{
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(112500);
}

void loop()
{
Serial.println(brightness);
if (digitalRead(buttonPin) == LOW)
{
digitalWrite(ledPin, HIGH);
brightness = 255;
OKtoFade = true;
}
else if (OKtoFade)
{
brightness = brightness - fadeAmount;
if (brightness < 0)
{
brightness = 0;
OKtoFade = false;
}
analogWrite(ledPin, brightness);
}
delay(10);
}
I have used bytes instead of ints, which is good practice, and have used the internal pullup resistor for the input pin to simplify wiring. The code sets a variable to indicate that it is OK to fade the LED only once when the button has been released. I have also changed the code layout to put each brace on its own line, which I find much easier to read.

what is the difference between bytes and int? the code posted cause the LED to flash when pushed and solid when left openso that doesnt quite work/:

I use something similar in an effects board. Press a button and an LED fades from full to off. This would be only a slight modification.

The way I do it is to always fade regardless, and set the brightness to what I want when I want:

Code:

void loop() {
static bright = 0;
static unsigned long ts = millis();

if (digitalRead(button) == LOW) {
bright = 255;
}

analogWrite(led, bright);

if (millis() - ts >= 10) { // or whatever delay you want
ts = millis();
if (bright > 0) bright--;
}
}

i tried using that code but it said "ISO C++ forbids declaration of 'brightness' with no type"/:

A few ways spring to mind, using an int would be the easiest. Or count up and just subtract the result from 255. Or test for <= 0 if that would be acceptable.

could you elaborate on that please? do you mean to run the fade program and then do an if function for brightness <== 0? and make the function of the if program to stop the fade?

I see that no one has yet mentioned that you (OP) should have a look at the state change detection example, if you really want the LED to fade only (once) when you release the switch.

I have to leave for work right now, but as soon as i can I'll check out that example and see if it helps! thanks!

i tried using that code but it said "ISO C++ forbids declaration of 'brightness' with no type"/:

Because as the error message suggests, brightness has no type. It needs to be a byte, int, char, long, float, etc.

i tried using that code but it said "ISO C++ forbids declaration of 'brightness' with no type"/:

The snippet of code has no "brightness".

If you're going to quote error messages, please post the code they relate to.

so i have to do something like byte brightness = 0 in the beginning?

what is the difference between bytes and int? the code posted cause the LED to flash when pushed and solid when left openso that doesnt quite work/:

I don't believe that you have explained how your button is wired. For my code to work the button has to be wired from the input pin to ground so that the internal pullup resistor can be used (no external resistor). That means that to check for the button being pushed you need to check for a LOW value as the pin is normally held HIGH. If your button is wired from the pin to 5V with a resistor to ground then it will normally be pulled low which the program will interpret as a button press. If you do not have a resistor in the button circuit then when it is not pressed the value on the pin will be floating at an uncertain voltage and all bets are off.

In the case of a standard Arduino, such as a UNO, a byte is an 8 bit unsigned value that can be between 0 and 255 whereas an int is a signed 16 bit variable with a value between -32,768 and 32,767. My point in using bytes instead of ints was to save memory, which is normally regarded as good practice. You will have seen later posts pointing out that my code was checking to see whether a byte value was less than zero, which is impossible, hence the suggestion to change to an int after all for the brightness variable.

I have it wired as the tutorial for button presses has it shown http://arduino.cc/en/Tutorial/ButtonStateChange so you're saying I SHOULD use int afterall to allow for the use of 0?

so Ive been taking a look at your code and just for learnings sake so I can do these things on my own let me see if I can break it down

const byte buttonPin = 2;  //setting the constant inputs
const byte ledPin = 9;
byte buttonState = HIGH;  //stating that when power is recieved, the button is being pressed
boolean OKtoFade = false;  // a variable linking to the else if statement below, setting the default value to false
byte brightness = 0;  // setting value for the variable brightness 
byte fadeAmount = 5;  //setting the fade rate for the fade command

void setup() 
{
  pinMode(ledPin, OUTPUT);  // assigning the LED as an output
  pinMode(buttonPin, INPUT_PULLUP);   //Assigning the button as an input and i assume that the _PULLUP activates the internal resistor?
  Serial.begin(112500);   //Begin communications with the button
}

void loop() 
{
  Serial.println(brightness);         //im not sure what your trying to communicate with in this line
  if (digitalRead(buttonPin) == LOW) // a conditional statement if the button is NOT pressed
  {
    digitalWrite(ledPin, HIGH); //a command to turn on the LED
    brightness = 255; // what brightness to give the LED
    OKtoFade = true; //make the fade variable true
  }
  else if (OKtoFade) //conditional statement for if OKtoFade is true
  {    
    brightness = brightness - fadeAmount; // fade program
    if (brightness < 0) //when 1st fade completes
    {
      brightness = 0; //turn off LED
      OKtoFade = false; //stop fade
    }
    analogWrite(ledPin, brightness); //to turn on the LED when the button is pressed
  }
  delay(10);   //fade rate?
}

thank you for all your help btw, I hope all my questioning isnt too much a bother, I just started learning all this stuff yesterday and its just completely fascinating I can't wait to get into more complicated processes and ideas after this project!

byte buttonState = HIGH;  //stating that when power is recieved, the button is being pressed

No, setting the starting state of the variable to HIGH

pinMode(buttonPin, INPUT_PULLUP); //Assigning the button as an input and i assume that the _PULLUP activates the internal resistor?

Yes, but it does mean that the button must be wired correctly and no external resistor is needed. Testing for the button being pressed requires the code to look for a LOW as it is normally held HIGH

Serial.begin(112500);   //Begin communications with the button

No. This sets up the serial output ready to print to the serial monotor. Nothing to do with the button

Serial.println(brightness);         //im not sure what your trying to communicate with in this line

Output the value of the brightness variable to the serial monitor so that it can be seen for debugging purposes.

 if (digitalRead(buttonPin) == LOW) // a conditional statement if the button is NOT pressed

No. Test if the button is pressed. Remember, INPUT_PULLUP means that it is HIGH when not pressed

  OKtoFade = true; //make the fade variable true

Yes. Set the variable to indicate that it is OK to fade the LED when the button is released.

 else if (OKtoFade) //conditional statement for if OKtoFade is true

We only get here if the button is not pressed but need to check whether the fade has already happened, in which case OKtoFade will be false and the code in the if code block will not be run. ie, no fade because we have already done it when the button was released.

     OKtoFade = false; //stop fade

Change the variable to make sure that next time through loop() we do not fade again unless the button has been pressed again

   analogWrite(ledPin, brightness); //to turn on the LED when the button is pressed

Set the brightness of the LED. It will already be turned on but we need to adjust the value to make the fade happen.

 delay(10);   //fade rate?

Wait 10 milliseconds between fades otherwise the fade will happen too fast.
NOTE - this command blocks execution of any other code.

Here is a revised version of the program that will work with your original wiring

const byte buttonPin = 2;
const byte ledPin = 9;
byte buttonState = LOW;
boolean OKtoFade = false;
int brightness = 0;
byte fadeAmount = 5;

void setup() 
{
  pinMode(ledPin, OUTPUT);
  analogWrite(ledPin, 0);
  pinMode(buttonPin, INPUT);
  Serial.begin(112500);
}

void loop() 
{
  Serial.println(brightness);
  if (digitalRead(buttonPin) == HIGH) 
  {
    digitalWrite(ledPin, HIGH);
    brightness = 255;
    OKtoFade = true;
  }
  else if (OKtoFade)
  {    
    brightness = brightness - fadeAmount;
    if (brightness <= 0)
    {
      brightness = 0;
      OKtoFade = false; 
    }
    analogWrite(ledPin, brightness);
  }
  delay(10);
}

thank you so much for your help! you've helped me tremendously, it should be fairly simple for me to alter the code to work by using the parrelel line for input versus the button!

austinphilp:

A few ways spring to mind, using an int would be the easiest. Or count up and just subtract the result from 255. Or test for <= 0 if that would be acceptable.

could you elaborate on that please?

I was replying to UKHeliBob's suggested code, not yours.

do you mean to run the fade program and then do an if function for brightness <== 0? and make the function of the if program to stop the fade?

That doesn't make a heap of sense. "if" isn't a function nor is it a program. I suggest reading a C tutorial.