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;
}
}
}
Imagine that I am the flash and I press the button but only for 50ms.
The first if statement will catch and set press to true and start holdTime. Then after 300ms, press is still true even though I've let go of the button 250ms ago. So it still registers as a short press.
This is happening on the last bounce when you release your long press. You need to set press back to false if you read HIGH on the button at any time.
// if button is NOT pressed
if(digitalRead(pin) == HIGH) {
if(longPress) {
// handle your long press end
} else if (press) {
// handle short press end
}
press = false;
longPress = false;
buttonPressStart = millis(); // constantly being updated until a press starts
}
if(millis() - buttonPressStart > 300) {
press = true;
}
if(millis() - buttonPressStart > 1000) {
longPress = true;
}
As counter intuitive as it sounds, you want to set the button start time to millis any time the button is NOT pressed. The start of a press is the last moment that it wasn't pressed. That makes the time easier to manage because you know that while the button isn't pressed, the elapsed time will always be zero. So now the elapsed time is all you have to check for.
Now that's a confusing construct. It just reverses the return value from digitalRead? That's an interesting level of obfuscation. Are you just trying to confuse the newbie?
Couldn't you just swap these:
Isn't that the whole purpose of extracting the values to an enum?
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!