Button presses register multiple times



  • Hello!
    I am right now making my LoPy4 send some data to a LoRa-gateway and change the color of the rgb light whenever I press the S1 button on my expansion board v3.1. However, it's not very responsive. The LoRa payload seems to be pretty quick, but it sometimes takes several seconds before the light changes color. Also the biggest issue is that for whatever reason, one click can sometimes register twice??

    Look here in my LoRa gateway data, this is the result of ONE button press.

    f11c4767-a06f-4114-8e1f-8c9dcca8112f-image.png

    So I pressed the button, it sent a message, and then for whatever reason it had a rising edge also 3 seconds later. This is very odd, and I am certain I did not press the button, and I have seen the same behavior when just printing inside the button callback function.

    This is the code for the button. I have tried using PULL_DOWN instead to see if there were some floating values fucking me over, but it had the same behavior.

    btn = Pin('G17', mode=Pin.IN, pull=Pin.PULL_UP)
    btn.callback(trigger=Pin.IRQ_RISING, handler=rnd_triage)
    


  • @robert-hh Thanks! I tried pulling a cable between two pins using the following code.

    count = 0
    def rnd_triage(arg):
        global count
        print("callback fired", count)
        count += 1
    
    p = Pin('P13', mode=Pin.IN, pull=Pin.PULL_DOWN)
    p.callback(trigger=Pin.IRQ_RISING, handler=rnd_triage)
    
    t = Pin('P12', mode=Pin.OUT, pull=None, alt=-1)
    
    while True:
        time.sleep(3)
        t.value(0)
        time.sleep(3)
        t.value(1)
    

    It seems to be working quite well at least, so maybe I will just endure the button performance for now. Thanks a lot for the help!



  • @robertsehlstedt There are many attempts for debouncing, both in software and hardware. As an example, I quick-hacked together some code, based on a time interrupt and a low pass filter.

    #
    from machine import Pin, Timer
    from time import sleep_ms
    
    btn = Pin('P10', mode=Pin.IN, pull=Pin.PULL_UP)
    
    state = False
    btn_state = 1
    
    LIMIT_ON = 0.1
    LIMIT_OFF = 0.9
    TIME_CONSTANT = 0.25
    
    def switch_state(p):
        global btn_state, state
        # low pass filtering of the input valeue
        btn_state += TIME_CONSTANT * (btn.value() - btn_state)
        if btn_state < LIMIT_ON:
            if state == False:
                print("Button pressed")
            # may schedule something else here, like sending a message
            state = True
        elif btn_state > LIMIT_OFF:
            if state == True:
                print("Button released")
            state = False
    
    alarm = Timer.Alarm(switch_state, 0.01, periodic = True)
    
    while True:
        sleep_ms(100)
    
    


  • @robert-hh I tried something similar to you and yeah I keep getting similar results where there are two button presses registered. I am not sure if I am following you, but it seems like there is nothing to be done about it? For the moment I am using the button to just demo some functionality, but in the future we will use other pins. I hope they won't have the same behaviour!



  • @robertsehlstedt So you tried a callback that just prints the message? Using that little script, I get quite a few responses. And the sleep in the callback causes events to seem happening later.

    #
    from machine import Pin
    from time import sleep_ms
    
    count = 0
    def rnd_triage(p):
        global count
        print("callback fired", count)
        sleep_ms(1000)
        count += 1
    
    
    while True:
        btn = Pin('P10', mode=Pin.IN, pull=Pin.PULL_UP)
        btn.callback(trigger=Pin.IRQ_FALLING, handler=rnd_triage)
        sleep_ms(100)
    
    

    Besides that, I'm not saying the the problem is at the server end. The problem is local, but LoRa might not send a second message before the RX2 periods of the first message has passed, and the scheduler for callbacks might not schedule the next callback before the message sending has been finished.
    The callbacks a not ISR's. Whenever an interrupt happens, it is just registered and the callback is added to a queue and executed whenever it's time to do so. There is no guarantee for a timely service.



  • @robert-hh Also I do want to say, to clear up any confusions here - that if I just make a button callback function which prints "Button pressed" or something like that, actually I can clearly see that sometimes when I click the button, it will register once, and then again a few seconds later. Which means that the delay probably isn't on the server end.



  • @robert-hh Alright thanks! Is there some way to avoid it?



  • @robertsehlstedt buttons use to bounce, so there may be various events in ms time distance, which have bee registered and processed later. Since a server may respond to any message after one or two seconds, the LoRa stack most likely waits for that time before sending the next message. The three seconds you see is well within the uncertainty of the time taking.


Log in to reply
 

Pycom on Twitter