How to Control LED Brightness on a Raspberry Pi With PWM

Raspberry Pi With Pwm Led Two Pushbuttons Breadboard Featured Image

If you had fun making LEDs blink on a Raspberry Pi, wait until you hear about controlling its brightness! In this guide, we work with a pair of buttons to adjust the led brightness on a Raspberry Pi.

Starting your first Raspberry Pi project? Here’s how to quickly install Raspberry Pi OS on your device.

What PWM Does to an LED

PWM, or Pulse Width Modulation, is a method that artificially lowers the voltage output of the Raspberry Pi’s GPIO (General Purpose Input/Output) pins. It’s artificial, as you don’t really reduce the voltage and just turn it on and off so fast that the overall voltage becomes lower than the real voltage you’re applying to it.

For an LED or Light-Emitting Diode, increasing the overall voltage makes it shine brighter, while decreasing it makes it dimmer. But since the Raspberry Pi has no analog output, we’re using PWM to control the LED’s brightness.

What You’ll Need

  • 2 pushbuttons
  • 3 resistors (250-550Ω will work. Use a lower rating if the LED is too dark.)
  • 1 LED (any color)
  • Breadboard
  • Jumper wires
  • Raspberry Pi (any model except the Pi Pico)

How to Use PWM to Control LED Brightness on a Raspberry Pi

In this guide, we are using use two buttons to make the LED shine brighter or dimmer with PWM. Pressing the “brighter” button increases the PWM output, while pressing the “dimmer” button decreases it.

Preparing the Circuit

  1. Let’s start with the LED. On the breadboard, place the LED and connect a resistor to one side. The side the resistor is placed does not matter.
Led And Resistor On Breadboard For Raspberry Pi Pwm Led Guide
  1. Connect a jumper to its cathode side. This one will point to pin 11 on the Raspberry Pi. Add another jumper that leads to the blue rail on the breadboard, then add another jumper from that blue rail to pin 9 on the Raspberry Pi, which is GND.
Led And Resistor On Breadboard Connected To Raspberry Pi For Raspberry Pi Pwm Led Guide

Note: to find the right pin number on the Raspberry Pi, hold the board so that the GPIO pin tray sits to the right. The top-left pin should be pin 1, to its right should be pin 2, and below should be pin 3.

Raspberry Pi Pinout
  1. You’ll need to build the pushbuttons. Place the pushbuttons on the breadboard and add a resistor to one leg of each pushbutton. The other side of the resistor should lead to the blue rail of the breadboard.

Tip: want to know more about pushbuttons? We have a full guide dedicated to showing you how to use pushbuttons with Raspberry Pi GPIO pins.

  1. Add jumper wires in a parallel connection with the resistor and pushbutton. Connect the other side of these to pins 13 (“Brighter” button) and 15 (“Dimmer” button).
Pushbuttons On Breadboard With Led For Raspberry Pi Pwm Led Guide
  1. Use a jumper wire to connect the pushbuttons to the side with the red rail of the breadboard.
Red Jumper Wires On Breadboard Pushbuttons For Raspberry Pi Pwm Led Guide
  1. Connect the red rail to a 3.3V source on the Raspberry Pi, like pin 1.

If Python is your go-to programming language, learn how to install and manage multiple Python versions in Linux.

Preparing the Code

On your favorite code-editing tool, make a new file and save it as “rpi-lcdpwm.py.”

  1. Start with the code below, which gives you two ways of importing modules on Python: the first imports the RPi.GPIO module and lets you call it with just GPIO, and the second one imports only the sleep() function from the entirety of the time module.
import RPi.GPIO as GPIO
from time import sleep
  1. Define the pin numbers to make it easier to change pins in case you change your mind later on.
ledPin = 11
brightenButton = 13
dimButton = 15
  1. Optional: add the line GPIO.setwarnings(False) so that you can avoid the GPIO warning message when you start the script later.
  1. Set the pin selection method. BOARD is a good choice for beginners, as it makes it easier to look for pins without having to consult the pinout. The other method is BCM, which stands for “Broadcom.” This uses the Broadcom numbers assigned to each pin, which may differ based on your Raspberry Pi’s make.
GPIO.setmode(GPIO.BOARD)
  1. Assign the GPIO pins as input or output. We’re assigning ledPin as an output pin and will always start its state as LOW. The next two lines set brightenButton and dimButton as input pins that listen to your button pushes. These should also be set as GPIO.PUD_DOWN to designate them as using pulldown resistors.
