0

I have an RGB LED common Anode attached to my Uno and this code detects a long press to turn the LED on and off. Short presses cycle through colors, then off.

The problem is that a longpress is 2+sec, but it doesn't register until I release the button. How would I set this up to execute the code at 2sec regardless of whether the button is released?

It's probably not worth my time if it requres too much modification. I have a working item, it's just not... ideal.

Xhunsigned long keyPrevMillis = 0;
const unsigned long keySampleIntervalMs = 25;

int redPin = 11;
int greenPin = 10;
int bluePin = 9;
int LEDcolor=0; // 0=White, 1=Red, 2=Green, 3-Blue, 4=Yellow, 5=Purple, 6=Pink, 7=Orange, 8=Off 
int LEDstatus =0; //0=Off, 1=On
int changed =0; //has the LEDstatus just changed?
byte longKeyPressCountMax = 80;    // 80 * 25 = 2000 ms
byte longKeyPressCount = 0;

byte prevKeyState = HIGH;         // button is active low
const byte keyPin = 2;            // button is connected to pin 2 and GND

// called when button is kept pressed for less than 2 seconds
void shortKeyPress() 
{
   Serial.println("short");
   if (LEDstatus==1)
   {
      LEDcolor = LEDcolor +1;
      if (LEDcolor==0) {analogWrite(redPin, 0);analogWrite(greenPin, 0);analogWrite(bluePin, 0);Serial.println("White");}
      if (LEDcolor==1) {analogWrite(redPin, 0);analogWrite(greenPin, 255);analogWrite(bluePin, 255);Serial.println("Red");}
      if (LEDcolor==2) {analogWrite(redPin, 255);analogWrite(greenPin, 0);analogWrite(bluePin, 255);Serial.println("Green");}
      if (LEDcolor==3) {analogWrite(redPin, 255);analogWrite(greenPin, 255);analogWrite(bluePin, 0);Serial.println("Blue");}
      if (LEDcolor==4) {analogWrite(redPin, 0);analogWrite(greenPin, 0);analogWrite(bluePin, 255);Serial.println("Yellow");}
      if (LEDcolor==5) {analogWrite(redPin, 175);analogWrite(greenPin, 255);analogWrite(bluePin, 175);Serial.println("Purple");}
      if (LEDcolor==6) {analogWrite(redPin, 0);analogWrite(greenPin, 255);analogWrite(bluePin, 155);Serial.println("Pink");}
      if (LEDcolor==7) {analogWrite(redPin, 5);analogWrite(greenPin, 215);analogWrite(bluePin, 255);Serial.println("Orange");}
      if (LEDcolor==8) {analogWrite(redPin, 255);analogWrite(greenPin, 255);analogWrite(bluePin, 255);Serial.println("Off");LEDstatus=0;}
   }
}

// called when button is kept pressed for more than 2 seconds
void longKeyPress() 
{
   Serial.println("long");
   if (LEDstatus==0 && changed==0)
   {
      analogWrite(redPin, 0);
      analogWrite(greenPin, 0); 
      analogWrite(bluePin, 0);
      LEDcolor=0;
      changed=1;
      LEDstatus=1;Serial.println("On");
   }
   if (LEDstatus==1 && changed==0)
   {
      analogWrite(redPin, 255);
      analogWrite(greenPin, 255); 
      analogWrite(bluePin, 255);
      LEDcolor=0;
      changed=1;
      LEDstatus=0;Serial.println("Off");
   }
   changed=0;
}

// called when key goes from not pressed to pressed
void keyPress() {
   Serial.println("key press");
   longKeyPressCount = 0;
}


// called when key goes from pressed to not pressed
void keyRelease() {
   Serial.println("key release");

   if (longKeyPressCount >= longKeyPressCountMax) {
      longKeyPress();
   }
   else {
      shortKeyPress();
   }
}

void setup() 
{
   Serial.begin(9600);
   pinMode(keyPin, INPUT);
   digitalWrite(keyPin, HIGH);
   pinMode(redPin, OUTPUT);
   pinMode(greenPin, OUTPUT);
   pinMode(bluePin, OUTPUT); 
   analogWrite(redPin, 255);
   analogWrite(greenPin, 255); 
   analogWrite(bluePin, 255);
}

