Trying to make a short and long press function with button

Trying to make functions for a short and long button press, my button is already working, but this won't work

buttonState = digitalRead(buttonPin);

  if (buttonState == HIGH) {
    if (!debounce) {  
      debounce = true;  
      last_clicked = millis();
      
      {delay(1);} while (buttonState == HIGH);

      if (millis() - last_clicked >= click_pause) {
        if (adding) {
          adding = false;
          digitalWrite(Led_Subtract, HIGH);
        } else {
          adding = true;
          digitalWrite(Led_Subtract, LOW);  
        }
      } else {
        if (adding) {
          number += 1;
        } else {
          number -= 1;
        }
        delay(pause);  
      }
      debounce = false;  
    }
  } else {
    debounce = false;  
  }

looks a little complicated. a 20 msec delay usually takes care of debouncing.

to recognize short/long pressed, capture the timestamp when a button is pressed. it's a long press if the time expires before the button is released and it's a short press if the button is release before it expires

careful, you want to recognize each as a single event

What is the purpose of this?

Hi @r0botixmaster ,

here is a method to register the time a button is down:

/*
  Forum: https://forum.arduino.cc/t/trying-to-make-a-short-and-long-press-function-with-button/1221545
  Wokwi: https://wokwi.com/projects/389182520812865537

  2024/02/08
  ec2021

*/

const byte buttonPin = 2;
unsigned long pressTime = 0;

void setup() {
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP);
  Serial.println("Start");
}

void loop() {
  // put your main code here, to run repeatedly:
  if (buttonReleased(pressTime)) {
    Serial.println(pressTime);
  }
}


boolean buttonReleased(unsigned long &buttonPressTime) {
  static unsigned long downTime;
  static unsigned long lastChange = 0;
  static byte lastState = HIGH;
  static byte state = HIGH;
  byte actState = digitalRead(buttonPin);
  if (actState != lastState) {
    lastChange = millis();
    lastState = actState;
  }
  if (actState != state && millis() - lastChange > 20) {
    state = actState;
    if (state) {
      buttonPressTime = millis() - downTime;
    } else {
      downTime = millis();
    }
    return (state);
  }
  return false;
}

On Wokwi: https://wokwi.com/projects/389182520812865537

It is the general function for debouncing, returns true on a change from LOW to HIGH and the press time is made available in the parameter.

If you just want "short" or "long" press you can modify buttonReleased() for this purpose.

BTW: The function is non-blocking of course!

Good luck!

P.S.: And here a version that returns short or long press information based on the same principle

Sketch

To be found on Wokwi: [https://wokwi.com/projects/389183114221981697](https://wokwi.com/projects/389183114221981697)

/*
  Forum: https://forum.arduino.cc/t/trying-to-make-a-short-and-long-press-function-with-button/1221545
  Wokwi: https://wokwi.com/projects/389183114221981697

  2024/02/08
  ec2021

*/

enum buttonPressType {
  IDLE,
  SHORTPRESS,
  LONGPRESS
};

const byte buttonPin = 2;
const unsigned long shortPressThreshold = 200;


void setup() {
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP);
  Serial.println("Start");
}

void loop() {
  // put your main code here, to run repeatedly:
  switch (buttonReleased()) {
    case SHORTPRESS:
      Serial.println("Short");
      break;
    case LONGPRESS:
      Serial.println("Long");
      break;
  }
}

buttonPressType buttonReleased() {
  static unsigned long downTime;
  static unsigned long lastChange = 0;
  static byte lastState = HIGH;
  static byte state = HIGH;
  byte actState = digitalRead(buttonPin);
  if (actState != lastState) {
    lastChange = millis();
    lastState = actState;
  }
  if (actState != state && millis() - lastChange > 20) {
    state = actState;
    if (state) {
      if (millis() - downTime > shortPressThreshold) {
        return LONGPRESS;
      } else {
        return SHORTPRESS;
      }
    } else {
      downTime = millis();
    }
  }
  return IDLE;
}


1 Like
byte            PinBut    = A2;
byte            butState;
unsigned long   msecTimeStamp;

unsigned long msec;

// -----------------------------------------------------------------------------
#define LongPeriod  1500

enum { None, Short, Long };

int
chkBut ()
{
    byte but = digitalRead (PinBut);
    if (butState != but)  {
        butState = but;
        delay (10);     // debounce

        if (LOW == but)                                 // button pressed
            msecTimeStamp = 0 == msec ? 1 : msec;       // not zero
        // check if button released before timer expires
        else if (msecTimeStamp)  {
            msecTimeStamp = 0;
            return Short;
        }
    }
    // check if timer expires while button being pressed
    else if (LOW == but)  {
        if (msecTimeStamp && (msec - msecTimeStamp > LongPeriod))  {
            msecTimeStamp = 0;
            return Long;
        }
    }

    return None;
}

