pin change interrupt + debouncing

All ESP8266 boards running MicroPython.
Official boards are the Adafruit Huzzah and Feather boards.
Target audience: MicroPython users with an ESP8266 board.
User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: pin change interrupt + debouncing

Post by pythoncoder » Mon Apr 09, 2018 5:39 pm

OutoftheBOTS_ wrote:
Mon Apr 09, 2018 10:07 am
@pythoncoder I just looked at your LCD160CR llibiary and this demo of it https://www.youtube.com/watch?v=OOz9U_YdstM

I am impressed.
Thanks, but I'm afraid that isn't my code :? That demo shows the speed of refresh but doesn't use the touch facility.

My GUI is a simplified touch interface which allows you to create objects like pushbuttons, sliders, dropdown lists and suchlike. These respond visually to touch and run callbacks like a very stripped down version of a tablet/phone GUI. Alas I haven't made a video but there are some stills on the link above.

@grafalex
The comments about CPU cycles are valid. However if you opt for the uasyncio approach (which I recommend) the module is based around polling. You don't have any option to control its usage of CPU cycles. If, in the context of a uasyncio application, you choose to use interrupts to interface to a specific device the only thing you will gain is performance.

In terms of detecting 1s pulses you will have no problem whatsoever unless your coroutines are badly designed. For example if you issue pyb.delay(3000) in a coroutine you'll miss pulses because you're stopping the scheduler for 3s. Issuing await asyncio.sleep(3) will fix the problem. In a sensibly designed application I'd expect response times to a switch state change to be under 50ms. The underlying speed of uasyncio context switching on a Pyboard is well under 1ms. In practice latency depends on the degree to which individual coroutines hog the CPU.

I have based some fairly complex (for the Pyboard) applications around my GUI code. I've yet to encounter a situation where the response to pressing a screen object wasn't visually instantaneous.
Peter Hinch
Index to my micropython libraries.

OutoftheBOTS_
Posts: 847
Joined: Mon Nov 20, 2017 10:18 am

Re: pin change interrupt + debouncing

Post by OutoftheBOTS_ » Mon Apr 09, 2018 8:19 pm

@dhylands

Code: Select all

the way I typically do it is that the interrupt handler disables itself and starts a debounce timer.
This is what I have done with Ardunio but I can't find out how to pause an interrupt in Micro-Python.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: pin change interrupt + debouncing

Post by dhylands » Mon Apr 09, 2018 10:43 pm

If you're using ExtInt to detect the pin change, then there is a disable/enable methods available:
http://docs.micropython.org/en/latest/p ... nt.disable

OutoftheBOTS_
Posts: 847
Joined: Mon Nov 20, 2017 10:18 am

Re: pin change interrupt + debouncing

Post by OutoftheBOTS_ » Tue Apr 10, 2018 3:44 am

If you're using ExtInt to detect the pin change, then there is a disable/enable methods available:
http://docs.micropython.org/en/latest/p ... nt.disable
Is this only available on the pyboard??

I have used the pin.irq in these docs http://docs.micropython.org/en/v1.9.3/e ... /pins.html


User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: pin change interrupt + debouncing

Post by pythoncoder » Wed Oct 03, 2018 7:20 am

The approach looks right but you really need to ensure that each pin uses a separate timer in case two pins change in quick succession. This would get expensive on timers if you had a lot of switches.

Another approach is to use uasyncio which avoids using hardware timers or interrupts. See this doc and code. This scales to any number of switches. Pushbutton objects also respond to long press and double-click events.
Peter Hinch
Index to my micropython libraries.


devxpy
Posts: 2
Joined: Sat Feb 03, 2018 5:26 pm

Re: pin change interrupt + debouncing

Post by devxpy » Fri Dec 07, 2018 7:14 pm

Here is an implementation @dhylands was suggesting; it seems to be working quite well. (Thanks!)

It does, however, introduce jitter and inconsistencies in registering inputs when multiple buttons, and hence multiple `Timer`s are used, like @pythoncoder sugggested. Polling certainly works better for multiple buttons

P.S. How do I properly format text here? (It shows BBcode is OFF :/)

DEBOUNCE_MS = 10

class BtnCallback:
def __init__(self, pin, send):
self.pin = pin
self.timer = Timer(pin)
self._tmp = None

def on_timer_end(self, _):
if self.pin.value() == self._tmp:
print("pressed!")
self._tmp = None

def __call__(self, _):
if self._tmp is not None:
return
value = self.pin.value()
if not value: # no need for debounce on a button release
print("released!")
else:
self._tmp = value
self.timer.init(
mode=Timer.ONE_SHOT,
period=DEBOUNCE_MS,
callback=self.on_timer_end,
)

pin = Pin(13, Pin.IN, Pin.PULL_UP)
pin.irq(handler=BtnCallback(pin))
Last edited by devxpy on Sat Dec 08, 2018 10:24 am, edited 1 time in total.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: pin change interrupt + debouncing

Post by dhylands » Fri Dec 07, 2018 8:27 pm

The correct way to format the code is to surround it in a code block. BBCode will automagically get turned on for your account once you've made enough posts that moderation is no longer required.

Post Reply