RGB LED: using long and short presses of a momentary

Greetings everyone! I am working on a project and I’m hoping you all can help me out…

I guess I’ll start with a piece of the puzzle and slowly work other bits in…

int buttonInt = 0; //Pin 2
int redPin = 11;
int greenPin = 10;
int bluePin = 9;

 
void setup()
{
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);  

}

void loop(){
}

The idea is, start off low, if the button is long pressed (2sec) Set all 3 colors to 255 (white).

If you short press, switch the color to red.
Long press turns it off

Hmm, this is sounding more complicated than I want it to…

Off
If longpress, goto on
On 
White
if shortpress, goto red
If longpress, goto off
Red
if shortpress, goto green
If longpress, goto off
Green
if shortpress, goto blue
If longpress, goto off
Blue
if shortpress, goto white
If longpress, goto off

Obviously not perfect, but I think it makes the idea easier to visualize? Longpress for on/off, shortpress to cycle colors? That may be easier…

Can anyone help me with the coding for this?

Edit:

I’m looking at what another member posted on a different thread to see if it can apply to what I’m wanting to do:

int held = 0;
while (digitalRead(button) == HIGH[glow] && held < 10[/glow])
{
  delay(100);
  held++;
}
if (held < 10)
  A;  // the button was released in less than a second
else
  B;  // a second has passed, note that the button may still be down

Do not use delay. Use the millis() function to record the time the button is pressed. Then if the millis timer reaches greater than a threshold value above what it was when the button was first pressed then it is a long press, if released befor this then it is a short press. Note all variables involved in holding millis values should be of the unsigned long type.

I'm just starting out, can you start me down the road with an example? Does this need to interrupt the loop?

There is something you need to figure out first - it is obvious, but not necessarily what you think of first up.

The difference between a short press and a long one, is only determined when the button is released.

So you need to decide in each situation, what should happen when the button is first pressed, and whether or how you change that when it is released.

So I think you need to carefully plan out your sequence ("state machine") a little better first in terms of these three actions at each step - button pressed, button released short, button released long.

And incidentally - you used the term "interrupt". Do be careful - interrupts are a special function in the microcontroller that has no relevance whatsoever to your present purpose.

sydcomebak: I'm just starting out, can you start me down the road with an example?

This is an advanced topic and is not suitable for some on first starting out. I know you might not think it is, but it is. To show you what is needed then see my:- http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html Or Robin2's several things at once http://forum.arduino.cc/index.php?topic=223286.0 For information about using the millis timer

Does this need to interrupt the loop?

No.

Are you suggesting something like this?

unsigned long before, after;

int buttonInt = 0; //Pin 2
int redPin = 11;
int greenPin = 10;
int bluePin = 9;

int CurrentColor = 0; //white=0,Red=1,Blue=2,Green=3
int threshold = 2000; //2000milisec = 2sec

 
void setup()
{
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);  

}

void loop(){

//button is pressed
before = millis()
//start a loop taking millis() and storing them in "after" while button is still down

while buttondown
after = millis()
if after - before > threshold then goto longpress
else goto shortpress

shortpress
If color <3 then CurrentColor = CurrentColor+1
else CurrentColor = 0
Output color to LED

Longpress
cycle power
  
}

Are you suggesting something like this?

Well something similar to that but something that : 1) Actually compiles so you can run it. This means getting the syntax right. 2) This bit is not right

while buttondown
after = millis()
if after - before > threshold then goto longpress
else goto shortpress

this is because it will never get to go to longpress because the first time it is tested and fails it will go to shortpress. maybe

while buttondown { do nothing but look at the button }
after = millis()
if after - before > threshold then goto longpress
else goto shortpress

or better still

while (buttondown) { // do the code until the next {
check if the button is still down
if millis() - before > threshold then goto longpress
} // end of the while structure

goto shortpress

Note to all others, this is not real code it is pseudo code. Also you never use a goto statement in C. If you do have a solid nailed on reason to use a goto in C code then there is a lot you don't understand.

OK, I can work on better pseudo-code, but the problem remains that I don't have a working example to modify for my purposes.

