The Pico In MicroPython: Simple Input
Written by Harry Fairhead & Mike James   
Monday, 17 January 2022
Article Index
The Pico In MicroPython: Simple Input
Press and Hold

If you change PULL_UP to PULL_DOWN, the way the switch is connected becomes:

switch2

The program still works, but now GP22 is high when the switch is pressed and hence the LED is on when the switch is pressed.

Should you use an internal or external resistor? The answer is that it mostly doesn’t matter as long as there is a resistor. The only problem with using an internal resistor is the possibility that the software fails to set the pull-up/down mode and leaves the input floating.

Also notice that this switch input is not debounced. The simplest way to do this is include a time delay in the loop before the line is sampled again.

If you want to respond to a button press, that is a press and a release event, then you have to test for a double transition:

from machine import Pin
import time
pinIn = Pin(22, Pin.IN,Pin.PULL_DOWN)
pinLED = Pin(25, Pin.OUT)
while True:
    while pinIn.value()==0:
        pass
    while pinIn.value()==1:
        pass
    pinLED.on()
    time.sleep(1)
    pinLED.off()

In this case you really do need the debounce delays if you want to avoid responding twice to what the user perceives as a single press.

A 1‑millisecond delay is probably the smallest delay that produces a button that feels as if it works. In practice, you would have to tune the delay to suit the button mechanism in use and the number of times you can allow the button to be pressed in one second.

Press Or Hold

You can carry on elaborating on how to respond to a button. For example, most users have grown accustomed to the idea that holding a button down for a longer time than a press makes something different happen.

To distinguish between a press and a hold all you need to do is time the difference between line down and line up:

from machine import Pin
import time
pinIn = Pin(22, Pin.IN,Pin.PULL_DOWN)
pinLED = Pin(25, Pin.OUT)
while True:
    while pinIn.value()==0:
        pass
    t=time.ticks_ms()
    time.sleep_ms(1)
    while pinIn.value()==1:
        pass
    t=time.ticks_diff(time.ticks_ms(),t)
    if t<2000:
        pinLED.on()
        time.sleep(1)
        pinLED.off()
    else:
        for i in range(10):
            pinLED.on()
            time.sleep_ms(100)
            pinLED.off()
            time.sleep_ms(100)

In this case holding the button for 2s registers a “held” – the LED flashes 10 times and anything less is a “push” – the LED flashes just once. Notice the 1ms debounce pause between the test for no-press and press.

One of the problems with all of these sample programs is that they wait for the button to be pressed or held and this makes it difficult for them to do anything else. You have to include whatever else your program needs to do within the loop that waits for the button – the polling loop. You can do this in an ad hoc way, but the best approach is to implement a finite state machine, see later.

How Fast Can We Measure?

Buttons are one form of input, but often we want to read data from a GPIO line driven by an electronic device and decode the data. This usually means measuring the width of the pulses and this raises the question of how fast can we accept input?

The simplest way to find out how quickly we can take a measurement is to perform a pulse width measurement. Applying a square wave to GP22 we can measure the time that the pulse is high using:

from machine import Pin
import time
pinIn = Pin(22, Pin.IN)
while True:
    while pinIn.value()==1:
        pass
    while pinIn.value()==0:
        pass
    t=time.ticks_us()
    while pinIn.value()==1:
        pass
    t=time.ticks_diff(time.ticks_us(),t)
    print(t)
    time.sleep(1) 

This might look a little strange at first. The inner while loops are responsible for getting us to the right point in the waveform. First we loop until the line goes low, then we loop until it goes high again and finally measure how long before it goes low. You might think that we simply have to wait for it to go high and then measure how long till it goes low, but this misses the possibility that the signal might be part way through a high period when we first measure it. This can be measured down to around 30µs with a very poor accuracy at this limit and an accuracy of 5 to 10µs for longer times .

Notice that in either case if you try measuring pulse widths much shorter than the lower limit that works, you will get results that look like longer pulses are being applied. The reason is simply that the Pico will miss the first transition to zero but will detect a second or third or later transition. This is the digital equivalent of the aliasing effect found in the Fourier Transform or general signal processing. 

 

MicroPython also provides a special method that implements the algorithm used in the above program. The method:

