0

How can I handle button inputs in a while loop and at the same time refresh i2c data in a timely manner?

A while loop that watches for changes on the button pins can be run very quickly so that it is responsive, but I also want to update the i2c data once second. If I use time.sleep(1) at the end of the while loop, this is too slow of a reaction time for the buttons.

Code would look something like:

from machine import Pin
from time import sleep

up_button = Pin(13, Pin.IN)  

while True: 
  
  logic_state = up_button.value()
  if logic_state == True:
        print("Button Pressed") 
  else:

  update_ic2_data() # polling the i2c device for new data
  time.sleep(1) # sleeping for 1 second which is a good speed for i2c, but not very responsive for the button inputs. 
em-steven
  • 5
  • 1

1 Answers1

1

You can use an interrupt handler to detect the button press and change the state of a global variable to let the code inside your while loop know when to respond to it.

up_pressed = False

def handle_up_press:
  global up_pressed
  up_pressed = True

up_button = Pin(13, Pin.IN, Pin.PULL_UP)
up_button.irq(trigger=Pin.IRQ_FALLING, handler=handle_press)

while True:
  if up_pressed:
    print("Button Pressed")
    up_pressed = False
  update_ic2_data()
  time.sleep(1)

Or if the code to respond to the button press executes quickly (like changing the state of a GPIO output), you can just put it directly in the handler function. But things like longer running things print() are generally not recommended.

See this doc for more info: https://docs.micropython.org/en/latest/reference/isr_rules.html

Dave H.
  • 538
  • 5
  • 11
  • Bravo! Yes, that is what you want to do. Have the interrupt indicate when a button press occurs, generally catching the rising-edge (if pulled high, or the opposite if pulled low -- and handling the button bounce) and then set a global flag for follow-up processing in the man program while-loop. All significant processing should be done in the main while loop and interrupt functions kept to a bare minimum (don't forget to clear the interrupt in the interrupt function) – David C. Rankin Mar 18 '23 at 05:26
  • @DavidC.Rankin Can you expand on "don't forget to clear the interrupt in the interrupt function"? I took this example from some working code, but I don't have anything to clear the interrupt inside my handler. I'm wondering if I've forgotten something. – Dave H. Mar 19 '23 at 14:31
  • Sure. Any time an interrupt is triggered, what is actually happening is the bit corresponding to that interrupt is set to `1` in the interrupt register. That's how the chip knows the interrupt has fired. Each time it does, you need to clear the interrupt (set the `1` bit back to `0`) so the interrupt will trigger again at the end of whatever period or condition you have set (pin-high, pin-low, rising-edge, falling-edge, etc..) Most APIs will have a `clear_interrupt_...()` function. If not you do it manually by XOR'ing with an unsigned value with that bit set to `1`. – David C. Rankin Mar 20 '23 at 00:49
  • Thanks, that's the right way to go about it. I was missing the concept of interrupts completely. – em-steven Mar 21 '23 at 13:25