GPIO.setup(ledPin, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(brightenButton, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(dimButton, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
  1. Let’s declare the PWM. pwmLEDPin is a variable that makes it easier to type GPIO.PWM(ledPin, 100) later on, and the .start(0) command begins the PWM process. We can now change the output of ledPin using PWM.
pwmLEDPin = GPIO.PWM(ledPin, 100)
pwmLEDPin.start(0)
  1. The duty cycle is the percentage of time that the pin is active during a pulse wave. Here, we’re setting the duty cycle to 100% first. We had a rather lengthy discussion on this topic in our guide to using servo motors with the Raspberry Pi, if you’re interested.
dutyCycle = 100
GPIO.output(ledPin, GPIO.HIGH)
  1. For the looping part, we are setting a while loop that runs virtually forever.
while True:
  1. At the beginning of this looping cycle, we are updating the duty cycle.
pwmLEDPin.ChangeDutyCycle(dutyCycle)
  1. Let’s program what the brightenButton does. When the Raspberry detects electricity passing through the pin for brightenButton, it will show a message that says “brightenButton is HIGH,” which adds 5 to the current value of the duty cycle until it reaches 100.
if GPIO.input(brightenButton) == GPIO.HIGH:
                print("brightenButton is HIGH")
                if dutyCycle < 100:
                        dutyCycle += 5
                        sleep(0.25)
                else: dutyCycle = 100
  1. When programming the dimButton function, it does the opposite, reducing the value by 5 until it reaches 0.
elif GPIO.input(dimButton) == GPIO.HIGH:
                print("dimButton is HIGH")
                if dutyCycle > 0:
                        dutyCycle -= 5
                        sleep(0.25)
                else: dutyCycle = 0

Final Code:

import RPi.GPIO as GPIO
from time import sleep
 
ledPin = 11
brightenButton = 13
dimButton = 15
 
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(ledPin, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(brightenButton, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(dimButton, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
pwmLEDPin = GPIO.PWM(ledPin, 100)
pwmLEDPin.start(0)
dutyCycle = 100
GPIO.output(ledPin, GPIO.HIGH)
 
while True:
        pwmLEDPin.ChangeDutyCycle(dutyCycle)
        if GPIO.input(brightenButton) == GPIO.HIGH:
                print("brightenButton is HIGH")
                if dutyCycle < 100:
                        dutyCycle += 5
                        sleep(0.25)
                else: dutyCycle = 100
        elif GPIO.input(dimButton) == GPIO.HIGH:
                print("dimButton is HIGH")
                if dutyCycle > 0:
                        dutyCycle -= 5
                        sleep(0.25)
                else: dutyCycle = 0

Making It Work

First, you’ll need a terminal. You can use the Raspberry Pi’s built-in terminal or control the Raspberry Pi through SSH on a separate computer. Through the terminal, you should go to the Python script’s directory and enter python3 rpi-ledpwm.py or the filename you used.

Sometimes the LED will look like it’s blinking. The PWM frequency is probably too low, if that’s the case. You can increase the frequency by increasing the number in pwmLEDPin = GPIO.PWM(ledPin, 100) until the blinking is no longer noticeable.

If you find the transitions to be grainy, lower the time in sleep(0.25) inside the while loop. It does get faster as you lower it, though, so don’t lower it too much.

Tip: prefer Arduino instead? Here’s a complete guide to getting you started with Arduino projects.

Frequently Asked Questions

What is the minimum frequency I can generate with the Raspberry Pi?

The lowest frequency you can set on a Raspberry Pi is 10Hz. The hardware can’t support anything lower than that.

What is the maximum frequency I can generate with the Raspberry Pi?

The highest frequency you can set on a Raspberry Pi is 8,000Hz.

Is it possible to turn pulse waves into sound waves?

Yes. With a piezoelectric element, it is entirely possible to turn pulse waves into sound waves that you can hear. In this case, modifying the frequency changes the pitch, while modifying the duty cycle adjusts the volume.

All images by Terenz Jomar Dela Cruz.

Terenz Jomar Dela Cruz
Terenz Jomar Dela Cruz

Terenz is a hobbyist roboticist trying to build the most awesome robot the world has ever seen. He could have done that already if he wasn't so busy burning through LEDs as a second hobby.

Subscribe to our newsletter!

Our latest tutorials delivered straight to your inbox