Electronics Software Development

Blink: Making An LED Blink On A Raspberry Pi

Blink Red LEDs
Written by John Woolsey

Last Updated: January 16, 2023
Originally Published: June 20, 2018

Skill Level: Beginner

Table Of Contents

Introduction

This tutorial will teach you how to connect and control an LED on a Raspberry Pi development board using the C, C++, and Python programming languages with multiple libraries. We will even cover how to control a pin directly from the command line.

If you are interested in using CircuitPython, you can also check out our Getting Started With CircuitPython On Raspberry Pi With Blinka tutorial once you finish this one.

A basic understanding of electronics and programming is expected along with some familiarity with the Raspberry Pi platform.

Fully commented versions of all source code used in this tutorial are available on GitHub for your reference.

What Is Needed

Background Information

A light emitting diode (LED) is a semiconductor device that emits light when energized and comes in an assortment of different colors. It is similar to a light bulb, but is much smaller and consumes much less power. LEDs are typically used as indicator lights in consumer electronics.

A solderless breadboard will be used to assemble the electronic circuit. These breadboards allow engineers and hobbyists to construct circuits without having to permanently (for the most part) attach your electronic components or have to deal with soldering them together. If you are not familiar with solderless breadboards, the Core Electronics’ How to Use Breadboards, and Science Buddies’ How to Use a Breadboard guides are good resources for learning how to use one.

The Raspberry Pi Foundation is the official source for all things Raspberry Pi and is a great resource for buying and learning about the Raspberry Pi. Their Documentation page is a good place to start if you are new to the Raspberry Pi platform. You will find helpful guides and documentation there to help you start setting up and configuring your new Raspberry Pi. I recommend you take a look if you haven’t already.

Since the Raspberry Pi is an actual small computer running its own operating system, you can either attach your own monitor, keyboard, and mouse and use it like a simple desktop computer, or alternatively, you can remotely connect to it across a network using a secure shell command, like ssh, or utility, like putty. I connect with my Raspberry Pi over a network using ssh from a macOS based computer. If you are interested in connecting yours over a network, please see the Remote access documentation for instructions.

Although the Raspberry Pi can run a variety of different operating systems, Raspberry Pi OS is the officially recommended OS maintained and distributed by the Raspberry Pi Foundation and is the default OS on most Raspberry Pi systems. It is based on the standard Debian Linux distribution. C, C++, Erlang, Java, Javascript, Perl, Python, Ruby, Scratch, and Wolfram are just some of the programming languages that come preinstalled in a standard Raspberry Pi OS installation. Many more can be easily installed if so desired.

The Raspberry Pi provides a 40 pin General Purpose Input/Output (GPIO) header that contains a multitude of different interfaces and power supplies for connecting external circuitry, including serial, I2C, SPI, and of course general purpose digital input/output pins just to name a few. Please note that all digital pins are rated at 3.3 volts, versus some other boards that use 5 volts like the Arduino Uno, so use caution in making sure your external circuits are designed to be operated at 3.3 V.

The programs shown here may be a little longer than some of the other “blink” programs you may have encountered around the internet, but I want to make sure that we are following good practice and not just the simplest. Specifically, the programs within this tutorial use loops to repeatedly turn on and off an LED with a delay in between to make an LED blink and are terminated by pressing CTRL-C on the keyboard. This action is known as a signal interrupt, and when a program is terminated in this fashion, it can create an unknown state for the board’s GPIO and cause accidental damage to the board if circuits are changed or disturbed in some way while in this unstable state. I will be using constructs to catch this signal interrupt so that we may place the GPIO in a known stable state before exiting the programs.

My development board is a Raspberry Pi 3 Model B running the Raspberry Pi OS operating system. If you are using a different model of the Raspberry Pi or a different Linux based OS that is similar to Raspberry Pi OS, the vast majority of this tutorial should still apply, however, some minor changes may be necessary.

Before continuing with this tutorial, make sure your Raspberry Pi is set up and running to your satisfaction according to Raspberry Pi’s Getting started documentation.

If you need assistance with your particular setup, post a question in the comments section below and I, or someone else, can try to help you.

Building The Circuit

Before building the circuit and connecting it to the Raspberry Pi, make sure your Raspberry Pi is shut down and disconnected from power in order to avoid accidental damage to the board during wiring. Shutting down the computer can be accomplished from the desktop (running as a stand alone computer) by selecting Raspberry > Shutdown from the main menu. If you are connected remotely over a network, use the following command within a terminal window to shut down the Raspberry Pi.

$ sudo shutdown -h now

