Simple push button turns out to be serious business

Hello,

I am humbled to report that I couldn’t make a simple push button work. I’m definitely missing some simple concept here. Here below is my code:

function buttonHandler() { local state = hardware.pin1.read(); server.log("Pin1 state: " + state); } hardware.pin1.configure(DIGITAL_IN, buttonHandler); imp.configure("Testing push button", [], []);

Well, the button is very sensitive, and, unless it’s pushed very bravely, there’s a stream of 1s and 0s, until it settles on the last 1, when pushed. Releasing apparently has fewer such symptoms, but still, it’s not always just one zero arriving.

Here’s below the way how I solved it. But I’m not particularly proud of it, feels kind of messy. Is there a better way how to deal with this jitter problem?

local lastStableState = 0; local lastState = 0; local lastUpdate = 0; local waiterEngaged = false; local waitTime = 5; // in milliseconds function waiter() { local curTime = hardware.millis(); if (curTime - lastUpdate > waitTime) { // Stable state long enough time if (lastState != lastStableState) { lastStableState = lastState; server.log("New stable state: " + lastStableState); } waiterEngaged = false; } else { // There have been new updates, must wait for stable value imp.wakeup(waitTime / 1000, waiter); } } function buttonHandler() { lastState = hardware.pin1.read(); lastUpdate = hardware.millis(); if (!waiterEngaged) { waiterEngaged = true; imp.wakeup(waitTime / 1000, waiter); } }

what you are unknowingly doing is called debouncing. All buttons have mechanical noise when pressed and released that causes many state changes. This can last between a few ms to 50ms or more depending on the button.

you need to filter out (ignore) the changes until you get a continuous state for a set amount of time

Yep, you can either debounce with hardware or software. With hardware, you might use an RC filter to debounce. What you are doing there is creating a circuit with a resistor and a capacitor. When you push the switch, the capacitor fills itself until you have a voltage level that is a “HIGH”, and when you release it, the resistor can drain it to low. You don’t get bounce, because you can only go high or low as fast as the RC circuit allows you too.

The pins on the Imp have interrupts enabled (I can’t explain that well), but you can set callback functions on each pin, so that when the pin goes high or low the function configured for callback will be executed. Callbacks actually handle debouncing pretty well by themselves, so much so that I don’t debounce the magnetic sensor switches on my security system.

Hugo had written some example code for debouncing in that thread… I think if you search for security system project you’ll find it.

Jeremy Blum has some great tutorials for the Arduino on youtube, and in one of the first ones, he talks about debouncing. I recommend watching all of them, but that one will have very useful information.

Thanks for the new dictionary item, and the relevant references. I’ll see if I can improve my software debouncer.

From this example code I see that it might be preferable to take into account the first changed value, not the last stable. Makes sense - then even extremely quick switching would be properly treated, while my code (in OP above) would consider that a noise and ignore.

@brandon, one of our hardware engineers, actually wrote a fairly powerful button class. It sounds kind of rediculous, but it does a very good job debouncing. The code in the class is a little confusing, but makes working with buttons super simple.