Debouncing QuickStart touch pads
I have looked at many debouncing forum threads (google search) and tried several approaches including those from Beau Schwabe, JonnyMac, Duane Degn, etc
but I still get multiple hits almost every time.
Someone mentioned bitwise OR in debouncing but I could not find any posted code.
If anyone has a "foolproof" approach, I would love to see the code!
Thanks,
Ron
but I still get multiple hits almost every time.
Someone mentioned bitwise OR in debouncing but I could not find any posted code.
If anyone has a "foolproof" approach, I would love to see the code!
Thanks,
Ron

Comments
http://www.parallaxsemiconductor.com/sites/default/files/parallax/TouchButtonsLEDDemov1.0_1.zip
Thanks jazzed,
But that was one of first ones I tried but I just did it again and got 25 lines of ("Cogs used: 5") in the terminal window with a quick touch.
My program just counts available unused cogs when pad one is touched.
I think that's what the Touch Buttons PASM/Spin code does - looks like it checks 31 times
CON SAMPLES = 32 ' Require 32 high redings to return true VAR long Results PUB State | Accumulator Accumulator := Results ' Sample multiple times and return true repeat constant(SAMPLES - 1) ' if every sample was highw Accumulator &= Results return AccumulatorThis approach gives good response. If your action takes long enough you can eliminate the first 1/16 second delay / stabilize pause. Some switches seem to bounce around for ages before they stabilize so the 1/16 second period may have to be lengthened.
Sandy
'CON { QS_ButtonScan.spin } ' { ButtonStart - responsible for the touch pad buttons } VAR LONG Buttons LONG ButtonCog LONG Stack[ 16 ] ' define my stack OBJ util:"QS_Utilities" PUB start( ButtonAdr ) ' start this in a new cog Buttons := ButtonAdr ' save status if ButtonCog cogstop(ButtonCog-1) ' no cog available ButtonCog := cognew(ButtonScan, @Stack) + 1 PUB ButtonScan | B, B1 ' local variables dira [0..7] := %11111111 ' all pad pins outputs outa [0..7] := %11111111 ' all pad pins high 'main loop - scan the buttons Repeat ' loop forever Repeat B from 0 to 7 ' QS LEDS are pins 0-7 dira [B] := 1 ' make pin an output dira [B] := 0 ' make pin an input util.WaitMS(4) ' short delay for some decay B1 := ina[B] ' read the pad if B1 == 0 ' 0 here means pressed BYTE[Buttons] |= |< B ' set bit if pressed else BYTE[Buttons] &= !|< B ' clear bit if notdemo program to test touchpads
CON { LED PingPong for the QuickStart board } _CLKMODE=XTAL2 _xinfreq = 5_000_000 Right = 1 ' Direction Left = 2 ' Direction ButtonR = 0 ' Right Button pin ButtonL = 7 ' Left Button Pin OBJ Tpad: "QS_Buttons" 'this loads the Touchpad driver as alias Touch. VAR LONG MS001 BYTE buttons BYTE PointsRight, PointsLeft,First, Last BYTE BallSpeed, Direction PUB SetUp Tpad.start( @buttons ) ' start touchpad driver MS001 := CLKFREQ / 1_000 ' define 1 millisec outa[ 16..23 ] := $00 ' all LED pins off ' dira[ 16..23 ] := $FF ' all LED pins outputs ' BallSpeed := 150 Direction := Left PingPong ' PUB PingPong ClearAll Repeat BallMove If Direction == Right ' to the Right if byte[Buttons AND %00000001] == 1 ' hit it? bit 0 ChangeDirection ' Oh Yea! else ScoreRight ' missed it by that much.. elseif Direction == Left ' Not right must be left if byte[Buttons AND %10000000] == 1 ' hit it? bit 7 changeDirection ' yup! else ScoreLeft 'aced him again! Pri ScoreRight PointsRight++ ShowScores WaitMS(1000) Pri ScoreLeft PointsLeft++ ShowScores WaitMS(1000) Pri ShowScores | X ' do we have a winner? if PointsRight == 7 ' I won! Repeat 20 outa [16..23] := %11111111 waitMS(50) outa [16..23] := %00000000 waitMS(50) ClearAll WaitMS(2000) ' wait a sec before serving again changeDirection ' change Server elseif PointsLeft == 7 ', no, I won! Repeat 20 outa [16..23] := %11111111 waitMS(50) outa [16..23] := %00000000 waitMS(50) ClearAll waitMS(2000) ' wait a sec before serving again ChangeDirection ' change server elseif 1 ' no winner - show the scores - keep playing If PointsRight >0 Repeat 10 Repeat x from 23-(PointsRight-1) to 23 outa[x] ~~ waitMS(50) outa [16..23] := %00000000 waitMS(50) If PointsLeft >0 repeat 10 Repeat x from 16 to 16+(PointsLeft-1) outa[x] ~~ waitMS(50) outa [16..23] := %00000000 waitMS(50) Pri ClearAll PointsLeft := 0 PointsRight := 0 PUB ChangeDirection If Direction == Right Direction := Left else Direction := Right PUB BallMove | LED ' sets direction in terms of LED pin numbers If Direction == Left First:= 16 Last := 23 else First:=23 Last :=16 ' now actually move the "ball" repeat Led FROM First to Last outa [LED] := 1 WaitMS(BallSpeed) outa [LED] := 0 WaitMS(100) PUB WaitMS(W) 'wait for W milliseconds WaitCNT ((W*MS001)+cnt)Thanks cavelamb. I can sort of get it to work if I stick a 20ms wait in my loop but I guess what I'm trying to come up with is a routine that gives me a single hit when a pad is touched.
I guess it needs to constantly compare the button states for a fixed period and only return a non-zero byte if button state bits are unchanged for the entire period but where it won't miss a button push (if that makes sense).
Sort of works
repeat outa[23..16] := Buttons if byte[Buttons AND %00000001] == 1 ' hit it? bit 0 CountCogs WaitMS(20)I thought the same thing at first, but it's a bit more involved that that.
Touchpad aren't switches.
The trouble you are experiencing is not "bounce".
It works like this:
First the touchpads are "charged up" but writing 1s to the pins as outputs.
Then the outputs are turned around to inputs.
Next, a short delay (word from our sponsor) to let that charge decay off a bit.
NOW we finally read the pin and check to see if it's touched or not.
Lastly, if the pad returns 0 (pressed) that bit is set (1) in the return byte.
for a project ...
I'd like to detect:
Short press
Long press
Double tap
I guess calling it bounce is technically not correct but the behavior is somewhat similar.
What I'm looking for is (do I dare say this on a Propeller forum?
Something that doesn't depend on long waits or give multiple hits for one brief touch.
Hmmmm - that can be problematic I see:
http://forums.parallax.com/showthread.php/126265-WAITPEQ-with-timeout
http://forums.parallax.com/showthread.php/99748-Forcing-exit-of-waitpeq-if-no-match-occurs
Thought that for a while too. But the Prop is "different".
That's what multiple cogs are for.
The touchpad routine could easily be started in another cog and left running.
Then all we would have to do is read the button byte and take action.
Small tight loop...
Try that drive I posted.
Shouldn't give you multiple hits.
It runs pretty smooth for me.
Its actually quite a bit more complicated than what you said.
Due to the conductivity of your finger, which can vary enormously, and the pressure of your !push! the decay time can vary greatly. Then, to top it all off, your finger also introduces a large 60 Hz AC signal into the node of unknown proportions.
So to read the pads reliably, with various users and humidity conditions, requires a somewhat complicated algorithm. I am developing an adaptive approach, but its not done yet.
Simple approaches such as timing may appear to work, but when users or conditions change, the results will vary. Hard long presses may give passable results, depending on your needs.
Cheers,
Peter (pjv)
Yes, I know that, p.
But the issue at hand is getting the guy "adapted" to the Propeller.
This set up has given me good service so far, but you are probably right that someone else probably has a
different "touch".
I'd be really interested in in seeing your driver when you get it working.
break
Ron, if it's really important, you can add real switches to the pad pins and read them
like real (bouncy) switches.
Here is the code I used and it does give multiple hits - especially if I remove the 20ms wait in the repeat loop.
repeat outa[23..16] := Buttons if byte[Buttons AND 000001] == 1 ' hit it? bit 0 CountCogs WaitMS(20)How fast can you get your finger off of the pad?
Looks like you need to FLAG that a toughpad has happened,
and wait for it to be released before repeating the loop?
I considered using real buttons
I'm really just messing around and trying to familiarize myself with the QuickStart.
I would probably use real buttons if I wanted a more reliable trigger...
Thanks,
- Ron
I need to play around with it some more - maybe I can figure out a way to do what I want.
or it repeats
Yeah - got to be a better way to approach this.
I thought it might be neat to use the QuickStart (and it's touch pads) to set the date and time on a ChronoDot (DS3231 Real Time Clock) module.
Using the pads to advance the hour/min/sec etc would tricky unless I can get a more controlled button action.
http://forums.parallax.com/showthread.php/137879-Chrono-dot-interface?p=1073753&viewfull=1#post1073753
[B]' untested[/B] repeat outa[23..16] := Buttons if byte[Buttons AND 000001] == 1 ' hit it? bit 0 [B]repeat while byte[Buttons AND 000001] == 1[/B] ' wait for release CountCogs WaitMS(20) ' when key press terminateor - there's that LONG PRESS thing that would be real handy here for auto-increment
something like?
repeat outa[23..16] := Buttons if byte[Buttons AND 000001] == 1 ' hit it? bit 0 tp_start := cnt repeat while byte[Buttons AND 000001] == 1 ' wait for release tp_end := cnt tp_time := tp_end - tp_start ' but doesn't allow for cnt rollover if tp_time >= tP_long then 'auto-bump the time 'and accellerate? - longer you hold it, the faster it goes else ' just inc/dec by onzies 'Maybe this will help.
Alarus.
Thanks
DUH!
Saving the buttons state byte into a variable (e.g. prevState) and only triggering the desired routine when the state changes pretty much eliminates the repeat action - as long as you make a firm, quick touch to the pad.
Holding your finger on the pad does not constitute a change either until you let go.
If you brush the pad or tentatively make contact you can get a repeat.
VAR byte btnState, prevState Buttons.start(_CLKFREQ / 100) ' Launch the touch buttons driver sampling 100 times a second dira[23..16]~~ ' Set the LEDs as outputs repeat btnState := Buttons.State outa[23..16] := btnState 'Buttons.State ' ' Light the LEDs when touching the corresponding buttons if btnState <> prevState ' has button state changed? prevState := btnState bitStatus := btnState & (|< 0) ' get bit 0 if bitStatus ' if high CountCogsTry that driver from Alarus.
It's small and tight and works right nice.
Try the CD4047 if you really want to add hardware. But I'd prefer to not do so.
That's kinda what he did, but in software...