Arduino. Time A Push Button Switch

Ever wanted to know how long a button switch was pressed for? No. Why you here? YES. Read on.

Here are a few examples that all basically do the same thing, time how long a switch is closed. And, although they may appear to use different methods that don’t really. All of them simply start a timer when the switch is closed and stop the timer when the switch is opened again.

Example 1

This sketch times how long a button switch is pressed and then displays the time in the serial monitor.

Once we have the time we can then use it to perform specific tasks based on the amount of time the button switch is pressed,

Example 1 Circuit

An Arduino
– D12 – button switch with 10k pull down resistor

Example 1 Sketch

The first couple of examples show the time a button switch is pressed.

What we doing?

Read the button switch pin.
Update the switchStatus variables.
If the switch has gone from OPEN to CLOSED start the timer.
If the switch has gone from CLOSED to OPEN stop the timer. Print the time.
Start again.

 
//  Sketch: Arduino - push button switch - time pressed 001
//  button switch with timer
//  Show the timer a button switch has been pressed
//  www.martyncurrey.com


//  Pins
//  D12 to push button switch with 10K ohm pull down resistor
const int PIN_PUSH_BUTTON_SWITCH = 12;
   
// variables 

// switch status. Current and previous
boolean switchState = LOW;
boolean oldSwitchState = LOW;

// used for debounce
boolean newSwitchState1 = LOW;      
boolean newSwitchState2 = LOW;     
boolean newSwitchState3 = LOW; 

