Handling Inputs with the Raspberry Pi Pico

In this installment of How to Program a Raspberry Pi Pico with Rust, I’m configuring a controller to receive inputs and describing some control logic for evaluating those inputs. You can check out my GitHub Repo for my project called PicoPonics if you want to see some examples of a system in the field now, handling inputs.

What is Input Handling?

a diagram of a temperature sensor and a pressure sensor hooked into a microcontroller

How does the Raspberry Pi Pico handle inputs?

Handling an input from a field device means receiving and interpreting a signal from a sensor or device that can provide that type of signal.

A push button can be considered a field device but is more commonly referred to as an input device. In the graphic above we see a temperature sensor and a pressure sensor, but we’ll focus on the button for now, as it’s almost always a discrete / digital input.

Receiving the signal

This part is often more difficult than programming the logic for dealing with the signal. But in the ideal world, there isn’t much more to it than:
1. wiring the device to the proper input

2. configuring the input to recognize the incoming signal

Interpreting the Signal

Signals produced by various instrumentation aren’t always exactly ‘common sense’. But even in cases where they are, to interpret a signal conduct the following:

  1. Translate the signal into data that is meaningful to the context of the program.

  2. Incorporate control logic to handle carrying out actions based on that new meaningful data

 

Here is a list of things that must be understood to handle an input:

  1. What type of IO Pin configuration is needed to properly receive the signal from the device in the field.

  2. Safety Risks

  3. How to write code to make decisions based on input state changes

  4. How to compile that code into a format that is recognizable to the target microcontroller

  5. How to move that code onto the controller (write / flash)

  6. How to wire up the GPIO to the sensor or device that will provide the input signal.

 

Tell the Microcontroller How to Interpret Incoming Signals

a diagram of a goofy microcontroller is wired into an input and it doesn't know how to interpret what signals are coming in

A controller needs to know how to interpret incoming signals

Just like we covered in the last post, the GPIO on the Pico need to be configured in the program. They are very general, and explicit instruction on how to behave is a requirement.

 
let gp15 = pins.gpio15.into_pull_down_input();
 

In this code above, GPIO Pin 15 is configured to act as a pull down input.

When a pin is a pull-down input, the goal is for the reference voltage at rest to be as near 0VDC as possible. When a voltage from a field device goes high, that’s becomes a logical high for the input, and it will be recognized by the controller as being active. The button we mentioned before will provide 5VDC to the input pin, and while it’s pressed, that pins value will read as true.

Setting Up Pins using a Hardware Abstraction Layer (HAL)

a diagram showing some configuration knobs that seem to be attached to a single pin on a controller

The below example shows how the HAL is imported into the file, then used to configure a variable called pins. This variable has all the power once created over how the pins will be configured.

If you’re interested to write your own code straight away, you can download my Super Blank Pico Project Repo, and start monkeying around with the pins variable in there to get some stuff happening on your own pico. The HAL I’m using is rp-hal from the rp-rs team.

 

// A shorter alias for the Peripheral Access Crate, which provides low-level

// register access

use hal::pac;

// The single-cycle I/O block controls our GPIO pins

let sio = hal::Sio::new(pac.SIO);

// Set the pins to their default state

let pins = hal::gpio::Pins::new(

pac.IO_BANK0,

pac.PADS_BANK0,

sio.gpio_bank0,

&mut pac.RESETS

);

// Configure a pin to be used as an output pin

let gp15 = pins.gpio15.into_pull_down_input();

 

I’ll once again link to a previous post for more information on what the above code is doing. For our purposes today, the value we’ll want to read is from the variable gp15 and will contain the true/false value we’d be expecting to represent our button state.

Writing Control Logic

a pencil drawing of an unlabelled, uncommented ladder logic diagram

Handling a button is mostly just figuring out what the button should do in the context of the program, and what should happen when it changes from true -> false or from false -> true.

 

// is_high would mean the button is pressed (if it’s a normally open button)

if gp15.is_high().unwrap() {

// Do something when the button is pressed

}


You can also check directly if the input is low

 

// is_low would mean the button is not pressed (if it’s a normally open button)

if gp15.is_low().unwrap() {

// Do something when the button is not pressed

}

 

The decision on what to do when the button is high or low it up to the designer. Could be setup for immediate effect, or just for logical effect like a counter.

Conclusion

We've covered what an input is, how to configure them, and some basics of handling them. With this information, it’s possible to start getting project work done with the Raspberry Pi Pico and Rust.

If you’ve got questions or if something in this article wasn’t clear, please let me know by one of the contact methods listed below, and I’ll come back through and update the article for clarity.

Previous
Previous

Understanding Iterators in Rust

Next
Next

Understanding GPIO using the Raspberry Pi Pico