Shop OBEX P1 Docs P2 Docs Learn Events
Debounce Question — Parallax Forums

Debounce Question

civstercivster Posts: 17
edited 2005-07-05 03:09 in BASIC Stamp
Should PAUSE be used to debounce a button? I know BUTTON can be used but I've read something about losing time. I would like to keep away from Schmitt trigger input for it takes board space.

Below is a barebones version of the application that I'm developing:

SelBtn    PIN    13
Pressed    CON    0

Main:
DO
  DEBUG CLS, "Task 1"
  DO:LOOP until (SelBtn = Pressed)
  PAUSE 250
  DEBUG CLS, "Task 2"
  DO:LOOP until (SelBtn = Pressed)
  PAUSE 250
  DEBUG CLS, "Task 3"
  DO:LOOP until (SelBtn = Pressed)
  PAUSE 250
LOOP
END

Comments

  • Jon WilliamsJon Williams Posts: 6,491
    edited 2005-07-01 18:35
    Using PAUSE like that only confirms that the button was pressed before the PAUSE and after, not that there was contact bounce.· In many cases this is alright, but I prefer a simple subroutine that ensures the bounce has settled Like this (and this is scalable to any number of buttons).

    btn··· VAR··· Bit
    idx····VAR··· Nib

    ...

    Scan_Button:
    · btn = 1····················· ' assume pressed
    · FOR idx = 1 TO 10
    ··· #IF ActiveLow #THEN
    ····· btn = btn & ~BtnInput··· ' invert active-low input
    ··· #ELSE
    ····· btn = btn & BtnInput
    ··· #ENDIF
    ··· PAUSE 5
    · NEXT
    · RETURN

    The way this works the button must be pressed on entry and remain pressed without "bounce" through the routine -- a little longer than 50 ms.

    I've tossed in a bit of advanced trickery ... the symbol called ActiveLow is a conditional compliation constant; if it is not defined (or defined as 0) then the program will assume active-high input(s).· Yes, the routine uses PAUSE, but is loops through a group of short-duration pauses, checking for contact bounce in between.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
  • civstercivster Posts: 17
    edited 2005-07-05 02:45
    Jon,

    Thanks for your feedback. You are absolutely right about having a long duration of pause can be a disadvantage. In my current application, a POLLIN and POLLRUN are being used and if the application is in PAUSE, and the POLLIN pin is pulled low momentarily before PAUSE has finish executing, POLLRUN would never execute.

    One thing I still don't understand in your above code is why you inverse the variable btn every 5ms or so?

    For the original code I posted above, should a debounce subroutine suffice? The code would look something like this:

    SelBtn      PIN    13
    Pressed    CON    0
    idx           VAR   BYTE
    
    Main:
    DO
      DEBUG CLS, "Task 1"
      DO:LOOP until (SelBtn = Pressed)
      GOSUB DebounceBtn
      DEBUG CLS, "Task 2"
      DO:LOOP until (SelBtn = Pressed)
      GOSUB DebounceBtn
      DEBUG CLS, "Task 3"
      DO:LOOP until (SelBtn = Pressed)
      GOSUB DebounceBtn
    LOOP
    END
    
    'stay here for the next ~250ms to let SelBtn settle
    DebounceBtn:
    FOR idx 1 to 50
      PAUSE 5
    NEXT
    RETURN
    
    



    Thanks!
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2005-07-05 03:09
    The routine I suggested scans the input every 5 milliseconds for 10 iterations -- this means the button must stay closed for 50 milliseconds. If it bounces open during any of those checks the value will return as 0. The invert operator (~) is used when an active-low button is connected to the circuit as the logic ANDs the current button value with the input (so we need to turn active-low [noparse][[/noparse]0] high ).

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax

Sign In or Register to comment.