Go Down

Topic: 2 button fade control (Read 3015 times) previous topic - next topic

digimike

I'm working on this to use 2 buttons to control fading of an LED. One button is used to increase the brightness of the LED in increments of 5 while the other button will decrease the brightness by 5.

The end goal is to set up 6 buttons and have full control of the color an RGB led produces. So maybe someone already has a better method of doing this.

Here is what i have so far.
Code: [Select]
 int redled = 10;    // assign LED to pin 10
 int button2 = 2;    // assign pushbutton 2 to pin 2
 int button3 = 3;    // assign pushbutton 3 to pin 3
 
 
 int button2State = 0;    // variable for reading the pushbuttons
 int button3State = 0;
 int fadered = 0;    // LED set to be off to start
 

 void setup () {
   pinMode(button2, INPUT);    //initialize pushbutton pins as input:
   pinMode(button3, INPUT);
 }
     
 void loop() {
   
   int button2State = digitalRead(button2);    //check button states
   int button3State = digitalRead(button3);
   
   if(button2State == HIGH && fadered <=250) { // if button is pressed increase brightness by 5
     fadered = fadered + 5;    // as long as brightness isn't greater then 250
     analogWrite(redled, fadered);    // lights LED at current brightness level
   
   }
       
   if (button3State == HIGH && fadered >=5) {    // if button is pressed decrease brightness by 5
     fadered = fadered - 5;    // as long as brightness isn't less then 5
     analogWrite(redled, fadered);    // lights LED at current brightness level
   
   }
  }


But all it does is turn the LED full on when the decrease button is pressed and off when the increase button is pressed. So what is wrong or what am i missing?

Groove

#1
Jan 14, 2010, 04:14 pm Last Edit: Jan 14, 2010, 04:22 pm by GrooveFlotilla Reason: 1
See my reply to your query in "Bugs" and don't forget that "loop" will execute many times whilst your button is pressed.

Quote
have full control of the color an RGB led produces. So maybe someone already has a better method of doing this.

Use three pots and the "map" function.
Per Arduino ad Astra

digimike

Flipped the LED. That helped allot thanks.

Is there a better way to have the sketch see only one press per push without adding a delay to each of the if statements?

PaulS

Add another variable to keep track of the button state.

Read the button state.

If it is HIGH and it was LOW, do something. If it is LOW and it was HIGH, do something else.

Set the new variable to the current button state.

digimike

Great idea. Thanks

But i think the delay will work best for now. That way the delay is set so a single push is registered only once but if i hold the button down i can still get multiple executions.

digimike

one last question. For the buttons, do you have to have a 10k resistor or will most any resistor due. I have noticed that the Arduino errors out if there is no resistor but seams to do fine when i use a 100 ohm in place of the 10k.

Groove

#6
Jan 14, 2010, 05:19 pm Last Edit: Jan 14, 2010, 05:20 pm by GrooveFlotilla Reason: 1
Assuming you're talking about pull-ups, you don't need any external pull-ups, simply use the AVR's built-in ones, enabled by a "digitalWrite" to the appropriate input pin (after you've set the "pinMode").
Connect the switches between the input and ground, and remember this will invert your logic; a closed switch will read LOW.
Per Arduino ad Astra

TroyO

If you are interested (Not sure it suits your application) here's some code that uses a single button to set the color of an LED then fade it in/out.

Click = Fade up
Double Click = Fade down

Press and hold puts you in a "menu" to set the color.
While in the setting mode, a single click steps up the current color (Reg. green or blue) in incriments of 10% from off to 100%. (11 steps) and a double click moves to the next color. Press and hold to exit the setting menu.

In practice, you go in to menu mode, then click-click-click-click until red is where you want it, then double-click to move to green, and click-click-click to set greens brightness, and double-click to start setting blue, etc. Press and hold to exit.

NOTE: the code is not very clean... it could use some tweaking/cleanup, etc. It's part of a larger project I'm working on, so it's not fully developed yet. At least, it may give you some ideas. (Atually, I like your press and hold to automatically step through values.... I may use that and require 2 press and hold events to exit the menu instead.)

