(PREAMBLE: sorry if I keep on seeming like I am re-hasing an old topic .. but
just want to share what information and work I've come up with.)
Okay... I've come to the conclusion that the simulating of an RC filter requires
a bunch of samples and the interval between samples needs to be considered.
One PDF paper I found a PDF file <
http://www.ganssle.com/debouncing.pdf> and the
paper talks about 50ms being an acceptable period for software debouncing (and
came to that time period using various reasons/sources). Parts of the PDF was in
the link in the previous post (which had a posted comment about simulating an RC
filter).
SOOOooo all that said, I've come up with a process for software debouncing and
simulating an RC filter. In my case, I am using 8 samples, each sample at about
6.2ms apart. 6.2ms * 8 is ALMOST 50ms (based on what I read in the PDF).
I might release this information (process) elsewhere, but I feel this is perhaps
the best way to implement software debouncing. But the import lines below are
the two lines:
1) BUTTONS |= Bsamples[0] & Bsamples[1] & Bsamples[2] &
Bsamples[3] & Bsamples[4] & Bsamples[5] & Bsamples[6] &
Bsamples[7];
and
2) BUTTONS &= Bsamples[0] | Bsamples[1] | Bsamples[2] | Bsamples[3] |
Bsamples[4] | Bsamples[5] | Bsamples[6] | Bsamples[7];
#1... if and bit in the array of the samples (in all elements) are always set,
peforming a bitwise AND of all samples, will result in setting the results as
SET. that SET is then bitwise (inclusive) OR (IOR) together with the shadowed
button register.. which if not set.. will end up setting it. Any break in
sequence of samples (if even ONE sample is unset), the result is NOT SET, and
then not IOR'ed into the shadow register BUTTON (which the code uses). Any
previous bits will remain in their state (SET or UNSET)
#2... similar to #1, the entire array of samples is IORed (Inclusive ORed)
together... if any bits are high, the result set is SET... flipside, if ANY bit
is ALWAYS unset. the result is UNSET. This result is then bitwise ANDed with the
shadow BUTTON register. If any bit is BUTTON is set but the result is UNSET, the
logic (bitwise) AND causes that bit to become unset. So any unset bit (over then
entire sampled array) will cause the shadow register to unset... any bit that is
set, will cause the state of the same bit in the shadow BUTTON register to stay
in it's current state. (little more complicated to understand)
if there is a sequence of alternating sampled bits, then BUTTONs remains
untouched (the external button is in a bouncing state).
This code will debounce a switch (up to the size of the register, 8-bits in this
case), over a set amount of time, similar to how an external RC filter would
debounce a switch in hardware and do it very effectively without having tons of
extra code. It can be scaled fairly easy and if you have a lot more samples, you
might want to roll the code (into a loop) to save on code space (execution time
will take longer).
here in C:
unsigned char BUTTONS=0; // software debounced registers
unsigned char Bsamples[8]; // sample (array) history (last 8 samples)
unsigned char Bindex=0; // Button sample array index
unsigned char Btimer=0;
if (Btimer!=0) { // reach here every 0.1ms
Btimer--;
} else {
//reset button timer
Btimer=61; // = 6.2ms * 8 = 49.6ms
Bsamples[Bindex]=read_buttons(); // unroll the following few lines if
sizeof(Bsamples)<8
if (Bindex==0) {
Bindex=sizeof(Bsamples);
}
Bindex--;
//unroll this: Bbitmask=0xff; for (i=0;i<sizeof(Bsamples);i++) { Bbitmask
&=Bsamples[i]; }
// BUTTONS = BUTTONS | Bbitmask;
BUTTONS |= Bsamples[0] & Bsamples[1] & Bsamples[2] & Bsamples[3] &
Bsamples[4] & Bsamples[5] & Bsamples[6] & Bsamples[7];
//unroll this: Bbitmask=0xff; for (i=0;1<sizeof(Bsamples);i++) } Bbitmask &=
~Bsamples[i]; }
// BUTTONS = BUTTONS & Bbitmask;
BUTTONS &= Bsamples[0] | Bsamples[1] | Bsamples[2] | Bsamples[3] |
Bsamples[4] | Bsamples[5] | Bsamples[6] | Bsamples[7];
} // end of software bounce buttons
here is (a portion) disassembled (C18 PIC) C: (I've gone ahead and optimized the
'C' code for size/speed for small/fast opcodes)
78: if (Btimer!=0) {
00082 0100 MOVLB 0
00084 5166 MOVF 0x66, W, BANKED
00086 E002 BZ 0x8c
79: Btimer--;
00088 0766 DECF 0x66, F, BANKED
80: } else {
0008A D029 BRA 0xde
81: //reset button timer
82: Btimer=61; // = 6.2ms * 8 = 49.6ms
0008C 0E3D MOVLW 0x3d
0008E 6F66 MOVWF 0x66, BANKED
83: Bsamples[Bindex]=read_buttons(); // unroll the following
few lines if sizeof(Bsamples)<8
00090 D85B RCALL 0x148
00092 6EE6 MOVWF 0xfe6, ACCESS
00094 0100 MOVLB 0
00096 5165 MOVF 0x65, W, BANKED
00098 6AEA CLRF 0xfea, ACCESS
0009A 0FF8 ADDLW 0xf8
0009C 6EE9 MOVWF 0xfe9, ACCESS
0009E 0E01 MOVLW 0x1
000A0 22EA ADDWFC 0xfea, F, ACCESS
000A2 52E5 MOVF 0xfe5, F, ACCESS
000A4 50E7 MOVF 0xfe7, W, ACCESS
000A6 6EEF MOVWF 0xfef, ACCESS
84: if (Bindex==0) {
000A8 5165 MOVF 0x65, W, BANKED
000AA E102 BNZ 0xb0
85: Bindex=sizeof(Bsamples);
000AC 0E08 MOVLW 0x8
000AE 6F65 MOVWF 0x65, BANKED
86: }
87: Bindex--;
000B0 0765 DECF 0x65, F, BANKED
88:
89: //unroll this: Bbitmask=0xff; for
(i=0;i<sizeof(Bsamples);i++) { Bbitmask &=Bsamples[i]; }
90: // BUTTONS = BUTTONS | Bbitmask;
91: BUTTONS |= Bsamples[0] & Bsamples[1] & Bsamples[2] &
Bsamples[3] & Bsamples[4] & Bsamples[5] & Bsamples[6] & Bsamples[7];
000B2 0101 MOVLB 0x1
000B4 51F8 MOVF 0xf8, W, BANKED
000B6 15F9 ANDWF 0xf9, W, BANKED
000B8 15FA ANDWF 0xfa, W, BANKED
000BA 15FB ANDWF 0xfb, W, BANKED
000BC 15FC ANDWF 0xfc, W, BANKED
000BE 15FD ANDWF 0xfd, W, BANKED
000C0 15FE ANDWF 0xfe, W, BANKED
000C2 15FF ANDWF 0xff, W, BANKED
000C4 0100 MOVLB 0
000C6 1364 IORWF 0x64, F, BANKED
92:
93: //unroll this: Bbitmask=0xff; for
(i=0;1<sizeof(Bsamples);i++) } Bbitmask &= ~Bsamples[i]; }
94: // BUTTONS = BUTTONS & Bbitmask;
95: BUTTONS &= Bsamples[0] | Bsamples[1] | Bsamples[2] |
Bsamples[3] | Bsamples[4] | Bsamples[5] | Bsamples[6] | Bsamples[7];
000C8 0101 MOVLB 0x1
000CA 51F8 MOVF 0xf8, W, BANKED
000CC 11F9 IORWF 0xf9, W, BANKED
000CE 11FA IORWF 0xfa, W, BANKED
000D0 11FB IORWF 0xfb, W, BANKED
000D2 11FC IORWF 0xfc, W, BANKED
000D4 11FD IORWF 0xfd, W, BANKED
000D6 11FE IORWF 0xfe, W, BANKED
000D8 11FF IORWF 0xff, W, BANKED
000DA 0100 MOVLB 0
000DC 1764 ANDWF 0x64, F, BANKED
96:
97: } // end of software bounce buttons
----- Original Message ----
From: Doug <
dx9s@...>
To:
laser_design@yahoogroups.com
Sent: Sunday, March 1, 2009 6:45:45 PM
Subject: [laser_design] Re: Software debouncing switches
I found this article on software debouncing and there seems to be a
wide range of techniques and thought put into the article:
<
http://www.embedded.com/columns/breakpoint/22100235>
http://www.embedded.com/columns/breakpoint/22100235
I my code is only two samples and I was thinking about using 3 or 4
... now after reading the comment at the bottom about simulating an RC
network... Gives me a few new ideas. (I'll report back on any changes
to my code).
--Doug
--- In
laser_design@yahoogroups.com, Douglas Marsh <dx9s@...> wrote:
>
> I was a little off (and because C18 is a little different that
midline assembler, the 'C' compiler spit out a little bit more code):
>
> (copy/paste from disassembled listing -- with comments below)
>
> 17: LAST = CURRENT;
> 00A6 C08B MOVFF 0x8b, 0x8a
> 00A8 F08A NOP
> 18:
> 19: CURRENT = PORTB;
> 00AA CF81 MOVFF 0xf81, 0x8b
> 00AC F08B NOP
> 20:
> ...