Prefixing a command with sudo will run the subsequent command as a privileged user and may require a password. If a password is requested, raspberry is typically used as the default password for the pi user. The $ symbol shown is the command line prompt character, which should not be typed, and yours may look different.

Now, let’s build the circuit. Attach the red LED to the solderless breadboard by connecting one end of the LED to one of the breadboard’s terminal strips and the other end to an adjacent terminal strip. The terminal strips are the horizontal rows of terminals grouped together in sets of 5 in the center of the board. The anode (positive terminal) of an LED is longer than the cathode (negative terminal). Connect one end of the 330 Ω resistor to the terminal strip containing the LED’s anode and the other end of the resistor to an empty adjacent terminal strip.

Next, we will connect the LED and resistor circuit to the Raspberry Pi board. Attach the male end of a jumper wire to the breadboard’s terminal strip containing the open end of the resistor. Attach the female end of the jumper wire to pin 40 (commonly referred to as GPIO21) on the Raspberry Pi GPIO header. With the Raspberry Pi oriented such that the GPIO header spans across the top of the board, this is the last pin furthest to the right on the top row.

Attach the male end of another jumper wire to the terminal strip containing the open end (cathode) of the LED on the breadboard. Attach the female end of this second jumper wire to pin 39 (GND) located in the second row of the GPIO header just below pin 40 we connected to previously. Once completed, your circuit should look like the one shown below.

Completed Blink Circuit Connected To A Raspberry Pi
Completed LED Circuit Connected To A Raspberry Pi

The circuit is complete so you can now connect power to the Raspberry Pi and boot it up.

Using The Command Line With The raspi-gpio Tool

Open a new terminal window on the Raspberry Pi. If you are running in desktop mode, run the Terminal application whose icon (contains >_) should be visible in the main menu of your desktop. If connecting remotely across a network, log in via a secure shell as shown in the Remote access documentation.

The Raspberry Pi community uses two pin numbering schemes, one for the physical pin locations on the Raspberry Pi GPIO header and the other based on the pins of the underlying Broadcom (BCM) microcontroller. This can sometimes make pin connections quite confusing. You should always understand and verify which pin numbering scheme is being used within instructions so that you not only connect your circuits properly but that you don’t accidentally damage your Raspberry Pi. Specifically, our LED circuit is attached to physical pin 40 and BCM pin 21.

The Raspberry Pi Pinout website is a great reference for understanding the various pin numbering schemes and capabilities used on the Raspberry Pi. Click on the various pins on the GPIO header within the website for detailed information about those particular pins.

Another useful reference is the pinout command that can be typed directly on the command line within a terminal window. It comes preinstalled with the Raspberry Pi OS and provides a nice colorful layout of the header pins along with additional useful information about your Raspberry Pi board. Give it a try.

$ pinout

The raspi-gpio tool is a popular command line utility, that also comes preinstalled, for controlling the Raspberry Pi’s GPIO pins from the command line or even from within shell scripts.

Run the following command in your terminal window to provide the status of all of the GPIO pins. If for some reason you do not have permission to access the GPIO pins, the sudo command may be required when running the raspi-gpio command.

$ raspi-gpio get

The command prints a lot of detailed information. All of the GPIO pins are listed with their BCM pin numbers and associated attributes. We won’t get into the details of what it all means, but in general, level shows whether a pin is high (1) or low (0) and func shows whether a pin is set as an input or an output for standard GPIO pins.

You can add a pin number to the end of that command to retrieve only the information for that particular pin. For example, entering the following command

$ raspi-gpio get 21

will provide the status of just GPIO pin 21, as shown below, which is the pin we will be using for our LED.

GPIO 21: level=0 fsel=0 func=INPUT

The pin is currently set as an input with a low level.

You can get additional raspi-gpio information and syntax usage with the help sub-command.

$ raspi-gpio help

Whew! With all of that out of the way, let’s see if we can get our LED working. As we saw above, GPIO pin 21 is currently configured as an input. We need to configure it as an output in order to “drive” our LED. This is done with the set sub-command of the raspi-gpio utility.

$ raspi-gpio set 21 op

We can then turn on our LED with the command

$ raspi-gpio set 21 dh

and turn off the LED with the following command.

$ raspi-gpio set 21 dl

The dh and dl options refer to drive high and drive low respectively.

Before we end this section, we should reset the LED pin back to an input (its default state) in order to avoid any accidental damage that may occur if any external circuity changes. It is not strictly necessary in this case, but it is a good habit to get into. To accomplish this, we use the same set sub-command we used earlier, but specify pin 21 as an input this time.

$ raspi-gpio set 21 ip

Using Python With The RPi.GPIO Library

RPi.GPIO is a very popular Python GPIO interface library for the Raspberry Pi. The Python language and the RPi.GPIO library come preinstalled in a standard Raspberry Pi OS installation. The RPi.GPIO library lets you directly access and manipulate the GPIO pins on your Raspberry Pi.

Open your favorite text editor and save the following Python program as blink_rpigpio.py.

from time import sleep
import RPi.GPIO as GPIO

RED_LED = 21

GPIO.setmode(GPIO.BCM)
GPIO.setup(RED_LED, GPIO.OUT)
print("Press CTRL-C to exit.")
try:
    while True:
        GPIO.output(RED_LED, GPIO.HIGH)
        sleep(1)
        GPIO.output(RED_LED, GPIO.LOW)
        sleep(1)
finally:
    GPIO.cleanup()

Lines 1-2 import the libraries we are using in our program. The time library contains a sleep() method we will use to add delays between turning on and off our LED. The RPi.GPIO library is imported as just GPIO so that we don’t have to use the RPi prefix every time we use it.

Line 4 defines a variable named RED_LED that is used throughout our program to refer to pin 21 using the BCM numbering scheme. This makes it much easier to understand what is being controlled when our programs grow much larger and multiple pins are being utilized.

Lines 6-7 set up our GPIO pins to use the BCM numbering scheme(GPIO.BCM) along with setting the RED_LED pin to be an output (GPIO.OUT).

Lines 10-14 are the main portion of our program that turn on (GPIO.HIGH) and off (GPIO.LOW) our LED with a one second delay in between that loops forever.

Lines 15 and 16 define an exception block finally clause containing the library’s cleanup() method that when used with the while loop in the try clause (line 9), will reset all GPIO pins back to their default (input) states and exit the program cleanly when CTRL-C is pressed on the keyboard.

If there is something that needs further explanation, please let me know in the comment section and I will try to answer your question.

Now that our program is written, let’s run it with the following command.

$ python blink_rpigpio.py

You should now see the LED in your circuit blinking. If for some reason you do not have permission to access the GPIO pins, the sudo command may be required when running the python executable to run our blink_rpigpio.py program. After we have marveled at our new creation and are ready to exit the program, press CTRL-C on the keyboard to terminate it.

Using Python With The GPIO Zero Library

GPIO Zero is another popular Python GPIO interface library that comes preinstalled. It works differently than the RPi.GPIO library used in the previous section in that it defines high level component based classes for specific components, such as LEDs or buttons, that we work with instead of controlling the GPIO pins directly as is done by the RPi.GPIO library.

Open your text editor and save the following Python program as blink_gpiozero_loop.py.

from time import sleep
from gpiozero import LED

red_led = LED(21)

print("Press CTRL-C to exit.")
while True:
    red_led.on()
    sleep(1)
    red_led.off()
    sleep(1)

Like in the previous section, lines 1-2 import our libraries, however, we are using a different importing construct than we used before. This time we are only importing the LED class of the gpiozero library.

Line 4 defines our red_led instance variable using the LED class initializer of the GPIO Zero library that allows us to control pin 21 with operations (methods) that make sense for an LED. You may have noticed that I used the lowercase red_led name in this case instead of the uppercase RED_LED name that was used in the previous section. The reason for that is because the red_led variable refers to an instance of the LED class within the GPIO Zero library as opposed to a standard pin constant that was used previously with the RPi.GPIO library.

Lines 7-11 turn on and off our LED similar to what we did in the previous section, but this time it is much more obvious that we are turning on and off our LED when using the LED class’ on() and off() methods. Using component based objects makes it much easier to work with specific components. For instance, instead of driving a specific pin to a high level to turn an LED on, as we did previously, all we had to do was tell the LED to turn itself on. Very nice!

Unlike the RPi.GPIO library, GPIO Zero automatically cleans up the GPIO pins upon exiting so we do not need any of the GPIO clean up code used in the previous section. That is a very nice feature of the GPIO Zero library.

Run the program to blink the LED and press CTRL-C when you want to exit.

$ python blink_gpiozero_loop.py

In the above program, we used the standard looping mechanism to turn on and off the LED with delays in between. The LED class also has a method, named blink(), specifically meant for this purpose that we could use instead.

Create another Python program named blink_gpiozero_blink.py with the following code.

from signal import pause
from gpiozero import LED

red_led = LED(21)

print("Press CTRL-C to exit.")
red_led.blink()
pause()

First of all, instead of importing the sleep() method of the time library, this time we are importing the pause() method of the signal library which causes the program to sleep until an interrupt signal, CTRL-C in this case, is received.

Then we are using the blink() and pause() methods to replace the entire while loop. Pretty snazzy.

Run the new program and it should function the same way as before.

$ python blink_gpiozero_blink.py

The GPIO Zero library contains many component classes that you can use within your programs. Check out the library’s documentation to discover more.

Using C With The pigpio Library

The C programming language and the pigpio library come preinstalled on Raspberry Pi OS. The pigpio library is similar to the RPi.GPIO library we used earlier in how it configures and interacts with GPIO pins, but it does require extra initialization and termination steps.

Open your text editor and save the following C program as blink_pigpio.c.

#include <signal.h>
#include <stdio.h>
#include <pigpio.h>

const int RedLED = 21;
volatile sig_atomic_t signal_received = 0;

void sigint_handler(int signal) {
   signal_received = signal;
}

int main() {
   if (gpioInitialise() == PI_INIT_FAILED) {
      printf("ERROR: Failed to initialize the GPIO interface.\n");
      return 1;
   }
   gpioSetMode(RedLED, PI_OUTPUT);
   signal(SIGINT, sigint_handler);
   printf("Press CTRL-C to exit.\n");
   while (!signal_received) {
      gpioWrite(RedLED, PI_HIGH);
      time_sleep(1);
      gpioWrite(RedLED, PI_LOW);
      time_sleep(1);
   }
   gpioSetMode(RedLED, PI_INPUT);
   gpioTerminate();
   printf("\n");
   return 0;
}

Lines 1-3 load the various libraries we are using, including the pigpio library.

Line 5 defines a constant named RedLED that is used throughout our program to refer to pin 21 using the BCM numbering scheme.

When exiting the program, we want to reset all GPIO pins to their default (input) states in order to avoid any accidental damage to the pins. Unlike the Python programs we created earlier, C does not have a simple way to detect when CTRL-C is pressed on the keyboard to exit our program, so we have to create our own. Since exiting a program with CTRL-C is considered a software interrupt signal, this can be accomplished by creating our own signal interrupt handler.

Line 6 defines a signal_received global variable that is used in conjunction with our signal interrupt handler. The volatile identifier let’s the compiler know that the value of this variable can change at anytime, which is exactly what happens when the signal interrupt handler gets called.

Lines 8-10 define a signal interrupt handler function that gets called when CTRL-C is pressed on the keyboard and sets the signal_received variable to the interrupt signal received.

Lines 12-30 define our main() function, which in C, includes the root level instructions that are run first when we execute our program.

Lines 13-16 initialize the pigpio library for use. The program will print an error and terminate at this point if the library could not be initialized.

Line 17 sets the RedLED pin to act as an output (PI_OUTPUT) so that we may control our LED.

Line 18 enables our signal interrupt handler for use.

Line 20 initiates a while loop that runs until the signal_received variable is no longer 0, which is set to 2 when CTRL-C is pressed on the keyboard. Lines 21-24 turn on and off the RedLED pin with a one second delay in between constituting the innards of our standard on-delay-off-delay blinking loop.

Once CTRL-C is pressed and the while loop is exited, line 26 resets the RedLED pin back to an input and line 27 terminates the pigpio library functionality before we exit the program.

Now that we have written our C program, we need to compile it before we can execute it. That can be accomplished by using the preinstalled Gnu C compiler with the command

$ gcc -Wall -o blink_pigpio blink_pigpio.c -lpigpio

that compiles the blink_pigpio.c C source code into the blink_pigpio executable (-o) while also linking the pigpio library to the executable (-l) and notifying us of any warnings or errors that may have occurred (-W) during compilation.

Once we have compiled our program, we can run it with the following command. The extra ./ in front of the executable name ensures that you are running the blink_pigpio program located in your current directory. Even if you did not have to use sudo for privileged access to the GPIO pins previously, it is required when using the pigpio library.

$ sudo ./blink_pigpio

You should now see the LED in your circuit blinking. Once you’re ready to exit the program, press CTRL-C on the keyboard to terminate it.

Using C++ With The pigpio Library

We will continue using the pigpio library from the previous section, but this time we will use the C++ programming language that also comes preinstalled.

Since C++ is a superset of the C programming language, we could just copy, compile it with the C++ compiler (g++), and run the C program we created in the previous section

$ cp blink_pigpio.c blink_pigpio.cpp
$ g++ -Wall -o blink_pigpio blink_pigpio.cpp -lpigpio
$ sudo ./blink_pigpio

but let’s modify it to incorporate the more typical C++ constructs. The highlighted lines in the code listing below are the only differences between the C and C++ programs.

#include <csignal>
#include <iostream>
#include <pigpio.h>

const int RedLED = 21;
volatile sig_atomic_t signal_received = 0;

void sigint_handler(int signal) {
   signal_received = signal;
}

int main() {
   if (gpioInitialise() == PI_INIT_FAILED) {
      std::cout << "ERROR: Failed to initialize the GPIO interface." << std::endl;
      return 1;
   }
   gpioSetMode(RedLED, PI_OUTPUT);
   signal(SIGINT, sigint_handler);
   std::cout << "Press CTRL-C to exit." << std::endl;
   while (!signal_received) {
      gpioWrite(RedLED, PI_HIGH);
      time_sleep(1);
      gpioWrite(RedLED, PI_LOW);
      time_sleep(1);
   }
   gpioSetMode(RedLED, PI_INPUT);
   gpioTerminate();
   std::cout << std::endl;
   return 0;
}

Compile the C++ program with the Gnu C++ compiler

$ g++ -Wall -o blink_pigpio blink_pigpio.cpp -lpigpio

and run it. Please note that this will overwrite the blink_pigpio executable created in C unless you compile it in a different directory or use a different executable name.

$ sudo ./blink_pigpio

Don’t forget to press CTRL-C when your done.

Shutdown

Before disconnecting the breadboard from your Raspberry Pi or altering the circuit in any way, it is always a good idea to shut down the Raspberry Pi and disconnect it from power in order to avoid accidental damage to the board or circuitry. It never hurts to be extra cautious, right?

If you are working from the desktop (stand alone computer), select Raspberry < Shutdown from the main menu. If you are connected remotely over a network, use the following command in the terminal window.

$ sudo shutdown -h now

Once the Raspberry Pi has successfully shut down, you can safely disconnect power from the board.

Summary

In this tutorial we learned

  • how to construct an LED circuit,
  • attach it to a Raspberry Pi development board,
  • use the raspi-gpio utility to control an LED from the command line,
  • and write various programs using the following different languages and libraries to make the LED blink.
    • Python language with the RPi.GPIO library
    • Python language with the GPIO Zero library
    • C language with the pigpio library
    • C++ language with the pigpio library

The final source code used for this tutorial are available on GitHub. The GitHub versions of the code are fully commented to include additional information, such as the program’s description, circuit connections, and code clarifications.

I also created a Raspberry Pi Basics Cheatsheet that you may want to download and reference in the future.

Thank you for joining me on this journey and I hope you enjoyed the experience. Please feel free to share your thoughts or questions in the comments section below.

This tutorial is provided as a free service to our valued readers. Please help us continue this endeavor by considering a donation.

About the author

John Woolsey

John is an electrical engineer who loves science, math, and technology and teaching it to others even more.
 
He knew he wanted to work with electronics from an early age, building his first robot when he was in 8th grade. His first computer was a Timex/Sinclair 2068 followed by the Tandy 1000 TL (aka really old stuff).
 
He put himself through college (The University of Texas at Austin) by working at Motorola where he worked for many years afterward in the Semiconductor Products Sector in Research and Development.
 
John started developing mobile app software in 2010 for himself and for other companies. He has also taught programming to kids for summer school and enjoyed years of judging kids science projects at the Austin Energy Regional Science Festival.
 
Electronics, software, and teaching all culminate in his new venture to learn, make, and teach others via the Woolsey Workshop website.

2 Comments

  • Hello John & Merry Xmas !

    Getting caught up on old emails, was visiting your site & ran across this article. I just wanted to make you aware (you probably already were) of some “developments” wrt RPi GPIO access. I’ll keep my remarks brief & let you research these things yourself.

    The long-rumored demise of the sysfs-based interface to the GPIO is now just around the corner. It is said that the release of the linux 6.6 kernel will be the final “nail in the coffin”. There have already been casualties: the popular ‘WiringPi’ library has been abandoned, and even the pigpio library is said to be broken (potentially irreparably) on the RPi 5.

    The “new way” is either libgpiod – or something as-yet-to-be-announced that functions similarly. As stated in a recent post in the RPi forums by a Raspberry Pi Engineer, “libgpio[d] is the correct answer for any variant of Pi now.”

    Some have expressed strong feelings against libgpiod – not because of its *design principles*, but because of its poor implementation. So stay tuned – it could be an interesting few months ahead.

    • Yes, I am aware of the Linux kernel and RP1 (Raspberry Pi 5) issues affecting GPIO access, but I am still very grateful for you sharing your knowledge. It will indeed be interesting and I hope we settle on a good solution across the popular embedded programming methods.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.