[CCC DEV] More on debounce - probable bug
Steve Pretty
steve.g.pretty at btinternet.com
Wed Jan 26 23:11:50 GMT 2011
As you know, I was looking at plumbing debounce and suggested a change
the other day.
Well, the reason I was looking at it was because I have been getting
some unexpected results when using it. I created an "instrumented"
version of debug (i.e. stuffed it with print statements etc), and
managed to capture an example of the problem:
0001 HIGH sent to out
0002 LOW sent to out LOW was last int
0001 HIGH sent to out
0001 LOW sent to out
0001 HIGH sent to out
0002 HIGH sent to out LOW was last int
0001 HIGH sent to out
0002 HIGH sent to out LOW was last int
0001 HIGH sent to out
0001 LOW sent to out
0001 HIGH sent to out
0001 LOW sent to out
0001 HIGH sent to out
0001 LOW sent to out
The first number is the number of messages received on in? during a
debounce. A lot of the time it is 1 - which means no additional bounce
interrupts occurred. The line continues by saying what LEVEL was sent
to out, and then if there were debounce messages, what was the last
value received in? (i.e. the final value of your valuable any).
In the test I am pushing a buttton on pin 3, which lights LED on pin 13
when pressed, and it should go out when the button is released. So what
you should see is a simple HIGH LOW HIGH LOW . . . . Well, in
practice, that happens a lot of the time, but not always. You can see
that I actually got two presses in a row where I got HIGH HIGH HIGH HIGH
HIGH. Note in each case that the last int value received was the
correct value.
I have experienced the problem with two different types of switch.
Changing the length of the debounce timer has no effect.
Here is what I believe is happening. Then the button state changes, an
interrupt is generated and digital.input gets called to handle it. It
immediately does a digital.read. This LEVEL is then passed to debounce,
and then on to the client. BUT the digital.read is happening immediately
after the state change, when the signal will be most noisy - and we
trust this reading and pass it on unchanged through debounce. So
basically, that means debounce does not work properly - all it is doing
is ensuring there is a single message to the client about an event,
rather than several.
Now, I suspect you have not experienced this problem, because as we have
discussed, your current version of digital.input has a "feature" where
it can only ever send HIGH - so debounce only ever sends HIGH - so no
problem to see.
I have thought of three possible solutions:
1. Eliminate debounce at source - The input pins have schmitt trigger
inputs, so one could add additional capacitor and resistor to the
switch. Not too happy with this, as it adds to circuit complexity and it
would be a bit of a black art to get just the right values!
2. Add a 50 ms delay into digital.input before doing the digital.read -
effectively doing the debounce in there. Dont like that one - it rather
specialises digital.input. What it I am connecting to a reliable digital
input that needs a low latency response?
3. Take another look at debounce - I believe if a bounce does occur, we
can be much more confident in accepting the LAST value received - which
should reflect the final stable state of the button, than trusting that
initial value.
I have now changed debounce to look like:
PROC debounce (CHAN LEVEL in?, out!)
LEVEL v:
WHILE TRUE
TIMER tim:
INT t:
SEQ
in ? v
tim ? t
t := t PLUS DEBOUNCE.TIME
INITIAL BOOL ignoring IS TRUE:
WHILE ignoring
ALT
in ? v
SKIP
tim ? AFTER t
ignoring := FALSE
out ! v
:
So the out is back at the end. the variable "any" has gone. If we do get
a bounce message, it updates v, so that it is the last v received that
is sent to out.
Tests on this approach look solid so far
(It is a shame that I will have to press my button an infinite number of
times to be sure this new version of debounce never emits the wrong value!)
Regards
Steve
More information about the developers
mailing list