machine.time_pulse_us(pin, level, timeout)

will block until the pin specified changes to the level specified or the timeout occurs. Once the pin attains the level specified it times how long it takes for it to change and returns the result in microseconds. The only problem is that, if the pin is already at the specified level, the timing begins at once.

Using this method the program above can be written more simply as:

import time
import machine
pinIn = machine.Pin(22, machine.Pin.IN)
while True:
    t = machine.time_pulse_us(pinIn, 1)
    print(t)
    time.sleep(1)

Notice that you will get some fractional measurements using this method. To get accurate results you would have to be sure that the line was at zero just before the method is used. For example:

import machine
import time
import machine
pinIn = machine.Pin(22, machine.Pin.IN)
while True:
    while pinIn.value() == 1:
        pass
    t = machine.time_pulse_us(pinIn, 1)
    print(t)
    time.sleep(1)

The time_pulse_us method is not a big improvement on the more basic way of doing the job, but it is more accurate for lengthier intervals.

In chapter but not in this extract

  • The Finite State Machine
  •  FSM Button
  •  FSM Hold Button
  •  FSM Ring CounterSummary

Summary

  • Input is hard because things happen at any time, irrespective of what your program might be doing.

  • You can call the value method at any time to discover the state of a GPIO line – the problem is when and how often to call it.

  • You can chose between external or internal pull-up/down resistors.

  • Mechanical input devices such as buttons have to be debounced.

  • The power of software is that it can enhance a simple device. A simple button is either pushed or released, but you can use this to generate a third “held” state.

  • Using a polling loop you can handle inputs as short as a few tens of microseconds.

  • Most IoT programs are best written as a polling loop.

  • The Finite State Machine (FSM) is one way of organizing a complex polling loop so that inputs are tested and outputs are set once for each time through the loop.

  • Ideally the states of a FSM should not be simple statements of the inputs of outputs that determine the state, but for simple systems this can be difficult to achieve.

  • It can be difficult to work out what constitutes the events of a FSM. Ideally they should be localized in time so that they indicate the moment that something happens.

 

 

Programming the Raspberry Pi Pico In MicroPython

By Harry Fairhead & Mike James

picoPython360

Buy from Amazon.

Contents

  • Preface
  • Chapter 1 The Raspberry Pi Pico – Before We Begin
  • Chapter 2 Getting Started
  • Chapter 3 Getting Started With The GPIO
  • Chapter 4 Simple Output
  • Chapter 5 Some Electronics
  • Chapter 6 Simple Input
             Extract: Simple Input ***NEW!
  • Chapter 7 Advanced Input – Events and Interrupts
  • Chapter 8 Pulse Width Modulation
             Extract: PWM 
  • Chapter 9 Controlling Motors And Servos
             Extract: DC Motors
  • Chapter 10 Getting Started With The SPI Bus
  • Chapter 11 A-To-D and The SPI Bus
  • Chapter 12 Using The I2C Bus
  • Chapter 13 Using The PIO   
  • Chapter 14 The DHT22 Sensor Implementing A Custom Protocol
             Extract: A PIO Driver For The DHT22  
  • Chapter 15 The 1‑Wire Bus And The DS1820
  • Chapter 16 The Serial Port
  • Chapter 17 WiFi Using The ESP8266
  • Chapter 18 Direct To The Hardware
             Extract: Direct To The Hardware

<ASIN:1871962692>

<ASIN:B09522FQRY>

<ASIN:1871962684>

<ASIN:B093LT5W54>

 

 

 

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

Banner


GraalVM's Alignment With OpenJDK Signifies A New Era For Java
10/11/2022

Oracle will be contributing GraalVM Community Edition Java Code to OpenJDK. There's a lot behind this simple statement. But before that, let's first look at what GraalVM actually does.



Meet Speedfolding The Shirt Folding Robot
06/11/2022

An international team of robotics researchers has developed a new robot for folding laundry. SpeedFolding is described as being reliable and efficient. Whether the 'speed' bit of the name is justified [ ... ]


More News

picobook

 



 

Comments




or email your comment to: comments@i-programmer.info

 

 



Last Updated ( Friday, 18 March 2022 )