Page 2 of 3

Re: Debouncing with IRQ

Posted: Wed Feb 14, 2018 2:56 pm
by SpotlightKid
Look at the test_machine function at the bottom of the Gist code. Just replace value for the swpin parameter with the pin number you want (i.e. 23) and the second and third arg to the DebouncedSwitch switch constructor with the callback function and its argument.

Here's a really reduced example:

Code: Select all

from debounce import DebouncedSwitch
from machine import Pin

def mycallback(arg):
    print("Switch toggled", arg)

sw = DebouncedSwitch(Pin(23, Pin.IN), mycallback, "dummy")

Re: Debouncing with IRQ

Posted: Wed Feb 21, 2018 8:14 pm
by dubaleeiro
Thanks a los.
It worked like a charm !

Re: Debouncing with IRQ

Posted: Fri Feb 23, 2018 6:41 pm
by sebbalex
@SpotlightKid
Thanks for the code, very useful!
The callback is called with only RISING event trigger, is there a chance to get it working with both events
RISING and FALLING ?
thanks a lot

Re: Debouncing with IRQ

Posted: Sat Feb 24, 2018 7:21 pm
by SpotlightKid
sebbalex wrote:
Fri Feb 23, 2018 6:41 pm
is there a chance to get it working with both events RISING and FALLING ?
Yes, for this you'll have to pass a machine.Pin object to DebouncedSwitch as the first argument and change line 37 and 43 to pass a value for the trigger parameter (note that self._set_cb is an alias name for the irq method of your Pin instance here):

Code: Select all

        self._set_cb(self._sw_cb if cb else None, trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING)
See the documentation on possible values for the trigger parameter:

http://docs.micropython.org/en/latest/p ... ne.Pin.irq

I'll leave it as an exercise to the reader to add an additional constructor parameter for the trigger event to the DebouncedSwitch class.

Re: Debouncing with IRQ

Posted: Sat Feb 24, 2018 10:22 pm
by sebbalex
first thanks for the update!

I tried as you mentioned but I can't figure it out why it is not working, even after those change only RISING event
is fired..

this is my class instance:

[code]
v = x #dynamic id in a loop
p = machine.Pin(v, machine.Pin.IN, machine.Pin.PULL_UP)
sw = DebouncedSwitch(p, pub_cb, [v,p.value()])
[/code]

Re: Debouncing with IRQ

Posted: Sun Feb 25, 2018 1:46 pm
by SpotlightKid
Sorry, I overlooked the "if self.sw():" statement in line 35. The code will not work for handling callbacks on the rising and falling edge as is. I'll put a version below that does but it doesn't work very well, due to timing issues. The callback for the rising edge is fired with a very noticable delay. I guess this is due to the use of micropython.schedule.

So I recommend using another debouncing approach in your case. Unfortunately I don't have the time at the moment to offer a solution.

Code: Select all

#
# inspired by: https://forum.micropython.org/viewtopic.php?t=1938#p10931
#
import micropython

try:
    from machine import Timer
    timer_init = lambda t, p, cb: t.init(period=p, callback=cb)
except ImportError:
    from pyb import Timer
    timer_init = lambda t, p, cb: t.init(freq=1000 // p, callback=cb)

# uncomment when debugging callback problems
#micropython.alloc_emergency_exception_buf(100)


class DebouncedSwitch:
    def __init__(self, sw, cb, arg=None, delay=50, tid=4):
        self.sw = sw
        # Create references to bound methods beforehand
        # http://docs.micropython.org/en/latest/pyboard/library/micropython.html#micropython.schedule
        self._sw_cb = self.sw_cb
        self._tim_cb = self.tim_cb
        self._set_cb = getattr(sw, 'callback', None) or sw.irq
        self.delay = delay
        self._last = -1
        self.tim = Timer(tid)
        self.callback(cb, arg)

    def sw_cb(self, pin=None):
        self._set_cb(None)
        self._last = self.sw()
        timer_init(self.tim, self.delay, self._tim_cb)

    def tim_cb(self, tim):
        tim.deinit()
        if self.sw() == self._last:
            self._last = -1
            micropython.schedule(self.cb, self.arg)
        self._set_cb(self._sw_cb if self.cb else None)

    def callback(self, cb, arg=None):
        self.tim.deinit()
        self.cb = cb
        self.arg = arg
        self._set_cb(self._sw_cb if cb else None)


def test_pyb(ledno=1):
    import pyb
    sw = pyb.Switch()
    led = pyb.LED(ledno)
    return DebouncedSwitch(sw, lambda l: l.toggle(), led)


def test_machine(swpin=2, ledpin=16):
    from machine import Pin
    sw = Pin(swpin, Pin.IN)
    led = Pin(ledpin, Pin.OUT)
    return DebouncedSwitch(sw, lambda l: l.value(not l.value()), led)

Re: Debouncing with IRQ

Posted: Thu Mar 01, 2018 9:17 am
by sebbalex
SpotlightKid wrote:
Sun Feb 25, 2018 1:46 pm
Sorry, I overlooked the "if self.sw():" statement in line 35. The code will not work for handling callbacks on the rising and falling edge as is. I'll put a version below that does but it doesn't work very well, due to timing issues. The callback for the rising edge is fired with a very noticable delay. I guess this is due to the use of micropython.schedule.

So I recommend using another debouncing approach in your case. Unfortunately I don't have the time at the moment to offer a solution.
Thank you anyway, this code is working but as expected there is a huge delay sometimes.
Maybe I should move to a different approach or use the uasyncio library that should have this behaviour built in.

Re: Debouncing with IRQ

Posted: Thu Mar 01, 2018 9:24 am
by pythoncoder
I was going to suggest uasyncio but I haven't used the WiPy V1.0 for a long time and I don't know how well it is supported. If you do use it you'll find asynchronous, debounced drivers for switches and pushbuttons here (aswitch.py).

Re: Debouncing with IRQ

Posted: Fri Mar 02, 2018 10:55 pm
by dubaleeiro
@SpotlightKid
I am trying to use the DebouncedSwitch to pause a loop which displays the current time in a 7-segment display, and when I execute the following code, the callback behaves as if I had pushed the button:

Code:
def cbButMenu(arg):
print(arg, 'value')
main_menu()
return

debMenu = DebouncedSwitch(butMenu, cbButMenu, "butMenu")

while True:
curTime = rtc.datetime()
display_time(curTime.hour, curTime.minute)
if cbButMenu("butMenu"):
break

Debbuging:
........
download ok
exec(open('./test4.py').read(),globals())
butMenu value
>>>

could you please point what am I doing wrong here...?

Re: Debouncing with IRQ

Posted: Sun Mar 04, 2018 2:42 pm
by SpotlightKid
You are calling the cButMenu callback function explicitly within the for loop (with the same argument as it would be called by the DebouncedSwitch callback). don't do that.