Code: [Select]

/* 3-Way Button: Click, Double-Click, Press+Hold RGB Test Sketch
By Jeff Saltzman
Oct. 13, 2009
Modified by Troy Ollom
Jan. 6, 2010

To keep a physical interface as simple as possible, this sketch demonstrates generating three output events from a single push-button.
1) Click: rapid press and release
2) Double-Click: two clicks in quick succession
3) Press and Hold: holding the button down
*/

#define buttonPin 2 // analog input pin to use as a digital input
#define redPin 3 // digital output pin for LED 1
#define grnPin 5 // digital output pin for LED 2
#define bluPin 6// digital output pin for LED 3

// RGB LED variables
int rgbX [3] = {
 11,2,2};           // RGB Array
int rgbFactor = 11;      // Value to factor by.. IE, 100 would provide 100 steps 255 is Max
int randFlicker = 10;
int fadeValue = 0;       //tracks the current state of the fade value
boolean fadeDirection = false; // in this case, true means fade up, false means fade down
int colorMode = 0;
boolean menuMode = false;

//=================================================
// RGB Timing Variables
long rgbMillis = 0;      // Store millis to keep track of the last time rgb was updated
int rgbInterval = 30;    // How often to update the rgb values
//=================================================
void setup()
{
 // Set button input pin
 pinMode(buttonPin, INPUT);
 digitalWrite(buttonPin, HIGH );
 // Set LED output pins
 pinMode(redPin, OUTPUT);
 digitalWrite(redPin, 0);
 pinMode(grnPin, OUTPUT);
 digitalWrite(grnPin, 0);
 pinMode(bluPin, OUTPUT);
 digitalWrite(bluPin, 0);
}

void loop()
{
 // Get button event and act accordingly
 int b = checkButton();
 if (b == 1) clickEvent();
 if (b == 2) doubleClickEvent();
 if (b == 3) holdEvent();

 if (menuMode == true)
 {
   fadeValue =255;
 }
 if (millis () - rgbMillis >= rgbInterval){             // if it's been 30 ms since last time, lets update the LED
   rgbMillis = millis ();                               //reset so we know the last time
   if (fadeDirection == true){                          //This is gonna happen is we are fading UP
     if (fadeValue <=250) {                             // If fadeValue is less than or equalls 250
       fadeValue = fadeValue +5;                        // Lets add 5 to it
     }
     else {
       randFlicker = random(41);            
       fadeValue = 255 - randFlicker;                  // or else if it's already there, just make it 255 and flicker it there
     }
   }
   if (fadeDirection == false){                         //This is gonna happen if we are fading down
     if (fadeValue >=5) {                               // if its over or = to 5
       fadeValue = fadeValue - 5;                       // subtract 5 from it
     }
     else {
       fadeValue = 0;                                   // if it's less than 5 hold it at zero
     }

   }
   updateLED ();
 }
}

void updateLED ()
{
 analogWrite(redPin, fadeValue * rgbX[0] / rgbFactor);   //Now that the math has been done, update the LED
 analogWrite(bluPin, fadeValue * rgbX[1] / rgbFactor);
 analogWrite(grnPin, fadeValue * rgbX[2] / rgbFactor);
}

//=================================================
// Events to trigger by click and press+hold

void clickEvent() {
 if (menuMode == false){
   fadeDirection = true;
 }
 if (menuMode == true){
   rgbX[colorMode] = rgbX[colorMode]++;
   if (rgbX[colorMode] >= rgbFactor){
     rgbX[colorMode] = 0;
   }
   updateLED();
 }
}
void doubleClickEvent() {
 if (menuMode == false){
   fadeDirection = false;
 }
 if (menuMode == true) {
   colorMode = colorMode ++;
   if (colorMode >=3){
     colorMode = 0;
   }  
 }
}
void holdEvent() {
 menuMode = !menuMode;
colorMode = 0;
}


/*
MULTI-CLICK: One Button, Multiple Events

Oct 12, 2009
Run checkButton() to retrieve a button event:
Click
Double-Click
Hold
Long Hold
*/