I definitely don't want someone to do all the work for me, but I need some working code to expand on. I'll post more later today while my kids nap.

but the problem remains that I don't have a working example to modify for my purposes.

I definitely don't want someone to do all the work for me, but I need some working code to expand on.

But if you have a working example then the work has been done for you hasn't it?

I could give you and example of a button that when you held it down for longer than a certain period it would auto increment at a certain rate. But the critical code while commented is mixed in with what other buttons are trying to do so my guess is that you would never understand it.

There is always this:-

Long / short button press

Grumpy_Mike: But if you have a working example then the work has been done for you hasn't it?

...

There is always this:-

Long / short button press

Funny how many of those links are purple from me reading them prior to posting... Most are based on the delay() function not millis().

At this point I feel like you're frustrated or just playing with me. Eventually I guess I'll figure it out, I thought I'd try not to re-invent the wheel if someone has done it before and could explain it well.

I thought I'd try not to re-invent the wheel if someone has done it before

If you can not re-invent the wheel then you can not invent anything.

At this point I feel like you're frustrated or just playing with me.

No not playing, I am trying to teach you something. Although the response of "just send me a working example" is a little exasperating. I find it the same as being asked to "do it for me" which you claim not to want.

and could explain it well.

If you don't understand anything in my explanation then please ask, that is what I am here for.

What I meant by a working example is:

"Given your setup, this will turn on your LED white with a 3sec press:"

From that, I think I could do all the loops, color changes, etc, etc... As I said in my first post, this is just a bite of what my actual project is. I simplified it as much as I could.

So far, I have:

const int buttonPin = 2; //Pin 2
const int redPin = 11;
const int greenPin = 10;
const int bluePin = 9;

int CurrentColor = 0; //white=0,Red=1,Green=2,Blue=3,Yellow=4,Purple=5
int threshold = 2000; //2000milisec = 2sec
int buttonState = 0; 

unsigned long BUTT_Press = 0;
unsigned long BUTT_Release = 0;
unsigned long NOW = 0;  

void setup()
{
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);  
  pinMode(buttonPin, INPUT);
  analogWrite(redPin, 255);
  analogWrite(greenPin, 255);
  analogWrite(bluePin, 255);}

void loop() {
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
    BUTT_Press = millis();
    // turn LED on:
if (CurrentColor == 0) {
  analogWrite(redPin, 0);
  analogWrite(greenPin, 0);
  analogWrite(bluePin, 0);
}
if (CurrentColor == 1) {
  analogWrite(redPin, 0);
  analogWrite(greenPin, 255);
  analogWrite(bluePin, 255);
}
if (CurrentColor == 2) {
  analogWrite(redPin, 255);
  analogWrite(greenPin, 0);
  analogWrite(bluePin, 255);
}
if (CurrentColor == 3) {
  analogWrite(redPin, 255);
  analogWrite(greenPin, 255);
  analogWrite(bluePin, 0);
}
if (CurrentColor == 4) {
  analogWrite(redPin, 0);
  analogWrite(greenPin, 0);
  analogWrite(bluePin, 255);
}
if (CurrentColor == 5) {
  analogWrite(redPin, 0);
  analogWrite(greenPin, 255);
  analogWrite(bluePin, 0);
}
    } 
}

Which turns on the LED white when I tap the button. I want to modify this to only turn on the LED if the button is held 3sec.

This works so far...

const int buttonPin = 2; //Pin 2
const int redPin = 11;
const int greenPin = 10;
const int bluePin = 9;

int CurrentColor = 0; //White=0,Red=1,Green=2,Blue=3,Yellow=4,Purple=5
int threshold = 2000; //2000milisec = 2sec
int duration = 0; //How long the button was high
int buttonState = 0; 
int buttonStatus = 0;
unsigned long BUTT_Press = 0;
unsigned long BUTT_Held = 0;
unsigned long BUTT_Release = 0;
unsigned long NOW = 0;  

void setup()
{
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);  
  pinMode(buttonPin, INPUT);
  analogWrite(redPin, 255);
  analogWrite(greenPin, 255);
  analogWrite(bluePin, 255);}