// -----------------------------------------------------------------------------
void
loop ()
{
    msec = millis ();

    switch (chkBut ())  {
    case Short:
        Serial.println (" short");
        break;

    case Long:
        Serial.println (" long");
        break;
    }
}

// -----------------------------------------------------------------------------
void
setup ()
{
    Serial.begin (9600);
    pinMode (PinBut, INPUT_PULLUP);
    butState = digitalRead (PinBut);
}
1 Like

thanks for the responses guys:

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);

  Serial.begin(9600);
}
const int buttonPin = 2;
int buttonState = 0;  

unsigned long buttonPresstime = 0;
bool buttonPressed = false;

int longClick_threshold = 1000; //the amount of time considered a 'long' click
int last_clicked = 0;

bool debounce = false;
bool debounce1 = false;

bool adding = true;

int pause = 1000;

void loop(){
bool buttonState = digitalRead(buttonPin);

  // Check if the button is pressed
  if (buttonState == HIGH && !buttonPressed) {//if buttonstate = high and not 'buttonPressed' 
    if (!debounce) { // if debounce = false
      debounce = true;
      buttonPresstime = millis(); //logs the moment button is pressed
      buttonPressed = true;       // Set the flag to indicate button press
    }
  }

  //check if button is released
  if (buttonState == LOW && buttonPressed) {//if button released and 'buttonpressed' is true
    if (debounce && !debounce1) { //if debounce = true and if debounce 1 = false
      debounce1 = true;
      
      unsigned long buttonReleaseTime = millis(); //just logs the moment button is released
      buttonPressed = false;                  

      //checks how long the button was pressed for
      unsigned long pressDuration = buttonReleaseTime - buttonPresstime;

      if (pressDuration < longClick_threshold) {
        // Short press
        Calculate();
        Serial.println("Short press");
      } else {
        // Long press

        if (adding) {
          adding = false;
          digitalWrite(Led_Subtract, HIGH);
        } else {
          adding = true;
          digitalWrite(Led_Subtract, LOW);
        }

        Serial.println("Long press");
      }
      delay(pause);
      debounce = false;
      debounce1 = false;
    }
  }

}

void Calculate() {
  if (adding) {
    number += 1;
  } else {
    number -= 1;
  }
}

won't this code immediately perform the above without waiting for a button release and knowing whether the button was pressed for a short or long period?

no because the debounce will prevent that

does this code compile? where's loop()?
did you test it?

yea it does work, forgot to add loop in the solution though

i get false Long press events before releasing the button due to bounce

i'm not sure why, this is what my full code looks like, and it works fine:

/*
  Binary counter
*/

int Led_8 = 8; //Green
int Led_4 = 9; //Blue
int Led_2 = 10; //White
int Led_1 = 7; //Red

int Led_Subtract = 12;

int binary_number = 0;
int number = 0;

int Delay = 750;
int Blink = 100;
int pause = 1000;

const int buttonPin = 2;
int buttonState = 0;  

unsigned long buttonPresstime = 0;
bool buttonPressed = false;

int longClick_threshold = 1000;
int last_clicked = 0;

bool debounce = false;
bool debounce1 = false;

bool adding = true;

void setup() {
  pinMode(Led_8, OUTPUT);
  pinMode(Led_4, OUTPUT);
  pinMode(Led_2, OUTPUT);
  pinMode(Led_1, OUTPUT);

  pinMode(Led_Subtract, OUTPUT);

  pinMode(buttonPin, INPUT_PULLUP);

  Serial.begin(9600);
}

