Close

RasPi Button debounce in python

A project log for Potpourri

Definition: A mixture of things, especially a musical or literary medley

peter-walshPeter Walsh 11/18/2019 at 17:220 Comments

I needed to debounce a RasPi button in python, and found that the software in this link has problems: sometimes the button press is ignored.

Here's an improved version fixing the problem. It uses the GPIO hardware to initially detect the button press (rising or falling, or both) then uses a timer to detect changes in state for a user-selected debounce time.

A full library file implementation "Button.zip" can be found in the project files section, along with a simple test program.

DEBOUNCE_MS = 50                        # Debounce time, in ms
UPDATE_MS   = 5                         # Update/check time, in ms

class ButtonHandler(threading.Thread):
    def __init__(self, pin, func, edge='both', bouncetime=200):
        super().__init__(daemon=True)

        self.edge = edge
        self.func = func
        self.pin = pin
        self.bouncetime = bouncetime
        self.bounceleft = bouncetime
        self.bouncing   = 0
        self.prevpinval = GPIO.input(self.pin)

    def __call__(self, *args):
        if self.bouncing:
            return

        self.bouncing   = 1
        self.bounceleft = self.bouncetime
        self.prevpinval = GPIO.input(self.pin)
        self.timer = threading.Timer(UPDATE_MS/1000.0, self.Tick, args=args)
        self.timer.start()

    def Tick(self, *args):
        pinval = GPIO.input(self.pin)

        if self.edge == GPIO.RISING  and pinval == 0:
            self.bouncing = 0
            return

        if self.edge == GPIO.FALLING and pinval == 1:
            self.bouncing = 0
            return

        if pinval != self.prevpinval:
            self.bounceleft = self.bouncetime

        self.bounceleft -= UPDATE_MS

        if self.bounceleft <= 0:
            self.bouncing   = 0
            self.func(*args)
            self.prevpinval = pinval
            return

        self.prevpinval = pinval
        self.timer = threading.Timer(UPDATE_MS/1000.0, self.Tick, args=args)
        self.timer.start()

Discussions