void loop() 
{
  buttonState = digitalRead(buttonPin);
    if (buttonState == LOW) 
    {
      buttonStatus=0;
      BUTT_Release = millis();
      if (duration >= 3000)
      {
        // turn LED on:
        if (CurrentColor == 0) {analogWrite(redPin, 0);analogWrite(greenPin, 0);analogWrite(bluePin, 0);}
        if (CurrentColor == 1) {analogWrite(redPin, 0);analogWrite(greenPin, 255);analogWrite(bluePin, 255);}
        if (CurrentColor == 2) {analogWrite(redPin, 255);analogWrite(greenPin, 0);analogWrite(bluePin, 255);}
        if (CurrentColor == 3) {analogWrite(redPin, 255);analogWrite(greenPin, 255);analogWrite(bluePin, 0);}
        if (CurrentColor == 4) {analogWrite(redPin, 0);analogWrite(greenPin, 0);analogWrite(bluePin, 255);}
        if (CurrentColor == 5) {analogWrite(redPin, 0);analogWrite(greenPin, 255);analogWrite(bluePin, 0);}
      } 
    }  
    
  if (buttonState == HIGH)
  {
    if (buttonStatus==0)
    {
      BUTT_Press = millis();
    }
    if (buttonStatus==1)
    {  
      BUTT_Held = millis();
      duration = BUTT_Held - BUTT_Press;
    }
    buttonStatus=1;
  }
}

Now a 3sec press turns it on, and a 3sec press turns it off:

const int buttonPin = 2; //Pin 2
const int redPin = 11;
const int greenPin = 10;
const int bluePin = 9;

int CurrentColor = 0; //White=0,Red=1,Green=2,Blue=3,Yellow=4,Purple=5, Off=6
int threshold = 2000; //2000milisec = 2sec
int duration = 0; //How long the button was high
int buttonState = 0; 
int buttonStatus = 0;
int LEDStatus = 0;

unsigned long BUTT_Press = 0;
unsigned long BUTT_Held = 0;
unsigned long NOW = 0;  

void setup()
{
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);  
  pinMode(buttonPin, INPUT);
  analogWrite(redPin, 255);
  analogWrite(greenPin, 255);
  analogWrite(bluePin, 255);}

void loop() 
{
  buttonState = digitalRead(buttonPin);
    if (buttonState == LOW) 
    {
      buttonStatus=0;
      if (duration >= 3000 && LEDStatus ==0) 
      {
          // turn LED on WHITE:
          analogWrite(redPin, 0);
          analogWrite(greenPin, 0);
          analogWrite(bluePin, 0);
          LEDStatus = 1;
          duration = 0;
      }
      if (duration >= 3000 && LEDStatus ==1) 
      {
          // turn LED on WHITE:
          analogWrite(redPin, 255);
          analogWrite(greenPin, 255);
          analogWrite(bluePin, 255);
          LEDStatus = 0;
          duration = 0;
      }
    }
  if (buttonState == HIGH)
  {
    if (buttonStatus==0)
    {
      BUTT_Press = millis();
    }
    else
    {  
      BUTT_Held = millis();
      duration = BUTT_Held - BUTT_Press;
    }
    buttonStatus=1;
  }
}

Won't that last code just flash the LEDs with a 3 second duration if you hold the button down?

There are several things to to:- 1) You are just looking to see if the button is held down. What you want to do is to see when the button is first pressed. You do this by having a variable that holds the state of the button the last time round the loop. Then when the state of the button this time is low and last time was high, the button is being pressed for the first time. Now is the time to set duration to the value in the millis counter and maybe set a Boolean variable to show that the count is now on. Then, when this variable is set, look at the button repeatedly and if it is low, check that the duration has not exceeded your threshold time. If it has then do the long function. If however the button comes up before this has happened do the short function.

Funny how many of those links are purple from me reading them prior to posting.

Well if you take the top hit of that search and look at reply #11 you will see code that is very close to what you want.

Try this type of code define your switch and the variable
int varSWITCH_PIN = 0; //variable to store switch presses

