Arduino - Dual Function Button - Long Press/Short Press (Without Delay) + Bonus
by xn1ch1 in Circuits > Arduino
139767 Views, 101 Favorites, 0 Comments
Arduino - Dual Function Button - Long Press/Short Press (Without Delay) + Bonus
Using software we can take a single button and have it toggle a light on or off, or complete a more complicated function if we so desire. But what if we have two functions but still only one button? Many of us use a button like this, on smartphones for example, everyday; this is called a short press and a long press (press and hold).
The following guide will take you through all the steps needed to create a simple push button that can control the state of two separate LED's.
The Theory
First some theory. Using a button to turn on a light is simple, if the button is reading HIGH (when pressed), then we can turn the LED on by writing the output pin it's attached to HIGH as well. Once the button is reading LOW, we can then set the output pin LOW again to turn off the LED. This is what we call momentary.
For this set-up though, we are looking to toggle the LED on or off. This in it'self is a problem for the simple example above, as the loop function in Arduino repeats hundreds of times per second. Even the quickest press could toggle on and off many many times. This first problem we will overcome using a simple boolean or two, explained on the next few pages.
The second problem is the long press function. How do we trigger this function without triggering the short press function first? The answer is simple. The long press function is triggered whilst the button is being pressed, the short press function is triggered once the button is released. This can again be observed on a smart phone by releasing an object on screen just before the long press function activates.
In the next step we will be creating our hardware set-up, feel free to skip this if you are already at this stage...
The Hardware
The hardware is very straight forward, so I won't bore you too much.
First are the two LED's. We wire the anodes of each to pins 12 and 13 on the Arduino, the cathodes then go to ground.
The button is connected to 5V output and pin 3 on the Arduino, then grounded with a 10kOhm resistor.
The Software in Detail Part 1
Now to detail each step of the code. If you want to go straight to the full code, you'll find that in the step 5
Let's first look at the variables needed for this set-up, starting with the straight forward pin references.
int LED1 = 12; int LED2 = 13; int button = 3;
Next we need a few booleans. These will be used to flip the state of the LEDs on or off
boolean LED1State = false; boolean LED2State = false;
Another two booleans now. The first will be changed dependant on the state of the button; this will allow the code to detect the first loop after the button has been pressed or released. The second will serve two functions, it will allow the code to stop the long press from activating more than once, and will stop the short press function being activated when we release the button after a long press.
boolean buttonActive = false; boolean longPressActive = false;
Finally the two last variables. The first variable is used to record the time the button is first pressed. The second variable, is the length of time (in milliseconds) you wish to have the button held down for, to activate the long press function. This can be changed to a figure of your choosing.
long buttonTimer = 0; long longPressTime = 250;
Now for the set-up, this is again very straight forward, we are simply setting the pin modes.
void setup() { pinMode(LED1, OUTPUT); pinMode(LED2, OUTPUT); pinMode(button, INPUT); }
The Software in Detail Part 2
Now for the loop. I'm going to break this down bit by bit, to explain what's going on. The first thing the program will do is read the state of the button. This will give us the code below and and allow us to create functions for both un-pressed and pressed states, remember that the short press function happens upon button release.
if (digitalRead(button) == HIGH) { //Button pressed } else { //Button not pressed }
In the button pressed section, the first thing we will do is test the buttonActive variable, upon set-up this is false. If this is currently false, this means the program is detecting the button being pressed for the first time. This is because after reading false we immediately set it to true, and only releasing the button can set it back to false. We also record the time the button was first pressed.
if (buttonActive == false) { buttonActive = true; buttonTimer = millis(); }
The next step within the button pressed section, is to test how long we have held the button for. We do this by testing the current time, subtracting the time first pressed in milliseconds and compare that to the length of time we wish until the long press is activated.
We also check that the longPressActive boolean is false, because once we have activated the long press function we will set this boolean to true to stop repeat activation. Once we have held the button for the desired time, we will flip the state of the LED1State boolean which will in turn flip the pin the LED is attached to HIGH or LOW accordingly.
if ((millis() - buttonTimer > longPressTime) && (longPressActive == false)) { longPressActive = true; LED1State = !LED1State; digitalWrite(LED1, LED1State); }
Moving on to the button not pressed section of the code. The first thing we will check is if the buttonActive boolean is true. If it is set to true, the code is looping for the first time since the button was released. It will then set the boolean back to false to allow the code above to detect the button being pressed again.
if (buttonActive == true) { buttonActive = false; }
Within the above if statement, as we are detecting the first loop after button release, we are next going to check if long press function was activated, which will give up two possible steps. If long press was activated we will simply set the longPressActive back to false to allow the program to long press once again. If it was not activated, we will flip the state of the second LED like we did with the first.
if (longPressActive == true) { longPressActive = false; } else { LED2State = !LED2State; digitalWrite(LED2, LED2State); }
The Full Code
Here is the full code ready for upload to your Arduino.
int LED1 = 12; int LED2 = 13; int button = 3; boolean LED1State = false; boolean LED2State = false; long buttonTimer = 0; long longPressTime = 250; boolean buttonActive = false; boolean longPressActive = false; void setup() { pinMode(LED1, OUTPUT); pinMode(LED2, OUTPUT); pinMode(button, INPUT); } void loop() { if (digitalRead(button) == HIGH) { if (buttonActive == false) { buttonActive = true; buttonTimer = millis(); } if ((millis() - buttonTimer > longPressTime) && (longPressActive == false)) { longPressActive = true; LED1State = !LED1State; digitalWrite(LED1, LED1State); } } else { if (buttonActive == true) { if (longPressActive == true) { longPressActive = false; } else { LED2State = !LED2State; digitalWrite(LED2, LED2State); } buttonActive = false; } } }
Bonus - Two Buttons 6 Functions
What if we have two buttons? Then we have the possibility of 6 functions as follows.
Short Press Button 1
Short Press Button 2
Short Press Button 1 & 2
Long Press Button 1
Long Press Button 2
Long Press Button 1 & 2
The program works in the same way the first code does, with some notable changes.
First there are more LED's, meaning there are more variables, and of course the extra button. But the biggest change comes to the point in which the long press or short press are activated. Once either of these two points are reached, rather than turn an LED on or off, we have three possible actions for each function. Resulting one of six possible LED's turning on or off. To determine which action to take, we check the state of each button and those points, and respond accordingly.
Here is the code
int LED1 = 8; int LED2 = 9; int LED3 = 10; int LED4 = 11; int LED5 = 12; int LED6 = 13; int button1 = 3; int button2 = 4; long buttonTimer = 0; long buttonTime = 250; boolean buttonActive = false; boolean longPressActive = false; boolean button1Active = false; boolean button2Active = false; boolean LED1Active = false; boolean LED2Active = false; boolean LED3Active = false; boolean LED4Active = false; boolean LED5Active = false; boolean LED6Active = false; void setup() { pinMode(LED1, OUTPUT); pinMode(LED2, OUTPUT); pinMode(LED3, OUTPUT); pinMode(LED4, OUTPUT); pinMode(LED5, OUTPUT); pinMode(LED6, OUTPUT); pinMode(button1, INPUT); pinMode(button2, INPUT); } void loop() { if (digitalRead(button1) == HIGH) { if (buttonActive == false) { buttonActive = true; buttonTimer = millis(); } button1Active = true; } if (digitalRead(button2) == HIGH) { if (buttonActive == false) { buttonActive = true; buttonTimer = millis(); } button2Active = true; } if ((buttonActive == true) && (millis() - buttonTimer > buttonTime) && (longPressActive == false)) { longPressActive = true; if ((button1Active == true) && (button2Active == true)) { LED4Active = !LED4Active; digitalWrite(LED4, LED4Active); } else if((button1Active == true) && (button2Active == false)) { LED5Active = !LED5Active; digitalWrite(LED5, LED5Active); } else { LED6Active = !LED6Active; digitalWrite(LED6, LED6Active); } } if ((buttonActive == true) && (digitalRead(button1) == LOW) && (digitalRead(button2) == LOW)) { if (longPressActive == true) { longPressActive = false; } else { if ((button1Active == true) && (button2Active == true)) { LED1Active = !LED1Active; digitalWrite(LED1, LED1Active); } else if ((button1Active == true) && (button2Active == false)) { LED2Active = !LED2Active; digitalWrite(LED2, LED2Active); } else { LED3Active = !LED3Active; digitalWrite(LED3, LED3Active); } } buttonActive = false; button1Active = false; button2Active = false; } }
From here we could even add a third button for a possible 14 LEDs, or four button for 30 LEDs. Maybe another time though :)