Page 1 of 2

Differentiate Double & Single Click of a button

Posted: Wed May 27, 2020 7:48 pm
by Mrfittingin
Hey guys
I have started to learn MicroPython recently, there is one problem I struggled for a while, I have been searching for solutions online and still have no clew what to do. Please help, Thanks.
This is the code, I have used aswitch.py module, I wish to achieve when I am double click the button, only the Yellow LED lights up( the Blue LED has no reaction while there is a double click of the button). and When this is long press, only the Green LED lights up. ( the Blue LED has no reaction while there is a long press of the button)
How should I change the Code to reach this function?

Code: Select all

from pyb import LED
from machine import Pin
import uasyncio as asyncio
from aswitch import Pushbutton

def toggle(led):
    led.toggle()

async def my_app():
    await asyncio.sleep(600)

pin = Pin('X1', Pin.IN, Pin.PULL_UP)  # Pushbutton to gnd
blue = LED(4)
yellow = LED(3)
green = LED(2)

pb = Pushbutton(pin)

pb.press_func(toggle, (blue,))  # Note how function and args are passed
pb.double_func(toggle, (yellow,))  # Note how function and args are passed
pb.long_func(toggle, (green,))  # Note how function and args are passed

loop = asyncio.get_event_loop()
loop.run_until_complete(my_app())  # Run main application code

Re: Differentiate Double & Single Click of a button

Posted: Wed May 27, 2020 9:18 pm
by kevinkk525
pb = Pushbutton(pin, suppress=True)

Should solve your problem.

Re: Differentiate Double & Single Click of a button

Posted: Thu May 28, 2020 12:17 pm
by Mrfittingin
Hey Kiven

Thank you for you help, I have added pb = Pushbutton(pin, suppress=True) into my code, but it did not work as I expected, the blue light always light up when the first click was pushed of the double click (same for the long press as well).

I wonder if there is any delay function or time frame interval function to let the full signal to go through, then start to process it?

I pasted the code down below.

Thank you!

Code: Select all

from pyb import LED
from machine import Pin
import uasyncio as asyncio
from aswitch import Pushbutton

def toggle(led):
    led.toggle()

async def my_app():
    await asyncio.sleep(600)

pin = Pin('X1', Pin.IN, Pin.PULL_UP)  # Pushbutton to gnd
blue = LED(4)
yellow = LED(3)
green = LED(2)

pb = Pushbutton(pin, suppress=True)


pb.double_func(toggle, (yellow,))  # Note how function and args are passed
pb.long_func(toggle, (green,))  # Note how function and args are passed

pb.press_func(toggle, (blue,))  # Note how function and args are passed

loop = asyncio.get_event_loop()
loop.run_until_complete(my_app())  # Run main application code

Re: Differentiate Double & Single Click of a button

Posted: Fri May 29, 2020 10:20 am
by pythoncoder
@Mrfittingin I think you have misunderstood the docs.

For a callback which occurs only on a single short press, you need to assign it to release_func and set suppress=True. As you have found, press_func still occurs on initial button press; this is by design. The reasoning is explained in the above doc. Note that response is necessarily delayed: this is also explained in the doc.

Re: Differentiate Double & Single Click of a button

Posted: Fri May 29, 2020 10:37 am
by kevinkk525
oh yes, thanks @pythoncoder. I missed the detail about having to use the release_func

Re: Differentiate Double & Single Click of a button

Posted: Mon Jun 01, 2020 2:24 pm
by Mrfittingin
Thank you so much for your help, problem solved!

Re: Differentiate Double & Single Click of a button

Posted: Fri Mar 05, 2021 2:51 am
by aerolite
Hello, I am new to micropython and have the same question for ESP32 board. Could anyone help me? I am using the M5ATOM stepper https://docs.m5stack.com/#/en/atom/atomic_step_motor I'd like to use single click to control the direction and double click to increase the speed.

thx

Code: Select all

import stepper
import lite
import machine
import time

last_button_press = 0

if (stepper.dcInput() == 0):
    lite.flashRed()
else:
    lite.flashGreen()

def move(irq):
    print(stepper.dcInput(),stepper.EN, stepper.DIR)
    
    if (stepper.dcInput() == 0):
        stepper.enable(False)
        stepper.setSpeed(1)
        lite.flashOFF()
        lite.flashRed()
        return
    
    if (stepper.EN == 0 ):
        stepper.enable()
        lite.flashOFF()
        lite.greenON(1)
    
    if (stepper.DIR == 0):
        stepper.direction(1)
        lite.flashOFF()
        lite.greenON(1)
    else:
        stepper.direction(0)
        lite.flashOFF()
        lite.blueON(1)
        
    print("button pressed"+str(stepper.DIR))

def double_click(inq):
    
    global last_button_press
    
    # Get the current date in milliseconds
    time_ms = time.ticks_ms()
    # Compute the elapsed time since the last interrupt
    delay = time.ticks_diff(time_ms, last_button_press)
    # If the delay is shorter than 200ms (your mileage may vary), consider this as a bounce
    if (delay < 200) :
        return
    # Else, we update the time of the last interrupt
    last_button_press = time_ms
    # If the delay is greater than 500ms (to be adjusted), it is a simple clock
    if delay > 600: # simple click
        move(1)
    else:
        stepper.setSpeed(stepper.SPEED+1)


button = machine.Pin(39, machine.Pin.IN, machine.Pin.PULL_UP)

button.irq(trigger = machine.Pin.IRQ_FALLING, handler = double_click)


Re: Differentiate Double & Single Click of a button

Posted: Fri Mar 05, 2021 10:40 am
by pythoncoder
See this doc which describes a Pushbutton class where you can define callbacks for single and double clicks.

Re: Differentiate Double & Single Click of a button

Posted: Mon Mar 29, 2021 1:49 am
by aerolite
Thank you for the information. But I still can't differentiate them. I use press and long function. when I long press the the press function still called. Here is my code and output. single press is good, but long press is not.

Code: Select all

def toggleRed():
    if (lite.lightStat()[0] == 0):
        lite.redON(1)
    else:
        lite.lightOFF(0)

    print( "red", lite.lightStat()[0] )

def toggleGreen():
    if (lite.lightStat()[1] == 0):
        lite.greenON(1)
    else:
        lite.lightOFF(0)
        
    print( "green", lite.lightStat()[1] )

async def my_app():
    await asyncio.sleep(60)  # Dummy

pin = Pin(39, Pin.IN, Pin.PULL_UP)  # Pushbutton to gnd
pb = Pushbutton(pin)
pb.press_func(toggleRed)  # Note how function and args are passed
#pb.double_func(toggleGreen)
pb.long_func(toggleGreen)
asyncio.run(my_app())  # Run main application code
red 64
red 0
red 64
red 0
red 64
red 0
red 64
red 0
red 64
green 64
red 64
green 64
red 64
green 64
red 64
green 64
red 64
green 64

Re: Differentiate Double & Single Click of a button

Posted: Mon Mar 29, 2021 6:35 am
by pythoncoder
when I long press the the press function still called.
This is a) inevitable and b) explained in the docs. At the time when you press a button, the driver doesn't yet "know" if the press is going to be a long one. See section 4.1.1, the "suppress" constructor arg.

As for your code, I suggest you start with the demo program making the minimum changes to accommodate ESP32 pin numbers. Then start adapting it for your own ends.