void loop() {

  if (number < 1) {
    digitalWrite(Led_1, LOW);
    digitalWrite(Led_2, LOW);
    digitalWrite(Led_4, LOW);
    digitalWrite(Led_8, LOW);
  }

  if (number == 1) {
    digitalWrite(Led_1, HIGH);
    
    digitalWrite(Led_2, LOW);
    digitalWrite(Led_4, LOW);
    digitalWrite(Led_8, LOW);
    binary_number = 1;
  }

  if (number == 2) {
    digitalWrite(Led_2, HIGH);

    digitalWrite(Led_1, LOW);
    digitalWrite(Led_4, LOW);
    digitalWrite(Led_8, LOW);
    binary_number = 2;
  }

  if (number == 3) {
    digitalWrite(Led_1, HIGH);
    digitalWrite(Led_2, HIGH);

    digitalWrite(Led_4, LOW);
    digitalWrite(Led_8, LOW);
    binary_number = 3;
  }

  if (number == 4) {
    digitalWrite(Led_4, HIGH);

    digitalWrite(Led_1, LOW);
    digitalWrite(Led_2, LOW);
    digitalWrite(Led_8, LOW);
    binary_number = 4;
  }

  if (number == 5) {
    digitalWrite(Led_1, HIGH);
    digitalWrite(Led_4, HIGH);

    digitalWrite(Led_2, LOW);
    digitalWrite(Led_8, LOW);
    binary_number = 5;
  }

  if (number == 6) {
    digitalWrite(Led_2, HIGH);
    digitalWrite(Led_4, HIGH);

    digitalWrite(Led_1, LOW);
    digitalWrite(Led_8, LOW);
    binary_number = 6;
  }

  if (number == 7) {
    digitalWrite(Led_1, HIGH);
    digitalWrite(Led_2, HIGH);
    digitalWrite(Led_4, HIGH);

    digitalWrite(Led_8, LOW);
    binary_number = 7;
  }

  if (number == 8) {
    digitalWrite(Led_8, HIGH);

    digitalWrite(Led_1, LOW);
    digitalWrite(Led_2, LOW);
    digitalWrite(Led_4, LOW);
    binary_number = 8;
  }

  if (number == 9) {
    digitalWrite(Led_1, HIGH);
    digitalWrite(Led_8, HIGH);

    digitalWrite(Led_2, LOW);
    digitalWrite(Led_4, LOW);
    binary_number = 9;
  }

  if (number == 10) {
    digitalWrite(Led_2, HIGH);
    digitalWrite(Led_8, HIGH);

    digitalWrite(Led_1, LOW);
    digitalWrite(Led_4, LOW);
    binary_number = 10;
  }

  if (number == 11) {
    digitalWrite(Led_1, HIGH);
    digitalWrite(Led_2, HIGH);
    digitalWrite(Led_8, HIGH);

    digitalWrite(Led_4, LOW);
    binary_number = 11;
  }

  if (number == 12) {
    digitalWrite(Led_4, HIGH);
    digitalWrite(Led_8, HIGH);


    digitalWrite(Led_1, LOW);
    digitalWrite(Led_2, LOW);
    binary_number = 12;
  }

  if (number == 13) {
    digitalWrite(Led_1, HIGH);
    digitalWrite(Led_4, HIGH);
    digitalWrite(Led_8, HIGH);

    digitalWrite(Led_2, LOW);
    binary_number = 13;
  }

  if (number == 14) {
    digitalWrite(Led_2, HIGH);
    digitalWrite(Led_4, HIGH);
    digitalWrite(Led_8, HIGH);

    digitalWrite(Led_1, LOW);
    binary_number = 14;
  }

  if (number == 15) {
    digitalWrite(Led_1, HIGH);
    digitalWrite(Led_2, HIGH);
    digitalWrite(Led_4, HIGH);
    digitalWrite(Led_8, HIGH);
    binary_number = 15;
  }

  if (number > 15) {
    digitalWrite(Led_1, LOW);
    digitalWrite(Led_2, LOW);
    digitalWrite(Led_4, LOW);
    digitalWrite(Led_8, LOW);
    number = 0;
  }

  bool buttonState = digitalRead(buttonPin);

  // Check if the button is pressed
  if (buttonState == HIGH && !buttonPressed) {
    if (!debounce) {
      debounce = true;
      buttonPresstime = millis();  
      buttonPressed = true;       // Set the flag to indicate button press
    }
  }

  //check if button is released
  if (buttonState == LOW && buttonPressed) {
    if (debounce && !debounce1) {
      debounce1 = true;
      
      unsigned long buttonReleaseTime = millis();  
      buttonPressed = false;                  

      unsigned long pressDuration = buttonReleaseTime - buttonPresstime;  

      if (pressDuration < longClick_threshold) {
        // Short press
        Calculate();
        Serial.println("Short press");
      } else {
        // Long press

        if (adding) {
          adding = false;
          digitalWrite(Led_Subtract, HIGH);
        } else {
          adding = true;
          digitalWrite(Led_Subtract, LOW);
        }

        Serial.println("Long press");
      }
      delay(pause);
      debounce = false;
      debounce1 = false;
    }
  }
}


void Calculate() {
  if (adding) {
    number += 1;
  } else {
    number -= 1;
  }
}

You could reduce the code that tests the value of number and sets the state of the 4 LEDs to a single line of code if you put the LED states in an array of 4 byte values indexed by the value of the number variable

EDIT
Or even better, just use the value of the bits in the number variable to set the state of the 4 LEDs

An example of the latter suggestion

const byte ledPins[] = { 3, 5, 6, 9 };

void setup()
{
    Serial.begin(115200);
    for (int c = 0; c < 4; c++)
    {
        pinMode(ledPins[c], OUTPUT);
        digitalWrite(ledPins[c], LOW);  //turn off the LEDs
    }
}

void loop()
{
    for (int z = 0; z < 16; z++)
    {
        setLeds(z);
        delay(500);
    }
}

void setLeds(byte num)
{
    for (int x = 0; x < 4; x++)
    {
        digitalWrite(ledPins[x], bitRead(num, x));
    }
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.