// Button timing variables
int debounce = 20; // ms debounce period to prevent flickering when pressing or releasing the button
int DCgap = 250; // max ms between clicks for a double click event
int holdTime = 2000; // ms hold period: how long to wait for press+hold event
int longHoldTime = 5000; // ms long hold period: how long to wait for press+hold event

// Other button variables
boolean buttonVal = HIGH; // value read from button
boolean buttonLast = HIGH; // buffered value of the button's previous state
boolean DCwaiting = false; // whether we're waiting for a double click (down)
boolean DConUp = false; // whether to register a double click on next release, or whether to wait and click
boolean singleOK = true; // whether it's OK to do a single click
long downTime = -1; // time the button was pressed down
long upTime = -1; // time the button was released
boolean ignoreUp = false; // whether to ignore the button release because the click+hold was triggered
boolean waitForUp = false; // when held, whether to wait for the up event
boolean holdEventPast = false; // whether or not the hold event happened already

int checkButton()
{
 int event = 0;
 // Read the state of the button
 buttonVal = digitalRead(buttonPin);
 // Button pressed down
 if (buttonVal == LOW && buttonLast == HIGH && (millis() - upTime) > debounce) {
   downTime = millis();
   ignoreUp = false;
   waitForUp = false;
   singleOK = true;
   holdEventPast = false;
   if ((millis()-upTime) < DCgap && DConUp == false && DCwaiting == true) DConUp = true;
   else DConUp = false;
   DCwaiting = false;
 }
 // Button released
 else if (buttonVal == HIGH && buttonLast == LOW && (millis() - downTime) > debounce) {
   if (not ignoreUp) {
     upTime = millis();
     if (DConUp == false) DCwaiting = true;
     else {
       event = 2;
       DConUp = false;
       DCwaiting = false;
       singleOK = false;
     }
   }
 }
 // Test for normal click event: DCgap expired
 if ( buttonVal == HIGH && (millis()-upTime) >= DCgap && DCwaiting == true && DConUp == false && singleOK == true) {
   event = 1;
   DCwaiting = false;
 }
 // Test for hold
 if (buttonVal == LOW && (millis() - downTime) >= holdTime) {
   // Trigger "normal" hold
   if (not holdEventPast) {
     event = 3;
     waitForUp = true;
     ignoreUp = true;
     DConUp = false;
     DCwaiting = false;
     //downTime = millis();
     holdEventPast = true;
   }
 }
 buttonLast = buttonVal;
 return event;
}





digimike

#8
Jan 14, 2010, 06:32 pm Last Edit: Jan 14, 2010, 06:48 pm by digimike Reason: 1
Thanks TroyO i'll have a look threw your code.

Well everything is working great. I only have 5 10k resistors so one of the buttons has a 100 ohm on it. I'm not sure of what Groove is referring too. Do i add lines to the void setup or in the loop to tell it to digital write the buttons?

I found one other problem with my sketch. It seams pin 12 doesn't do analogWrite. so i adjusted things so the leds are on pins 9, 10, and 11.

