DIGITAL_IN with callback

I’m seeing a strange phenomenon that’s perplexing me. I have a simple toggle switch wired to an input that’s pulled to ground with a 10K resistor. One side of the switch goes to 3.3v and the other to the input. This is a very common configuration for me.

I was working on some debounce code and started seeing something that I simply don’t understand. I started with a debounce ~100msec and no matter how high I go with the sleep, I’m always getting 2 log messages whenever I turn the switch to the “on” position, but only 1 when I turn it off.

Perhaps it’s just a “Monday” thing, but this is alluding me. Thoughts?

Here’s the simple test code:
`
fred <- hardware.pin8

function logit() {
imp.sleep(1.9);
server.log("input = "+fred.read());
server.log(“let’s see if this prints, too”);
}

fred.configure(DIGITAL_IN, logit);
`

Here’s the output I’m seeing ( started with the switch in the “off” position):
2015-03-30 13:53:19 UTC-4 [Status] Device connected; 1.60% program storage used 2015-03-30 13:53:26 UTC-4 [Device] input = 1 2015-03-30 13:53:26 UTC-4 [Device] let's see if this prints, too 2015-03-30 13:53:28 UTC-4 [Device] input = 1 2015-03-30 13:53:28 UTC-4 [Device] let's see if this prints, too 2015-03-30 13:53:43 UTC-4 [Device] input = 0 2015-03-30 13:53:43 UTC-4 [Device] let's see if this prints, too 2015-03-30 13:53:50 UTC-4 [Device] input = 1 2015-03-30 13:53:50 UTC-4 [Device] let's see if this prints, too 2015-03-30 13:53:52 UTC-4 [Device] input = 1 2015-03-30 13:53:52 UTC-4 [Device] let's see if this prints, too

That’s what a bounce looks like. The pin goes high, we enter the callback, the callback sleeps. The pin bounces low again, we queue a new callback, we can’t run it yet 'cos the first one is still running. The pin bounces high, we note a callback is already queued and don’t queue another one. These can happen a few times. Eventually the first callback exits and the queued one is called.

As for why this doesn’t happen on the falling edge, the falling direction won’t bounce because of your pull-down, so the callback is entered just once.

Peter

Thanks, @peter, for the clarification. I’ll peruse the forum a bit to learn about more effective debouncing techniques. I incorrectly assumed that sleeping for a bit would handle the bounce.

One of our engineers wrote a Button Class to help demonstrate good software debouncing techniques.

It also also lets you do some other things like specify a callback for the button being pressed, and the button being released.

The fundamental debouncing scheme seems to be:

  1. Start with the input configured with a callback
  2. Immediately in the callback, reconfigure the port to eliminate the callback
  3. Wait 10 msec and then read the “debounced” input
  4. Reconfigure the input to have the callback.

I tried this technique and got very reliable results. This was really just a learning exercise for myself.

The Button Class reference finally forced me to think about bindenv(), call() and acall() and I think I finally got the context issue through my thick skull, although I’m not ready to try to explain it! Thanks for pointing me in the right direction.

@hvacspei - have you looked at the bindeny article @smittytone wrote?

Yep! That was where I went after looking at your referenced Button Class. Remember, I’m an old fart who did all programming in a procedural fashion until lately. I’m still learning!

+1 for us old farts. This is my keyboard:

lol. +1 if you recognise what these were used for…

That small floppy is modern. You should have posted the 8 inch floppy disk.

All this newfangled stuff! I grew up with these

An IBM 029 Card Punch? Now that brings back memories!

@hvacspei
Sorry we’re sort of hijacking your thread. It’s fun though.
How many of us remember taking the clear plastic container of “tiny paper punches” under the Tele-Type tape reader, and dumping it over another student’s head? If the student had a 1970’s ‘afro’, it would take them hours to get the paper punch dots out of their hair.

Remember punching in the bootloader on the front panel?

Back on topic for a quick FYI… I have a current switch on a 160A circuit and I’m seeing quick a bit of bounce, likely due to the contactor (or the inrush exceeding the limit of the current switch). I’ve had to increase the debounce time to 0.50 seconds to get it to “behave”. Just thought I’d pass this along, since everything was great on the desk with a toggle switch, but the real world with different hardware provided yet another learning opportunity.

The saga continues…

I believe I’m likely seeing EMI in the electrical cabinet that is causing some problems that I thought were debounce issues. That being said, I’m posting my device code to confirm my debounce is consistent with the example code. The input is pulled to ground with a 10K resistor and tied to 3.3 via the current switch input (normally open).

`
//Controls a timed output based upon an input going high
//Created: 20150402 ctm
//Revised: 20150415 - incresed debouncePeriod to 1.0 and then 2.0

inputPort <- hardware.pin9;
outputPort1 <- hardware.pin1;
outputPort2 <- hardware.pin2;

const on = 1;
const off = 0;
const timer1Period = 45;//Specifies the number of seconds output 1 should be on;
const timer2Period = 60;//Specifies the number of seconds output 2 should be on
const debouncePeriod = 2.0; //length of input debounce period in seconds

dummy <- null;

server.log(“StarTimer v3 device code starting”);
input <- off;

class timedOutput {
static on=1;
static off=0;

_pin = null;
_gsStream = null;
timer = null;

constructor (pin,gsStream) {
    _pin = pin; //hardware pin
    _gsStream = gsStream; //GroveStreams stream name
    _pin.configure(DIGITAL_OUT);
}

function start(period) {
    server.log("starting output="+_gsStream);
    _pin.write(on);
    // if (timer!=null) {
    //     server.log("Canceling existing timer");
    //     imp.cancelwakeup(timer);
    // }
    timer = imp.wakeup(period,stop.bindenv(this));
    agent.send("gsPut","&"+_gsStream+"=1");
}

function stop() {
    server.log("stopping ouput="+_gsStream);
    if (timer!=null) {
        imp.cancelwakeup(timer);
    }
    if (_pin.read()==on){
    _pin.write(off);            
    agent.send("gsPut","&"+_gsStream+"=0");
    }
}

}

function startup() {
//This function is called at startup and runs only once
server.log("The MAC address of this device is: "+imp.getmacaddress());
server.log("The unique id of this device is: "+hardware.getdeviceid());
server.log("The SSID of the wireless network is: "+imp.getssid());
server.log("The signal strength is: "+ imp.rssi());
//The output is sent to pin9 of the imp
timer1 <- timedOutput(outputPort1,“fanOutput1”);
timer1.stop(); //make sure the output is off
//timer2 <- timedOutput(outputPort2,“fanOutput2”);
//timer2.stop(); //make sure the output is off
//The input being watched
inputPin <- inputPort;
inputPin.configure(DIGITAL_IN,debounceInput);
}

function inputHandler(){
input = inputPin.read(); //this should be a debounced input
server.log(“input=”+input);
if (input==off){
timer1.stop();
//timer2.stop();
}
else { //input is on
timer1.start(timer1Period);
//timer2.start(timer2Period);
}
inputPin.configure(DIGITAL_IN,debounceInput); //re-enable debounce callback
}

function debounceInput(){
inputPin.configure(DIGITAL_IN); //disable callback
imp.wakeup(debouncePeriod,inputHandler) //let input debounce
}

function requestParameters(dummy){
//called by the agent if it needs configuration information that requires the device ID
agent.send(“getDeviceParams”,hardware.getdeviceid());
}

startup();

agent.on(“requestParameters”,requestParameters)
`

I’m basically seeing double inputs about a second apart. I’m now wondering if there are input state changes happening so quickly, they get queued before debounceInput() gets called to remove the callback. Thoughts?