@Falcon, you get multiple interrupts due to contact “bounce”. Search the forum for “interrupt debounce” to look how others have addressed this.
@peekay123 Thank you your suggestion, I’ve tried using ClickButton library to trigger a click and do the debouncing. It has significantly helped in debouncing the switch, but occasionally, I do have many (4 to 8) events being triggered at once i.e. just for one click.
Could you also suggest what is Debounce time ? which is set to a default value of 20ms. Could this vary between different switches ?
// This #include statement was automatically added by the Particle IDE.
#include <clickButton.h>
/* ClickButton library demo
OUtput a message on Serial according to different clicks on one button.
2010, 2013 raron
GNU GPLv3 license
*/
// the Button
const int buttonPin1 = D2; // Default 4
ClickButton button1(buttonPin1, LOW, CLICKBTN_PULLUP);
// Button results
int function = 0;
int num = 10;
void setup()
{
Serial.begin(9600);
Serial.println("Hello");
pinMode(D2, INPUT_PULLUP);
// Setup button timers (all in milliseconds / ms)
// (These are default if not set, but changeable for convenience)
button1.debounceTime = 20; // Debounce timer in ms
button1.multiclickTime = 250; // Time limit for multi clicks
button1.longClickTime = 1000; // time until "held-down clicks" register
}
void loop()
{
//num = num + 1;
//Serial.println(num);
// Update button state
button1.Update();
// Save click codes in LEDfunction, as click codes are reset at next Update()
if (button1.clicks != 0) function = button1.clicks;
if(button1.clicks == 1) Serial.println("SINGLE click");
if(function == 2) Serial.println("DOUBLE click");
if(function == 3) Serial.println("TRIPLE click");
if(function == -1) Serial.println("SINGLE LONG click");
if(function == -2) Serial.println("DOUBLE LONG click");
if(function == -3) Serial.println("TRIPLE LONG click");
function = 0;
delay(5);
}
@peekay123 just tried doing that (increased the bounce delay to 50ms), but it still triggers multiple events for just 1 click . I just got 20 Double click events for just one double click. It happens similarly for single click events too.
@bko any suggestions or thoughts on how to resolve the bouncing effect that I am having using the micro switch.
First, I assume you can ignore double click events. Second, you may need to make the bounce delay even larger and make the multiclicktime and longclicktime very large.
@Falcon
I just tried solving your problem, and I have come up with a solution that solves bouncing and the need for delays.
#include "Particle.h"
/*SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);*/
#define BUTTON D0
bool pressing = false;
unsigned int lastPress, lastRelease, previousLastPress, previousLastRelease;
int buttonHandler() // 0 = not pressing, 1 = still pressing, 2 = just stopped pressing, 3 = just started pressing
{
if (digitalRead(BUTTON) == LOW && pressing == false) // 3 = just started pressing
{
pressing = true;
lastPress = millis();
return 3;
}
if (digitalRead(BUTTON) == HIGH && pressing == true) // 2 = just stopped pressing
{
pressing = false;
lastRelease = millis();
return 2;
}
if (pressing == true) // 1 = still pressing
{
return 1;
}
else // 0 = not pressing
{
return 0;
}
}
void setup() // Put setup code here to run once
{
pinMode(BUTTON, INPUT_PULLUP);
digitalWrite(BUTTON, HIGH);
Serial.begin(9600);
}
void loop() // Put code here to loop forever
{
int check = buttonHandler(); // get press status
if (previousLastRelease != lastRelease) // Button bumped, pushed and then released at later time
{
// Particle.publish("click","Click took "+String(lastRelease - lastPress)+" ms");
Serial.println("Click took "+String(lastRelease - lastPress)+" ms");
previousLastRelease = lastRelease;
}
}
In this example, the Photon replies via Serial how long a click took.
Example output (from Serial) for a bunch of “normal clicks”:
Click took 84 ms
Click took 91 ms
Click took 133 ms
Click took 131 ms
Click took 123 ms
Click took 119 ms
Click took 116 ms
Click took 129 ms
Click took 128 ms
Click took 134 ms
Click took 136 ms
Click took 1 ms
Click took 145 ms
Click took 148 ms
Sometimes I get values lower than 10ms, which I assume is just noise or bouncing, but it works really well.
@nrobinson2000, pinMode(BUTTON, INPUT_PULLUP); sets the pin as input with the pull-up. This digitalWrite(BUTTON, HIGH); does nothing, unlike Arduino land where it activates the pull-up on an input.
The solution suggested by @nrobinson2000 works perfectly, when I don’t have events like, publish to the particle cloud / writing data to EEPROM in the loop function.
As I have to publish data to cloud, save data to EEPROM, this solution becomes unreliable.
I have started using the below code suggested by @BulldogLowell, it still doesn’t remove the bouncing of the interrupt fully, as it still registers 2 to 3 interrupts for each button press.
Could someone please guide me how I could resolve interrupt bouncing issue ?
Here is a the MicroSwitch that I am using along with my particle Electron.
int button = D2;
void press(void);
int buttonState=1;
volatile bool flag = false;
void setup()
{
Serial.begin(9600);
//while(!Serial.available()) SPARK_WLAN_Loop();
Serial.println("Interrupt Test");
pinMode(button, INPUT_PULLUP);
attachInterrupt(button, press, FALLING);
}
void loop()
{
if (flag == true)
{
Serial.println("Key Pressed");
flag = false;
}
}
void press()
{
//Serial.println("switched now");
static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > 50) // debounce time = 50milliseconds
{
flag = true;
}
last_interrupt_time = interrupt_time;
}
Below are the signals from the Micro Switch captured on Oscilloscope, from this I understand that the total bounce time is below 2ms, the problem may not be with the bounce time of the switch.
The problem could be with the logic of debouncing.
It could be that the interrupt on a pin (set to falling) is being triggered when switch makes contact (Falling) as well as when switch breaks contact (Rising).
Any ideas on triggering the interrupt only when the switch makes contact and not when it breaks the contact.
FALLING interrupts do actually only fire when there is a falling edge - that is definet.
But as your scope shows even letting go of the button causes bounce which does again trigger falling edges.
That’s the reason why most actions don’t usually trigger on the button press but rather on the release.
Is the code from this post still your current version?
I’d try this ISR instead
const uint32_t msDebounce = 50;
volatile uint32_t msLastTrig = 0;
void press()
{
msLastTrig = millis();
}
void loop()
{
if (msLastTrig && millis() - msLastTrig > msDebounce)
{ // we know there was a trigger and the bouncing should have stopped by now
msLastTrig = 0;
if (!digitalRead(button))
doStuffOnPress();
else
doStuffOnRelease();
}
}
Whith this approach you can also use a CHANGE interrupt that would react on any edge, since the actual signal probing happens after the bounce in loop()
Below is what happens when I implement the above code. Even the button pressed method is called several times when button is pressed for a longer time. The button released method is called several times on release of the button.
@Falcon, it may be time to consider hardware debouncing by using an RC circuit to slow the switch rise time and “absorb” the bounce in both directions (on and off). Coupling the RC with a schmitt trigger would give a clean edge on the signal. Here is a good article dealing with bounce: