Skip to content

Reading Button Presses

Reading GPIO inputs is a crucial component of creating responsive projects. In this guide we learn to read GPIO inputs by using a simple button to turn an LED on and off.
Written by: Jonathan Tynan
Last updated: Apr 27 2024


In this guide, we explore how to use the GPIO pins on a Raspberry Pi to read button presses. This ability is crucial for projects involving user input, like interactive installations or basic controls for robotics. We look at the basics of setting up a circuit with a button, how to use the SplashKit library to detect the button press and briefly introduce more advanced topics like the concept of floating pins and debouncing.

Components

Breadboard

Breadboards are invaluable for testing and building circuits without the need for soldering. Arranged in rows and columns of holes, each row internally connected. See Blink LED Tutorial for more details.

Push Button

A push button allows electricity to flow between its two contacts by physically moving strips of metal together when pressed. This connects the circuit and provides power to our input pin. This pushbutton has four pins and each diagonal pin is paired with each other. It’s a simple switch mechanism which we can detect and use.

Jumper Wires

Jumper wires connect our components on the breadboard to the Raspberry Pi and each other. We use M/F jumper wires for this setup. See Blink LED Tutorial for more details.

The Circuit

Below is the circuit diagram for this project. We connect the power and ground to the appropriate rails on the breadboard and connect our components ground or power connections to these rails. We can have the LED directly connected to Pin 11 on the Raspberry Pi, and the button to Pin 29.

Circuit Diagram for reading a button press

The physical circuit is show in the below image, where we can see the physical implementation of the provided circuit diagram. Note: The power and ground rail connections are swapped in the below image due to the orientation of the breadboard, ensure your connections are correct.

Photograph of circuit for reading a button press

The Code

#include "splashkit.h"
int main()
{
raspi_init();
pins button_pin = PIN_29;
pins led_pin = PIN_11;
pin_values led_state = GPIO_LOW;
raspi_set_mode(button_pin, GPIO_INPUT);
raspi_set_mode(led_pin, GPIO_OUTPUT);
raspi_set_pull_up_down(button_pin, PUD_DOWN);
open_window("dummy_window", 1, 1);
while(!any_key_pressed())
{
process_events();
if(raspi_read(button_pin) == GPIO_HIGH)
{
led_state = raspi_read(led_pin);
if(led_state == GPIO_LOW)
{
raspi_write(led_pin, GPIO_HIGH);
}
else
{
raspi_write(led_pin, GPIO_LOW);
}
}
}
close_all_windows();
raspi_cleanup();
return 0;
}

Understanding the code

Lets break down this code and analyse it in sections.

  1. raspi_init();
    pins button_pin = PIN_29;
    pins led_pin = PIN_11;
    pin_values led_state = GPIO_LOW;

    We start this code by initialising our hardware through Raspi Init, we then define the Pins that we’re are using for the button (Pin 29), and the LED (Pin 11). We also initialise a variable, led_state, to hold the state of the LED at any point in time. We use led_state later to determine whether to switch the LED on, or off.

  2. raspi_set_mode(button_pin, GPIO_INPUT);
    raspi_set_mode(led_pin, GPIO_OUTPUT);
    raspi_set_pull_up_down(button_pin, PUD_DOWN);

    We begin by setting the mode for each pin using Raspi Set Mode. The button pin is set to GPIO_INPUT and the LED pin is set to GPIO_OUTPUT. We do this as in this program we are detecting the input of the button and are writing the output of the LED. Then we use Raspi Set Pull Up Down on the button pin with the argument PUD_DOWN. This sets the internal pull-down resistor to prevent the pin from being a “floating pin.”

  3. open_window("dummy_window", 1, 1);
    while(!any_key_pressed())
    {
    process_events();
    ...
    }

    Just like in the first tutorial, we create a timer that limits how long our program runs for. We do this so we know that our pins are cleaned properly upon exiting the program.

  4. if(raspi_read(button_pin) == GPIO_HIGH)
    {
    led_state = raspi_read(led_pin);
    if(led_state == GPIO_LOW)
    {
    raspi_write(led_pin, GPIO_HIGH);
    }
    else
    {
    raspi_write(led_pin, GPIO_LOW);
    }
    }

    Above is the main section of this code. On each loop we read the state of the button pin using Raspi Read and if the result is GPIO_HIGH, then this indicates that the button has been pressed. We then read the state of the led, which can either be GPIO_LOW indicated the LED is not on, or GPIO_HIGH indicating that the LED is on. Once we have this state we can use Raspi Write to change the pin to the opposite of what has been read.

  5. close_all_windows();
    raspi_cleanup();
    return 0;

    Just like in the first tutorial and most projects involving GPIO pins, we must ensure that the hardware and resources we’ve used are cleaned properly, and we do this by stopping and freeing our timers and calling Raspi Cleanup.

Build and run the code

We can build this program with the following command:

Terminal window
g++ button_press.cpp -l SplashKit -o button_press

We can then run the program with the following command:

Terminal window
./button_press

GIF of the button press circuit in action.

Further Information

Floating Pins

A ‘floating’ pin is one that is not actively driven high (connected to some kind of power) or driven low (connected to ground). When this is the case the pin is said to be ‘floating’ as the state of the pin can change due to electrical noise or interference. If we were to read the pin in this state, then the value returned would be randomly either GPIO_HIGH or GPIO_LOW

In this tutorial we’ve used an internal pull-down resistor to prevent this. A pull-down resistor connects the pin to ground which effectively neutralises the electrical interference. Doing this ensures the pin only readsGPIO_LOW until the button is actually pressed and the pin is powered.

Debouncing

The button that is used in this tutorial works by physically moving a strip of metal against another strip of metal to complete a circuit. When you press or release the button, these electrical contacts can physically bounce and create multiple on-off signals. This phenomenon is known as ‘debouncing’ and can be remedied through hardware and software solutions. One basic way to address this in software is create a non-blocking delay when reading the input (in this case the button). To do this we record the time when we last read the input and take it away from the current time in the loop. We then only read the button when this result is greater than some interval we’ve set.