Here is the final code for those interested.
Code: [Select]
/*
 RGB Color Wheel
 
 Indivigually control the brightness of a Red LED, Blue LED and
 Green LED using 6 pushbuttons attached to pins 2 thru 7. The
 pushbuttons on the even number pins will brighten the corosponding
 LED and the odd numbered ones will dim them. LEDs will be attached
 to pins 10, 11, and 12.
 
 The Circuit:
 * Red LED from pin 9 to ground threw a 220 Ohm resistor
 * Blue LED from pin 10 to ground threw a 220 Ohm Resistor
 * Green LED from Pin 11 to ground threw a 220 Ohm Resistor
 * pushbutton 1 attached to pin 2 from +5V
 * 10k resistor attached to pin 2 from ground
 * pushbutton 2 attached to pin 3 from +5V
 * 10k resistor attached to pin 3 from ground
 * pushbutton 3 attached to pin 4 from +5V
 * 10k resistor attached to pin 4 from ground
 * pushbutton 4 attached to pin 5 from +5V
 * 10k resistor attached to pin 5 from ground
 * pushbutton 5 attached to pin 6 from +5V
 * 10k resistor attached to pin 6 from ground
 * pushbutton 6 attached to pin 7 from +5V
 * 10k resistor attached to pin 7 from ground
 
 
 created 13 Jan 2010
 by digimike
 modified 14 jan 2010
 by digimike
 */
 
 
 int redled = 9;    // assign LEDs to pins
 int greenled = 10;
 int blueled = 11;
 int button2 = 2;    // assign pushbuttons to pins
 int button3 = 3;
 int button4 = 4;
 int button5 = 5;
 int button6 = 6;
 int button7 = 7;
 
 int button2State = 0;    // variable for reading the pushbuttons
 int button3State = 0;
 int button4State = 0;
 int button5State = 0;
 int button6State = 0;
 int button7State = 0;
 int fadered = 0;
 int fadegreen = 0;
 int fadeblue = 0;



 void setup () {
   pinMode(button2, INPUT);    //initialize pushbutton pins as input:
   pinMode(button3, INPUT);
   pinMode(button4, INPUT);
   pinMode(button5, INPUT);
   pinMode(button6, INPUT);
   pinMode(button7, INPUT);
 }
 
 void loop() {
   button2State = digitalRead(button2);    //check button state
   if(button2State == HIGH && fadered <= 250) {
     // if button is pressed increase brightness by 5
     // as long as brightness isn't greater than 250
     fadered +=5;
     analogWrite(redled, fadered);  // lights LED at current brightness level
     delay(250);  // allows time so button won't be detected multiple times
   }
   
   button3State = digitalRead(button3);    //check button state
   if (button3State == HIGH && fadered >= 5) {
     // if button is pressed decrease brightness by 5
     // as long as brightness isn't less than 5
     fadered -=5;
     analogWrite(redled, fadered);  // lights LED at current brightness level
     delay(250);  // allows time so button won't be detected multiple times
   }
   
   button4State = digitalRead(button4);    //check button state
   if (button4State == HIGH && fadegreen <= 250) {  
     // if button is pressed increase brightness by 5
     // as long as brightness isn't greater than 250
     fadegreen +=5;
     analogWrite(greenled, fadegreen);  // lights LED at current brightness level
     delay(250);  // allows time so button won't be detected multiple times
   }
   
   button5State = digitalRead(button5);    //check button state
   if (button5State == HIGH && fadegreen >= 5) {  
     // if button is pressed decrease brightness by 5
     // as long as brightness isn't less than 250
     fadegreen -=5;
     analogWrite(greenled, fadegreen);  // lights LED at current brightness level
     delay(250);  // allows time so button won't be detected multiple times
   }
   
  button6State = digitalRead(button6);    //check button state
   if (button6State == HIGH && fadeblue <= 250) {  
     // if button is pressed increase brightness by 5
     // as long as brightness isn't greater than 250
     fadeblue += 5;
     analogWrite(blueled, fadeblue);  // lights LED at current brightness level
     delay(250);  // allows time so button won't be detected multiple times
   }
   
   button7State = digitalRead(button7);    //check button state
   if (button7State == HIGH && fadeblue >= 5) {  
     // if button is pressed decrease brightness by 5
     // as long as brightness isn't less than 250
     fadeblue -= 5;
     analogWrite(blueled, fadeblue);  // lights LED at current brightness level
     delay(250);  // allows time so button won't be detected multiple times
   }
 }    


Hope its as simple and clean as i wanted it to be. I like to try and keep things as simple as possible. The last time i did any amount of programing was on my old TI-85 calc using TIBasic. Doesn't take long for basic to eat up the little memory the calc had.

EDIT:
After reviewing TroyO's code i think i figured out what you meant about the buttons.
So my setup will now look like this, right?
Code: [Select]
void setup () {
   pinMode(button2, INPUT);    //initialize pushbutton pins as input:
   pinMode(button3, INPUT);
   pinMode(button4, INPUT);
   pinMode(button5, INPUT);
   pinMode(button6, INPUT);
   pinMode(button7, INPUT);
   digitalWrite(button2, HIGH);
   digitalWrite(button3, HIGH);
   digitalWrite(button4, HIGH);
   digitalWrite(button5, HIGH);
   digitalWrite(button6, HIGH);
   digitalWrite(button7, HIGH);    
 }