// timer to record how long the switch is closed
long timer_timeStart = 0;
long timer_timeStop  = 0;

  
void setup() 
{
    Serial.begin(9600);
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    Serial.print("Uploaded: ");   Serial.println(__DATE__);
    Serial.println(" ");

    pinMode(PIN_PUSH_BUTTON_SWITCH, INPUT); 
}

 
void loop()
{
    // simple debounce
    // if all are the same value then we have a reliable reading
    // simple debounce
    newSwitchState1 = digitalRead(PIN_PUSH_BUTTON_SWITCH);      delay(1);
    newSwitchState2 = digitalRead(PIN_PUSH_BUTTON_SWITCH);      delay(1);
    newSwitchState3 = digitalRead(PIN_PUSH_BUTTON_SWITCH);

   if (  (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )
   {
        // record the old switch state and update the new switch state variables
        oldSwitchState = switchState;
        switchState = newSwitchState1;
    
    
        //  OPEN => OPEN
        if ( oldSwitchState == LOW && switchState == LOW )
        {
    		// switch is OPEN and was OPEN last time. Do nothing
        }
    
    
        //  OPEN => CLOSED
        if ( oldSwitchState == LOW && switchState == HIGH )
        {
    		// the switch has just been closed / button has been pressed.
    		// start the timer
    		timer_timeStart = millis();
    		Serial.print("Key pressed.  "); 
        }
    
        
        //  CLOSED => CLOSED
        if ( oldSwitchState == HIGH && switchState == HIGH )
        {
    		// switch is CLOSED and was CLOSED last time. Do nothing
        }
    
    
        //  CLOSED => OPEN
        if ( oldSwitchState == HIGH && switchState == LOW )
        {
    		// switch is OPEN and was CLOSED last time. 
    		// stop timer and print the time the button was pressed
    		timer_timeStop = millis();
    		Serial.print("Key was pressed for ");   
    		Serial.print(timer_timeStop - timer_timeStart ); 
    		Serial.println(" ms"); 
        }
    
        
  } // if (  (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )


    
}  // loop

Hopefully the sketch is fairly self explanatory, especially if you have seen any of the other guides.
When the switch goes from OPEN to CLOSED a timer is started.
When the switch goes from CLOSED to OPEN the timer is stopped and the time is printed in the serial monitor

The only tricky bit may be keeping track of the decision tree (the if/then logic). Using oldSwitchState and switchState with HIGH/LOW may not be that clear. We change this in the next example.

You will notice I have checks to see when the switch was OPEN and is still OPEN, and also, when the switch is CLOSED and still CLOSED. These are not required but may come in useful later.

//  OPEN => OPEN
if ( oldSwitchState == LOW && switchState == LOW )
{
   // switch is OPEN and was OPEN last time. Do nothing
}
//  CLOSED => CLOSED
if ( oldSwitchState == HIGH && switchState == HIGH )
{
  // switch is CLOSED and was CLOSED last time. Do nothing
}

Upload the sketch and open the serial monitor.

Press and hold down the button switch. “Key pressed” is displayed.

Release the button switch. The total time the button was pressed is displayed.

Let’s tidy up the code; move some of the code to functions and make loop() cleaner.
For a sketch this short using separate functions isn’t really required, however, as the sketch gets longer and longer things can quickly become messy.
Breaking the sketch in to smaller functions makes larger sketches easier to manage and should make the code easier to read.

Example 2

This example does exactly the same thing as the previous one. All we are doing is moving the code around and adding some extra status variables to make the sketch easier to read and appear a little tidier.

Example 2 Circuit

Same as example 1.

Example 2 Sketch

//  Sketch: Arduino - push button switch - time pressed 002
//  button switch with timer. Added functions
//  Show the time a button switch has been pressed
//  www.martyncurrey.com

 
//  Pins
//  D12 to push button switch with 10K ohm pull down resistor
const int PIN_PUSH_BUTTON_SWITCH = 12;
   
// Variables 
boolean switchState = LOW;
boolean oldSwitchState = LOW;

long timer_timeStart = 0;
long timer_timeStop  = 0;

int state = 0;
int oldState = 0;
const int OPEN_OPEN = 0;
const int OPEN_CLOSED = 1;
const int CLOSED_CLOSED = 2;
const int CLOSED_OPEN = 3; 


void setup() 
{
    Serial.begin(9600);
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    Serial.print("Uploaded: ");   Serial.println(__DATE__);
    Serial.println(" ");

    pinMode(PIN_PUSH_BUTTON_SWITCH, INPUT); 
}

 
void loop()
{

    state = checkSwitch();

    if (state != oldState)
    {
        oldState = state;
        dealWithChangedState(state);
        
    } // if (state != oldState)
    
   
}  // loop
  


int checkSwitch()
{
    int ret = 0;  // return value
    
    // simple debounce
    boolean newSwitchState1 = digitalRead(PIN_PUSH_BUTTON_SWITCH);      delay(1);
    boolean newSwitchState2 = digitalRead(PIN_PUSH_BUTTON_SWITCH);      delay(1);
    boolean newSwitchState3 = digitalRead(PIN_PUSH_BUTTON_SWITCH);

    if (  (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )
    {
      oldSwitchState = switchState;
      switchState = newSwitchState1;
  
      //  OPEN => OPEN
      if ( oldSwitchState == LOW && switchState == LOW )  { ret = OPEN_OPEN; }
  
      //  OPEN => CLOSED
      if ( oldSwitchState == LOW && switchState == HIGH )  { ret = OPEN_CLOSED; }      
      
      //  CLOSED => CLOSED
      if ( oldSwitchState == HIGH && switchState == HIGH )  { ret = CLOSED_CLOSED; } 
      
      //  CLOSED => OPEN
      if ( oldSwitchState == HIGH && switchState == LOW ) { ret = CLOSED_OPEN; } 
  
      return ret;
    }


} // int checkSwitch()



void dealWithChangedState(int switchState)
{
        if ( switchState == OPEN_OPEN )
        {
            // switch is OPEN and was OPEN last time
            // do nothing
        }
    
    
        if ( switchState == OPEN_CLOSED )
        {
            // the switch has just been closed / button has been pressed.
            // start the timer
            timer_timeStart = millis();
            Serial.print("Key pressed.  "); 
        }
    
        
        if ( switchState == CLOSED_CLOSED )
        {
            // switch is CLOSED and was CLOSED last time
            // do nothing
        }
    
    
        if ( switchState == CLOSED_OPEN )
        {
            // switch is OPEN and was CLOSED last time. 
            // stop timer and print the time the button was pressed
            timer_timeStop = millis();
            Serial.print("Key was pressed for ");   
            Serial.print(timer_timeStop - timer_timeStart ); 
            Serial.println(" ms"); 
        }

} // void dealWithChangedState()
 

Changes

  • Moved the switch check code to its own function.
  • Moved the code that does something with the switch change status in to its own function.
  • Added a check to see if the switch state has changed. If the switch state has not changed there is no reason do anything!

The main loop() is now quite compact.

void loop()
{
    state = checkSwitch();

    if (state != oldState)
    {
        oldState = state;
        dealWithChangedState();
    } // if (state != oldState)
    
}  // loop

The code that checks the switch is now in its own function

int checkSwitch()
{
    int ret = 0;
    
    // simple debounce
    boolean newSwitchState1 = digitalRead(pin_switch);      delay(1);
    boolean newSwitchState2 = digitalRead(pin_switch);      delay(1);
    boolean newSwitchState3 = digitalRead(pin_switch);

    if (  (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )
    {
      oldSwitchState = switchState;
      switchState = newSwitchState1;
  
      //  OPEN => OPEN
      if ( oldSwitchState == LOW && switchState == LOW )  { ret = OPEN_OPEN; }
  
      //  OPEN => CLOSED
      if ( oldSwitchState == LOW && switchState == HIGH )  { ret = OPEN_CLOSED; }      
      
      //  CLOSED => CLOSED
      if ( oldSwitchState == HIGH && switchState == HIGH )  { ret = CLOSED_CLOSED; } 
      
      //  CLOSED => OPEN
      if ( oldSwitchState == HIGH && switchState == LOW ) { ret = CLOSED_OPEN; } 
  
      return ret;
    }


} // int checkSwitch()

Added 4 new switch change status variables. These are not really required but I thought I’d give an example of using named values to show the status of something. This is a lot easier to read.

const int OPEN_OPEN = 0;
const int OPEN_CLOSED = 1;
const int CLOSED_CLOSED = 2;
const int CLOSED_OPEN = 3; 

The new switch change status variables are used when checking if the switch status has changed.

void dealWithChangedState()
{
       //  OPEN => OPEN
        if ( state == OPEN_OPEN )
        {
            // switch is OPEN and was OPEN last time
            // do nothing
        }
    
    
        if ( state == OPEN_CLOSED )
        {
            // the switch has just been closed / button has been pressed.
            // start the timer
            timer_timeStart = millis();
            //  timerIsActive = true;
            Serial.print("Key pressed.  "); 
        }
    
        
        if ( state == CLOSED_CLOSED )
        {
            // switch is CLOSED and was CLOSED last time
            // do nothing
        }
    
    
        if ( state == CLOSED_OPEN )
        {
            // switch is OPEN and was CLOSED last time. 
            // stop timer and print the time the button was pressed
            timer_timeStop = millis();
            Serial.print("Key was pressed for ");   
            Serial.print(timer_timeStop - timer_timeStart ); 
            Serial.println(" ms"); 
        }

} // void dealWithChangedState()

It should be fairly obvious what state == OPEN_CLOSED and state == CLOSED_OPEN means. If it isn’t you could try changing them to wasOPENandIsNowCLOSED and wasCLOSEDandIsNowOPEN.

Upload the new sketch and give it a go. Be amazed! It does exactly the same thing as before! We have made the loop() function smaller, yeah, and the sketch longer, woah! Sometimes, readability takes more words.

Example 3

In the above examples you will notice that the time the push button is pressed (the actual value) is no longer really available inside the loop() function. Let’s address that with a new approach. This time we have a checkSwitch() function that returns the time pressed.

Example 3 Circuit

Same as example 1.

Example 3 Sketch

//  Sketch: Arduino - push button switch - time pressed 001
//  Time how long a button switch is pressed 
//  Returns the time only after the button switch is released
//  www.martyncurrey.com

 
//  Pins
//  D12 to push button switch with 10K ohm pull down resistor

   
// Define the pins being used
const int PIN_PUSH_BUTTON_SWITCH = 12;
   
// variables 
boolean switchState = LOW;
boolean oldSwitchState = LOW;

long timer_timeStart = 0;
long timer_timeStop  = 0;
long timePressed = 0;



void setup() 
{
    Serial.begin(9600);
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    Serial.print("Uploaded: ");   Serial.println(__DATE__);
    Serial.println(" ");

    pinMode(PIN_PUSH_BUTTON_SWITCH, INPUT); 
}

 
void loop()
{
    // timePressed = the time the button switch is closed or 0 if a push / release is not complete
    timePressed = checkSwitch();

    if(timePressed > 0) 
    { 
      Serial.print("Time pressed = "); Serial.print( timePressed );Serial.println(" ms");
    }
   
}  // loop
  


long checkSwitch()
{
    long returnTime = 0;  // return value
    
    // simple debounce
    boolean newSwitchState1 = digitalRead(PIN_PUSH_BUTTON_SWITCH);      delay(1);
    boolean newSwitchState2 = digitalRead(PIN_PUSH_BUTTON_SWITCH);      delay(1);
    boolean newSwitchState3 = digitalRead(PIN_PUSH_BUTTON_SWITCH);

    if (  (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )
   {
        // record the switch state variables
        oldSwitchState = switchState;
        switchState = newSwitchState1;
    
  
        //  OPEN => CLOSED
        if ( oldSwitchState == LOW && switchState == HIGH )
        {
            // the switch has just been closed / button has been pressed
            // start the timer
            timer_timeStart = millis();
        }
    
        //  CLOSED => OPEN
        if ( oldSwitchState == HIGH && switchState == LOW )
        {
            // the switch has just been released
            // stop timer
            timer_timeStop = millis();
            returnTime = timer_timeStop - timer_timeStart ;
        }

        return returnTime;
        
  } // if (  (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )


} // int checkSwitch() 

Basically the same as before but a little cleaner. This example does not show when the push button is first pressed and so there is no user feedback to say the switch is closed.

Example 4: Multi-function Toggle Switch

Let’s try taking the last example further. By using the time pressed we can create a multi-function toggle switch.

  • First short press – turn on an LED
  • Second short press – turn of the LED
  • First long press – turn on flashing LED
  • Second long press – tuen off flash LED

marg-bot_05em

ppp

Leave a Comment