99 lines
3.2 KiB
C
99 lines
3.2 KiB
C
/* 3-Way Button: Click, Double-Click, Press+Hold
|
|
*
|
|
* By Jeff Saltzman
|
|
*
|
|
* Modified by: Andrew Tuline
|
|
*
|
|
* Oct. 13, 2009
|
|
*
|
|
* To keep a physical interface as simple as possible, this sketch demonstrates generating four output events from a single push-button.
|
|
*
|
|
* 1) Click: rapid press and release
|
|
* 2) Double-Click: two clicks in quick succession
|
|
* 3) Press and Hold: holding the button down
|
|
*
|
|
* http://forum.arduino.cc/index.php?topic=14479.0
|
|
*
|
|
*/
|
|
|
|
|
|
//=================================================
|
|
// MULTI-CLICK: One Button, Multiple Events
|
|
|
|
// Button timing variables
|
|
int debounce = 20; // ms debounce period to prevent flickering when pressing or releasing the button
|
|
int DCgap = 250; // max ms between clicks for a double click event
|
|
int holdTime = 1000; // ms hold period: how long to wait for press+hold event
|
|
|
|
|
|
// Button variables
|
|
boolean buttonVal = HIGH; // value read from button
|
|
boolean buttonLast = HIGH; // buffered value of the button's previous state
|
|
boolean DCwaiting = false; // whether we're waiting for a double click (down)
|
|
boolean DConUp = false; // whether to register a double click on next release, or whether to wait and click
|
|
boolean singleOK = true; // whether it's OK to do a single click
|
|
long downTime = -1; // time the button was pressed down
|
|
long upTime = -1; // time the button was released
|
|
boolean ignoreUp = false; // whether to ignore the button release because the click+hold was triggered
|
|
boolean waitForUp = false; // when held, whether to wait for the up event
|
|
boolean holdEventPast = false; // whether or not the hold event happened already
|
|
|
|
|
|
|
|
uint8_t checkButton() {
|
|
uint8_t event = 0;
|
|
buttonVal = digitalRead(buttonPin);
|
|
// Button pressed down
|
|
if (buttonVal == LOW && buttonLast == HIGH && (millis() - upTime) > debounce)
|
|
{
|
|
downTime = millis();
|
|
ignoreUp = false;
|
|
waitForUp = false;
|
|
singleOK = true;
|
|
holdEventPast = false;
|
|
|
|
if ((millis()-upTime) < DCgap && DConUp == false && DCwaiting == true) DConUp = true;
|
|
else DConUp = false;
|
|
DCwaiting = false;
|
|
}
|
|
// Button released
|
|
else if (buttonVal == HIGH && buttonLast == LOW && (millis() - downTime) > debounce)
|
|
{
|
|
if (not ignoreUp)
|
|
{
|
|
upTime = millis();
|
|
if (DConUp == false) DCwaiting = true;
|
|
else
|
|
{
|
|
event = 2;
|
|
DConUp = false;
|
|
DCwaiting = false;
|
|
singleOK = false;
|
|
}
|
|
}
|
|
}
|
|
// Test for normal click event: DCgap expired
|
|
if ( buttonVal == HIGH && (millis()-upTime) >= DCgap && DCwaiting == true && DConUp == false && singleOK == true && event != 2)
|
|
{
|
|
event = 1;
|
|
DCwaiting = false;
|
|
}
|
|
// Test for hold
|
|
if (buttonVal == LOW && (millis() - downTime) >= holdTime) {
|
|
// Trigger "normal" hold
|
|
if (not holdEventPast)
|
|
{
|
|
event = 3;
|
|
waitForUp = true;
|
|
ignoreUp = true;
|
|
DConUp = false;
|
|
DCwaiting = false;
|
|
//downTime = millis();
|
|
holdEventPast = true;
|
|
}
|
|
}
|
|
buttonLast = buttonVal;
|
|
return event;
|
|
} // checkButton()
|
|
|