asyncio newbie question #13690
Replies: 9 comments
-
I did a similar bit of playing just last weekend with the aim of working through some of @peterhinch tutorials and code he produces on async and switches and pushbuttons. The way I learn is to pinch his code but type it in to some code I produce to see if I can follow along. So your best bet is to have a deep peruse of https://github.com/peterhinch/micropython-async/blob/master/v3/README.md and some of Peters other readme files and to look at his switches and pushbutton classes. You will find interesting stuff relating to IRQ's v async polling for pushbuttons. In case it helps I give my weekend snippet all mostly copied from Peter Hinches examples. I was using it on a rpi pico w that was put on one of those nice Cryton makerboards that includes three pushbuttons attached. (not sure if those pushbuttons have any on board pullups but they work splendidly with the debounce interval that Peter puts in his code)
And if Peter happens to peruse this perhaps you could comment on
Anyway a big thanks to Peter for making my push buttons work with short, long, and very long pushes. Splendid stuff. |
Beta Was this translation helpful? Give feedback.
-
And its the next morning and I see I did not allude to your question of: " Anticipating a future question, what I would also like to do is to call a function when I press a button and then recall that very same function if the button is still pressed once that function has completed. Is there a way to do that? " I would think there is probably a solution based on asyncio button pressed, button released and function done events, but probably not if one is running different functions based on whether its a short or long press. ( but maybe the long press function to be run could be repeated I guess) The repeated calling of a function if the button is still pressed Im thinking along the lines that the button pressed function will call this other function which will need to send a flag (or event) to indicate its finished so as only to run one version of this function at a time. I may have a go at this tomorrow to help complete my foray into push buttons as its an interesting thought. However I expect you may well get to a good solution before I do :-) Just in case its of interest, the snippet I posted in previous reply was my first go at using the Peter Hinch event based push button stuff. I did go on to produce a more involved snippet based on a push button class and used it on a couple of pushbuttons to run some functions based on long and short presses that simply sleep for differing amounts of time for illustrative purposes. I post this more sophisticated code (all based on the Peter Hinch examples of course)
|
Beta Was this translation helpful? Give feedback.
-
Thanks for your replies. I’ve been reading the documentation on this stuff and I’m still trying to bang this stuff into my head. I’m now thinking that using events is the way to go here, but I’m still flailing around. |
Beta Was this translation helpful? Give feedback.
-
Well I gave the run a function when button pushed and run it again if still pushed a quick go with the asyncio events malarky and it was really rather a trivial task that took all of 10 minutes with a bit of cut and past. In the trivial example I enclose below the function blinks the pico on board LED on a button push and runs the function repeatedly whilst the button is still pressed. Not suggesting one would need all this asyncio event based push button polling to just blink on a button press, but I hope it illustrates the sort of code I was alluding to in my comment in the previous post. (now I will have to think of a more complicated thing to do for my Sunday programming hour :-o )
|
Beta Was this translation helpful? Give feedback.
-
@kb6nu Your code works fine here. Note that a long press causes the short press function to run once, followed by the long press. This is discussed under Re your second question here are three alternatives. Firstly using functions: def func():
# Actual payload code
def short_press(button):
func()
if button():
func()
pb = Pushbutton(pin)
pb.press_func( short_press, (pb,)) # Pass the button as an arg The second approach is to use coroutines. This is usually better because async def func():
# Actual payload code
async def short_press(button):
await func()
if button():
await func()
pb = Pushbutton(pin)
pb.press_func( short_press, (pb,)) # Pass the button as an arg The final option is to use an async def func():
# Actual payload code
async def do_short_press(button):
while True:
button.press.clear() # Clear any pending event
await button.press.wait() # Wait for a button press
await func() # Launch the coroutine and wait for completion
if button(): # If still pressed, launch the function again
await func()
pb = Pushbutton(pin)
pb.press_func(None) # use an Event
asyncio.create_task(do_short_press(pb)) |
Beta Was this translation helpful? Give feedback.
-
Thanks again for all your help so far. Can I ask another dumb question? I have four buttons on this hardware I’m trying to program. I’d like to call a single function if the user presses one of those buttons. Is there a way to simply pass an int to the routine called by the press_func method? Failing that, how do I extract the pin number form the pb instance of the Pushbutton object? And, more generally, is there a way to print the attributes of a MicroPython object? I tried a few things from the web that do this for Python objects, but they don’t seem to work in MicroPython. |
Beta Was this translation helpful? Give feedback.
-
This is the the way I'm interpreting your question. I'm thinking that you want some different actions to take place depending on the button that is pressed, but you want just one function to be called initially (perhaps to determine a long or short press or something like that) and that function must see which button was actually pressed to cause the desired action to run. But that what one of the examples above does in effect. In the example of the PinWatch class each instantiation of that class nominates the pin to watch and the function to run for that particular pin depending on a short, long or very long press. The example shows just two pins being used, but of course you can have as many pins as you want. However I fear I may not be grasping what you require and there are no doubt lots of different ways to achieve to same outcome so the example may not be what you want but on the face of it, it appears to do the job. I'm also not too clear on the printing attributes question and I presume a print(dir(pin22)) as taken from the instantiation of a PinWatch class is not what you are after. So hopefully over to a more enlighten one to give some better or alternative answers for you, but I though I would chime in with my answer in the hope that it helps. |
Beta Was this translation helpful? Give feedback.
-
You can pass anything you want. Consider these two lines from my above examples: pb = Pushbutton(pin)
pb.press_func(short_press, (pb,)) # Pass the button as an arg It's possible to pass In fact, passing the button itself as an arg (as in the example) also enables this to be done. Assume the buttons are global objects with names def short_press(button):
button_id = id(button)
if buttonid == id(Button1):
# Button 1 was pushed
elif buttonid == id(Button2):
# Button 2 was pushed |
Beta Was this translation helpful? Give feedback.
-
Thanks again. As I said, I’m a real newbie when it comes to Python, and I didn’t really understand the idea of a tuple of arguments. When I got my mind around that, I got it to work how I wanted. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I’m a newbie to the Pico and Micropython. I’ve started a project that uses a Pico and five pushbuttons for input. I did some coding with interrupts and polling and got some basic functionality to work, but then I discovered asyncio. It seems to me a better way of handling the pushbuttons than the way I was doing it.
I found some code in the documentation for micropython-async for the Pushbutton class in the DRIVERS.md file, and played around with it. Here’s what I came up with:
This detects short and long presses, but I’m either not using this properly, or the pushbutton presses aren’t getting debounced, because I’m getting output like this:
Anticipating a future question, what I would also like to do is to call a function when I press a button and then recall that very same function if the button is still pressed once that function has completed. Is there a way to do that?
Beta Was this translation helpful? Give feedback.
All reactions