was_pressed equivelant for IO pins

Questions and discussion about running MicroPython on a micro:bit board.
Target audience: MicroPython users with a micro:bit.
Post Reply
plantpot
Posts: 1
Joined: Tue Jul 30, 2019 11:48 pm

was_pressed equivelant for IO pins

Post by plantpot » Tue Jul 30, 2019 11:50 pm

I am wanting to create a simple button counter using the IO pins instead of the A/B buttons. With the buttons this is easy because of:

is_pressed()
Returns True if the specified button button is pressed, and False otherwise.

was_pressed()
Returns True or False to indicate if the button was pressed since the device started or the last time this method was called.

With the IO pins, there is no was_pressed, only is_touched. How can I create a counter that will wait until is_touched is False?

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: was_pressed equivelant for IO pins

Post by jimmo » Wed Jul 31, 2019 5:59 am

The way was_pressed works for the buttons is that every 6ms, the MicroPython firmware checks the state of the buttons (which are on pins 5 and 11), and compares them to what state they were 6ms ago. If they go from unpressed to pressed, it sets a flag, which is what was_pressed() returns. was_pressed() also clears the flag.

Unfortunately in micro:bit MicroPython (unlike main MicroPython), you don't have a way to set up a timer to run code in the background, so you have to do that manually in your main loop. The same approach works if you want to use a pin's value (i.e. because it's connected to an external button).

(Sorry this code is untested, but hopefully illustrates what needs to happen).

Code: Select all

pin0_flag = False
pin0_last_state = False

def check_pin0_touch():
  global pin0_flag, pin0_last_state
  pin0_state = pin0.is_touched()
  if pin0_state and not pin0_last_state:
    pin0_flag = True
  pin0_last_state = pin0_state

def pin0_was_touched():
  global pin0_flag
  result = pin0_flag
  pin0_flag = False
  return result

while True:
  check_pin0_touch()
  
   .. other program things...
   
    if pin0_was_touched():
      .. increment counter..
This gets a bit messy if you want to handle multiple pins. A nicer way to do this would be to make a class:

Code: Select all

class WasTouchedPin:
  def __init__(self, pin):
    self._pin = pin
    self._flag = False
    self._last_state = False
    
  def check(self):
    .. same as check_pin0_touch above ..
    
  def was_touched(self):
    .. same as was_touched above ...
    
touch_pins = [WasTouchedPin(pin0), WasTouchedPin(pin1), WasTouchedPin(pin2)]
while True:
  for p in touch_pins:
    p.check()
   
  .. now you can write touch_pins[2].was_touched()
BUT... if you want a counter, you don't really care about was_touched, you just want ... well.. a counter:

Code: Select all

class PinCounter:
  def __init__(self, pin):
    self._pin = pin
    self._count = 0
    self._last_state = False
    
  def check(self):
    state = self._pin.is_touched()
    if state and not self._last_state:
      self._count += 1
    self._last_state = state
    
  def count(self):
    result = self._count
    self._count = 0
    return result
    
counter_pins = [PinCounter(pin0), PinCounter(pin1), PinCounter(pin2)]
while True:
  for p in counter_pins:
    p.check()
   
  .. now you can write counter_pins[x].count() to get the count since last time you checked ...
But the problem with all of these approaches is that it means that you can't use sleep() anywhere in your code, because while you're sleeping your main loop isn't looping. So you need a different way to measure time passing. At my last job we spent a lot of time teaching micro:bits, and I wrote this article that might be relevant to this: https://medium.com/groklearning/become- ... b8b4e2d747

Post Reply