I have an ESP8266 (NodeMCU) development board. I'm trying to implement software debounce on a tactile push-button connected to GPIO5 while using an interrupt. For the "relayPin" I'm temporarily using the onboard LED (GPIO16).
The debounce works for the most part when I try to push the button down and wiggle it very rapidly. However, it fails on rare occasion and only when the time gap is zero between two different detected pulses. So essentially, it never fails when the time gap is above 0 and below the debounce time (200ms). Please see the image of the serial monitor.
While this issue occurs under extreme conditions (the switch will not be used in this manner), I'd still like to figure out if this is something to do with my code or another aspect I'm not aware of.
Image 2: Code & serial monitor
int swButton = 5;
int relayPin = 16;
bool relayOn = false; // Present on/off state of the relay.
int debounceTime = 200; // Debounce time in ms.
volatile bool switchToggle = false; // True when button press is valid (and not bounce noise).
volatile unsigned long nowPush = 0; // The millis() time of the present button press.
volatile unsigned long lastPush = 0; // The millis() time of the previous button press.
volatile unsigned long timeGap = 0; // The difference of the nowPush and lastPush times.
// Interrupt Service Routine on button press (falling edge).
ICACHE_RAM_ATTR void swButtonISR() {
nowPush = millis();
timeGap = nowPush - lastPush;
// Debouncing stuff, recognizing this button-press as a valid one.
if (timeGap > debounceTime) {
switchToggle = true;
lastPush = nowPush;
}
}
// Function that toggles the relay when called upon.
void toggleRelay () {
if (relayOn) {
digitalWrite(relayPin, LOW); // Turn off relay.
relayOn = false;
Serial.println((String)"Relay ON. Time gap: "+timeGap);
return;
}
else {
digitalWrite(relayPin, HIGH); // Turn on relay.
relayOn = true;
Serial.println((String)"Relay OFF. Time gap: "+timeGap);
return;
}
return;
}
void setup() {
Serial.begin(115200);
pinMode(swButton, INPUT);
pinMode(relayPin, OUTPUT);
pinMode(greenLED, OUTPUT);
attachInterrupt(digitalPinToInterrupt(swButton), swButtonISR, FALLING);
}
void loop() {
if (switchToggle == true) {
toggleRelay();
switchToggle = false;
}
}
There are a couple of changes you can make to also force a longer delay after "button release". (You could also just attach ONE interrupt handler with the CHANGE condition, to catch both FALLING and RISING edges.)
Add this
attachInterrupt(digitalPinToInterrupt(swButton), swButtonISR2, RISING);
change this
ICACHE_RAM_ATTR void swButtonISR() {
nowPush = millis();
timeGap = nowPush - lastPush;
// Debouncing stuff, recognizing this button-press as a valid one.
if (timeGap > debounceTime) {
switchToggle = true;
}
lastPush = nowPush;
}
add this
ICACHE_RAM_ATTR void swButtonISR2() {
lastPush = millis();
}