Language: EN

salidas-pwm-raspberry-pi

What are PWM outputs and how to use them in Raspberry Pi

  • 5 min

In this post, we will see how to use PWM outputs on Raspberry Pi to control devices like LEDs, motors, and servos.

PWM outputs (Pulse Width Modulation) are a technique in electronics that allows us to control electrical signals by generating a “pseudo-analog” signal.

Key PWM Concepts

A PWM output is a simple (and cheap) way to achieve a “more or less analog” signal.

Instead of varying the voltage directly, PWM modifies the time that a signal is in a high state (ON) versus the time it is in a low state (OFF) within a cycle.

  • Duty Cycle: It is the percentage of time that the signal is in a high state (ON) during a complete cycle. For example, a 50% duty cycle means that the signal is high half the time and low the other half.

  • Frequency: It is the number of complete cycles per second. It is measured in Hertz (Hz). A high frequency means that the cycles repeat quickly, while a low frequency means that the cycles repeat more slowly.

For some devices, a PWM signal works “more or less the same” as a real analog signal. For example, an LED will give us virtually the same performance.

However, a PWM signal is not an analog signal. You are actually applying pulses of 3.3V. If you connect it to a device that does not support that voltage, you may damage it.

Hardware PWM Outputs

The Raspberry Pi has two pins that support hardware PWM: GPIO18 and GPIO19. These pins are suitable for applications that require high precision and stability (like controlling servos or motors).

Let’s see an example where we will use pin GPIO18 to control the brightness of an LED using PWM.

import RPi.GPIO as GPIO
import time

# Pin configuration
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)

# Create a PWM instance with a frequency of 100 Hz
pwm = GPIO.PWM(18, 100)

# Start PWM with a duty cycle of 0% (LED off)
pwm.start(0)

try:
    while True:
        # Gradually increase the brightness of the LED
        for duty_cycle in range(0, 101, 5):
            pwm.ChangeDutyCycle(duty_cycle)
            time.sleep(0.1)
        
        # Gradually decrease the brightness of the LED
        for duty_cycle in range(100, -1, -5):
            pwm.ChangeDutyCycle(duty_cycle)
            time.sleep(0.1)
except KeyboardInterrupt:
    # Stop PWM and clean up GPIO pins
    pwm.stop()
    GPIO.cleanup()

In this code:

  • We configure pin GPIO18 as an output.
  • We create a PWM instance with a frequency of 100 Hz.
  • We start PWM with a duty cycle of 0% (LED off).
  • We use a loop to gradually increase and decrease the brightness of the LED.

Software PWM

If we need more PWM pins or do not have access to the hardware pins, we can use software PWM.

Software PWM is less accurate and may consume more CPU resources.

In this example, we will use pin GPIO17.

import RPi.GPIO as GPIO
import time

# Pin configuration
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)

# PWM frequency (in Hz)
frequency = 100

# Initial duty cycle (0%)
duty_cycle = 0

# Cycle time (1 / frequency)
cycle_time = 1.0 / frequency

try:
    while True:
        # Calculate the high and low times
        on_time = cycle_time * (duty_cycle / 100.0)
        off_time = cycle_time - on_time
        
        # Turn on the LED
        GPIO.output(17, GPIO.HIGH)
        time.sleep(on_time)
        
        # Turn off the LED
        GPIO.output(17, GPIO.LOW)
        time.sleep(off_time)
        
        # Increase the duty cycle
        duty_cycle += 5
        if duty_cycle > 100:
            duty_cycle = 0
except KeyboardInterrupt:
    # Clean up GPIO pins
    GPIO.cleanup()

In this code:

  • We configure pin GPIO17 as an output.
  • We implement software PWM using a loop that alternates between turning the LED on and off.
  • We gradually increase the duty cycle to simulate an increase in the brightness of the LED.

Practical Examples