void loop() {
// key management section
   if (millis() - keyPrevMillis >= keySampleIntervalMs) {
      keyPrevMillis = millis();

      byte currKeyState = digitalRead(keyPin);

      if ((prevKeyState == HIGH) && (currKeyState == LOW)) {
         keyPress();
      }
      else if ((prevKeyState == LOW) && (currKeyState == HIGH)) {
         keyRelease();
      }
      else if (currKeyState == LOW) {
         longKeyPressCount++;
      }

      prevKeyState = currKeyState;
   }
}
1
  • The button watcher will have to become aware of time, or be able to be alerted that the short-press time has been exceeded. How much trouble and whether it's worth it is up to your own cost (labor) vs. benefit preference, but it's probably a worthwhile learning exercise.
    – JRobert
    Jan 21, 2016 at 14:32

1 Answer 1

1

I've rewritten the code entirely. Not that yours was terrible, it was just easier for me to start from scratch. You are left with a very empty loop(), which I always prefer.

The code contains three 'colours' and an OFF state. You can add as many other colours as you wish: add an enumeration to _LED_STATE and then add a corresponding case(<NEW_COLOUR>) statement in LEDcontrol(). I haven't included any analogWrite() functions - or in fact any declarations for the LED pins at all - because I'm a little too lazy but it should be obvious where to put them within the case statement.

Note that in the final case() statement, the LED state is changed from green to off. This means that a short press will turn the LED off after it has cycled through all the other colours, but will stay off until a long press. If you only want long pressed to switch off/on, change line 103 to eLED_STATE = _LED_STATE_RED;, or whichever the first colour is.

#define btn 3   // button pin

#define SHORT_PRESS 100     // useful for debouncing, can be changed
#define LONG_PRESS  2000    // defines how long a 'long press' is
#define CYCLE       false
#define SHOW        true

//--// You can add new colours in this enum block
enum _LED_STATE
{
    _LED_STATE_OFF,
    _LED_STATE_RED,
    _LED_STATE_BLUE,
    _LED_STATE_GREEN
};

_LED_STATE eLED_STATE = _LED_STATE_OFF;

void setup()
{
    pinMode(btn, OUTPUT);
    LEDcontrol(SHOW);
}

void loop()
{

    if (digitalRead(btn))
        btnPressed();
}

void btnPressed()
{
    unsigned long tStart = millis();

    //--// Loop continuously while button is pressed
    while (digitalRead(btn))
    {
        //--// If LONG_PRESS is exceeded...
        if (millis() > tStart + LONG_PRESS)
        {
            //--// If LED is off, turn it on
            if (eLED_STATE == _LED_STATE_OFF)
                eLED_STATE = _LED_STATE_RED;        // Choose 'starting' colour
            //--// If LED is on, turn if off
            else
                eLED_STATE = _LED_STATE_OFF;
            //--// Update LED to display new eLED_STATE
            LEDcontrol(SHOW);
            //--// Now loop here until button is released
            while (digitalRead(btn));
        }
    }

    //--// If button is released in between the two press times
    if ((millis() > tStart + SHORT_PRESS) && (millis() < tStart + LONG_PRESS))
    {
        //--// Ignore if LED is off         ////// REMOVE ////////////////////
        if (eLED_STATE == _LED_STATE_OFF)   ////////// IF ////////////////////
            return;                         ///////////// NECESSARY //////////

        //--// Change the LED colour
        LEDcontrol(CYCLE);
        //--// Update LED to display new eLED_STATE
        LEDcontrol(SHOW);
    }

    //--// This helps to debounce; experiment with it
    delay(10);
}

void LEDcontrol(bool SHOW_OR_CYCLE)
{
    switch (eLED_STATE)
    {
        case(_LED_STATE_RED) :
        {
            if (SHOW_OR_CYCLE)
            {
                // paint it red
                return;
            }
            eLED_STATE = _LED_STATE_GREEN;
            return;
        }
        case(_LED_STATE_GREEN) :
        {
            if (SHOW_OR_CYCLE)
            {
                // paint it green
                return;
            }
            eLED_STATE = _LED_STATE_BLUE;
            return;
        }
        case(_LED_STATE_BLUE) :
        {
            if (SHOW_OR_CYCLE)
            {
                // paint it blue
                return;
            }
            //--// What happens after last colour? Next colour or OFF?
            eLED_STATE = _LED_STATE_OFF;
            return;
        }
        case(_LED_STATE_OFF) :
        {
            if (SHOW_OR_CYCLE)
            {
                // paint it black
                return;
            }
            eLED_STATE = _LED_STATE_RED;
            return;
        }
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.