Then of course the if statements will be looking for the button to read LOW.  It works like a charm. Thanks.

Next i think i'll have the leds blink a couple of times if i hit the 255 max. Its hard to tell if its on full. its seams to be as bright as it will get at around 150. guess i should have it report back to the PC what teh level is. but i havn't gotten that far in learning this yet.

tkbyd

In this sort of application, the problem of "switch bounce" can be a factor. Lots of things about that on the web. A less than perfect one at...

http://sheepdogguides.com/arduino/FA1inp1.htm

digimike

As of now all the kinks in the sketch are worked out. I went from using a red, a green, and a blue LED to using a single RGB LED. Problem was the RGB uses a common Anode and the sketchup was writen for the LEDs having a common Cathode. So i had to do some tweeking. For a while there i did have commands in there that blinked the LEDs once when it hit the 255 max. But took that out. I had it so that if the fade value was 255 it would use a digitalWrite to turn the LED off then back on again with a 1 second delay. But i didn't want any possible conflicts between the arduino using those pins as analogWrite then digitalWrite.

I'm at work right now but will post the completed code when i get home tonight. Overall the project isn't completed quite yet. When it is i'll post it in exhibition.

Next part that i'll be asking help on will be comunicating the brightness levels of the LEDs back to the PC. Fortunatly my wife has had some schooling on C and C++ so she is able to help. But since she doen't understand the hardware at all she has trouble with figuring out the initial code. But she is good with troubleshooting existing code for me.

Groove

Quote
But i didn't want any possible conflicts between the arduino using those pins as analogWrite then digitalWrite

So, you've already worked out which values for "analogWrite" set the LED full on, and those values that turn it off, so instead of blinking the LED with digitalWrite, use analogWrite instead.
Per Arduino ad Astra

digimike

#12
Jan 15, 2010, 11:46 pm Last Edit: Jan 15, 2010, 11:47 pm by digimike Reason: 1
Not sure if i'll incorperate that or not. But it was hlepful to have that blink to indicate full on. Once i get the unit reporting the values back to the PC there will be no need for the blink.

Here is the working code from the thread in the hardware section that just uses the red side of the RGB. Full code will be posted some time around 1 AM eastern.

Code: [Select]
/*
 created 14 Jan 2010
 by digimike
 modified 15 jan 2010
 by digimike
 */


 int redled = 9;    // assign LED to pin 9
 int redup = 2;    // assign pushbuttons to pins
 int reddown = 3;

 int r_btn_up = 0;    // variable for reading the pushbuttons
 int r_btn_down = 0;
 int fadered = -5;    // starting brightness values for each led


 void setup () {
   pinMode(redup, INPUT);    //initialize pushbutton pins as input:
   pinMode(reddown, INPUT);
   digitalWrite(redup, HIGH);
   digitalWrite(reddown, HIGH);
 }

 void loop() {
// increase the brightness
   r_btn_up = digitalRead(redup);    //check button state
   if(r_btn_up == LOW && fadered >= -250) {
     if(fadered == 255) {fadered = 0;} // if fade value is 255 (off) set it to 0
     // if button is pressed increase brightness by 5
     // as long as brightness isn't greater than -250
     fadered -=5;
     analogWrite(redled, fadered);  // lights LED at current brightness level
     delay(250);  // allows time so button won't be detected multiple times
   }

// decrease brightness
   r_btn_down = digitalRead(reddown);    //check button state
   if(r_btn_down == LOW && fadered <= -5) {
     // if button is pressed decrease brightness by 5
     // as long as brightness isn't less than -5
     fadered +=5;
     if(fadered == 0) {fadered = 255;}
     // when the fade value reaches 0, 255 is stored to the fade value to turn off the LED
     analogWrite(redled, fadered);  // lights LED at current brightness level
     delay(250);  // allows time so button won't be detected multiple times
   }

 }    

Go Up