How to detect how long a button was pressed in Arduino?

Rafael Beckel picture Rafael Beckel · Sep 6, 2015 · Viewed 22.1k times · Source

How can I detect how long a button was pressed / released in Arduino and then print some custom output after that?

Answer

Rafael Beckel picture Rafael Beckel · Sep 6, 2015

Arduino can only detect the state of your button (pressed OR unpressed).

You could use a timer variable (based on this example from their docs) to save the exact time when you pressed or released the button, so you can check the difference between both variables to calculate how long it is on hold or idle.

The code should look something like this:

const int buttonPin = 2;  

int buttonState = 0;     // current state of the button
int lastButtonState = 0; // previous state of the button
int startPressed = 0;    // the moment the button was pressed
int endPressed = 0;      // the moment the button was released
int holdTime = 0;        // how long the button was hold
int idleTime = 0;        // how long the button was idle

void setup() {
  pinMode(buttonPin, INPUT); // initialize the button pin as a input
  Serial.begin(9600);        // initialize serial communication
}

void loop() {
  buttonState = digitalRead(buttonPin); // read the button input

  if (buttonState != lastButtonState) { // button state changed
     updateState();
  }

  lastButtonState = buttonState;        // save state for next loop
}

void updateState() {
  // the button has been just pressed
  if (buttonState == HIGH) {
      startPressed = millis();
      idleTime = startPressed - endPressed;

      if (idleTime >= 500 && idleTime < 1000) {
          Serial.println("Button was idle for half a second");
      }

      if (idleTime >= 1000) {
          Serial.println("Button was idle for one second or more"); 
      }

  // the button has been just released
  } else {
      endPressed = millis();
      holdTime = endPressed - startPressed;

      if (holdTime >= 500 && holdTime < 1000) {
          Serial.println("Button was hold for half a second"); 
      }

      if (holdTime >= 1000) {
          Serial.println("Button was hold for one second or more"); 
      }

  }
}

However, if you want to trigger an event while the button is still pressed (or maybe you want to increment a counter in some display), you can still do the same math.

Change your condition in the loop function to be like this:

  if (buttonState != lastButtonState) { 
     updateState(); // button state changed. It runs only once.
  } else {
     updateCounter(); // button state not changed. It runs in a loop.
  }

And then implement your new function:

void updateCounter() {
  // the button is still pressed
  if (buttonState == HIGH) {
      holdTime = milis() - startPressed;

      if (holdTime >= 1000) {
          Serial.println("Button is hold for more than a second"); 
      }

  // the button is still released
  } else {
      idleTime = milis() - endPressed;

      if (idleTime >= 1000) {
          Serial.println("Button is released for more than a second");  
      }
  }
}