Button short and long press without library

I'm trying to detect independently short and long presses of a button with debounce and not using a library. Long press is detected while button held, not on release. I've simulated the following code in Wokwi and sometimes get a short indication after a long indication. Is there a simpler or more efficient way of doing this?

void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT_PULLUP); // button to gnd
}

void loop() {
  // button hold with debounce
  static unsigned long  holdTime;
  static bool press, hold;
  if ( digitalRead(2) == LOW && press == false) {
    // one time on button press - on bounce first low
    holdTime = millis();
    press = true;
  }
  // only after bounce period check for button release
  if (millis() - holdTime > 300) {
    if (digitalRead(2) == HIGH && press == true && hold == false) {
      holdTime = millis();
      press = false;
      Serial.println("Short");
    }
  }
  // if button remains held for period
  if (millis() - holdTime > 1000) {
    if (digitalRead(2) == LOW && press == true && hold == false) {
      press = false;
      hold = true;
      holdTime = millis();
      Serial.println("Long");
    }
    // inhibit retrigger
    if (digitalRead(2) == HIGH && hold == true && millis() - holdTime > 1000) {
      press = false;
      hold = false;
    }
  }
}

Wokwi simulation

This is for "long"

This is for "short"

1000 > 300 and when holdtime > 1000...

This allows the press release to be registered as "short"

Hello mazellan

Welcome back :slight_smile:

Check and test this small button manager. This sketch has to be modified to your project needs.

enum ButtonStates {Released, Pressed};
enum TimerStates {Halt, Run};
uint32_t currentMillis = millis();
constexpr uint32_t DebounceInterval = 20;
uint32_t debouncePrevious = millis();
constexpr uint8_t ButtonPin = A0;
uint8_t stateOld = LOW;
constexpr uint32_t ClickInterval = 1000;
uint32_t clickPrevious = 20;
uint8_t clickControl = LOW;
void setup()
{
  Serial.begin(9600);
  Serial.println("Button short and long press without library");
  pinMode (ButtonPin, INPUT_PULLUP);
}
void loop()
{
  currentMillis = millis();
  if (currentMillis - debouncePrevious >= DebounceInterval)
  {
    debouncePrevious = currentMillis;
    uint8_t stateNew = digitalRead(ButtonPin) ? LOW : HIGH;
    if (stateOld != stateNew)
    {
      stateOld = stateNew;
      switch (stateNew)
      {
        case Pressed:
          Serial.println("Pressed");
          clickPrevious = currentMillis;
          clickControl = Run;

          break;
        case Released:
          Serial.println("Released");
          switch (clickControl)
          {
            case Halt:
              break;
            case Run:
              clickControl = Halt;
              Serial.println("pressed short");
              break;
          }
          break;
      }
    }
  }
  if (currentMillis - clickPrevious >= ClickInterval  and clickControl)
  {
    clickControl = Halt;
    Serial.println("pressed long");
  }
}

Have a nice day and enjoy coding in C++.

1 Like

Is your middle name Stefan.
I share knowledge so that the TO becomes curious to learn new things.
That's the purpose of this forum.
And if you don't like it, just ignore my well-intentioned programme examples!

1 Like

Thanks for that, it does exactly what I want, and I learnt some new C++ stuff too!

1 Like

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