if (digitalRead(SWITCH_PIN) == LOW)
{
time = millis();
delay(200); //debounce

// check if the switch is pressed for longer than 1 second.
if(digitalRead(SWITCH_PIN) == LOW && time - millis() >1000)

{
varSWITCH_PIN++; //add 1 Step to next Mode in setup
if(varSWITCH_PIN==8){varSWITCH_PIN=0;} //switch back to 0 after the required modes

// if it is a short press <1000
} else
do something

}

This would be great if I understood why these commands were chosen, but there was absolutely no explanation for why this works.

Again, I didn’t want it done FOR me. I want to learn how to do it. What I threw together was about 2-3hrs of logic mapping in my head and guess & check work.

This would be great if I understood why these commands were chosen,

The commands were chosen to do the job. There are many ways to code this problem and this is just one of them.

Now you need to read this code like you read words in a book. Each command does something, if you don’t know what it does then look it up in the reference page of the IDE. Some lines are a combination of lots of commands so you have to separate them out. This is why I said that this was not a beginners project.

Sorry I did write a lot trying to explain that code, but the more I wrote the more mistakes I found and so now I think it is not worth trying to correct. It looked fine on first glance but there is a lot wrong with it when you look in detail. Sorry for misleading you.

Note when posting code use the </> icon

Reply #3 in this thread looks good http://forum.arduino.cc/index.php?topic=140123.0 But again you need to understand it to make sense of it. That is why I think it is best if you try and build up the code yourself with help where needed.

OK, so the code I worked out myself and then posted KINDA worked. I need help to make it work. Can you do that?

const int buttonPin = 2; //Pin 2
const int redPin = 11;
const int greenPin = 10;
const int bluePin = 9;

int CurrentColor = 0; //White=0,Red=1,Green=2,Blue=3,Yellow=4,Purple=5, Off=6
int threshold_long = 3000; //3000millisec = 3sec
int threshold_short = 500; //500millisec = .5sec
int duration = 0; //How long the button was high
int buttonState = 0; 
int buttonStatus = 0;
int LEDStatus = 0;

unsigned long BUTT_Press = 0;
unsigned long BUTT_Held = 0;

void setup()
{
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);  
  pinMode(buttonPin, INPUT);
  analogWrite(redPin, 255);
  analogWrite(greenPin, 255);
  analogWrite(bluePin, 255);}

void loop() 
{
  buttonState = digitalRead(buttonPin);
    if (buttonState == LOW) 
    {
      buttonStatus = 0;
      if (duration <=threshold_short && LEDStatus==1)
      {
        CurrentColor=CurrentColor+1; 
        if (CurrentColor>3)
        {
          CurrentColor=0;
        }
        if (CurrentColor == 0)
        {
          analogWrite(redPin, 0);
          analogWrite(greenPin, 0);
          analogWrite(bluePin, 0);
        }
        if (CurrentColor == 1)
        {
          analogWrite(redPin, 0);
          analogWrite(greenPin, 255);
          analogWrite(bluePin, 255);
        }
        if (CurrentColor == 2)
        {
          analogWrite(redPin, 255);
          analogWrite(greenPin, 0);
          analogWrite(bluePin, 255);
        }
        if (CurrentColor == 3)
        {
          analogWrite(redPin, 255);
          analogWrite(greenPin, 255);
          analogWrite(bluePin, 0);
        }
        duration = 0;
      }
      if (duration >= threshold_long && LEDStatus ==0) 
      {
          // turn LED on WHITE:
          analogWrite(redPin, 0);
          analogWrite(greenPin, 0);
          analogWrite(bluePin, 0);
          LEDStatus = 1;
          duration = 0;
          CurrentColor=0;
      }
      if (duration >= threshold_long && LEDStatus ==1) 
      {
          // turn LED off:
          analogWrite(redPin, 255);
          analogWrite(greenPin, 255);
          analogWrite(bluePin, 255);
          LEDStatus = 0;
          duration = 0;
      }
    }
  
  if (buttonState == HIGH)
  {
    if (buttonStatus==0)
    {
      BUTT_Press = millis();
    }
    else
    {  
      BUTT_Held = millis();
      duration = BUTT_Held - BUTT_Press;
    }
    buttonStatus=1;
  }
}