micropython-salidas-analogicas-pwm

PWM Analog Outputs with MicroPython

  • 6 min

In this tutorial, we will see how to use PWM signals in MicroPython to generate pseudo-analog outputs to control, for example, LED brightness or motor speed.

PWM (Pulse Width Modulation) is a technique we have frequently seen on the blog, which allows us to generate “more or less analog” signals cheaply with a microcontroller.

Basically, since having hardware to make a real analog signal is expensive, what we do is a cycle where we turn a digital signal on and off at certain intervals.

  • Duty Cycle: It is the percentage of time the signal is in a high state. For example, a 50% duty cycle means the signal is on half the time and off the other half.
  • Frequency: It is the number of times the signal repeats per second, measured in Hertz (Hz).

The PWM frequency must be adjusted according to the device being controlled. In general, a frequency between 500 Hz and 1 kHz is usually suitable in many cases.

If the device is “slow” (has a lot of inertia) compared to the PWM frequency, it may behave more or less as if it were receiving an analog signal.

But not all devices will accept your pseudo-analog signal. Some of them may behave erratically and we can even damage them if they are not prepared for the voltage levels.

PWM Configuration in MicroPython

To use PWM in MicroPython, we must first import the machine module, which provides the necessary functions to interact with the hardware (as we did with digital outputs).

Then, we configure a GPIO pin as a PWM output like this,

pwm = PWM(led_pin)
Copied!

Now we can use some of the PWM methods to configure our pseudo-analog output. For example

CommandDescription
pwm.freq(freq)Sets or returns the frequency of the PWM signal in hertz (Hz).
pwm.duty(duty_cycle)Adjusts the duty cycle, varying the LED brightness (value between 0 and 1023).
pwm.deinit()Deactivates the PWM signal on the specified pin.
pwm.duty_u16(duty_cycle)Adjusts the duty cycle with 16-bit resolution (value between 0 and 65535).
pwm.init(freq, duty)Initializes the PWM with a specific frequency and duty cycle.

Practical Example

Let’s see it better with a simple example. We are going to control the brightness of an LED using PWM.

from machine import Pin, PWM
import time

# GPIO pin configuration where the LED is connected
led_pin = Pin(2, Pin.OUT)  # Using GPIO pin 2 (common in ESP32/ESP8266)
pwm = PWM(led_pin)         # Configure the pin as a PWM output

# PWM frequency configuration (for example, 1000 Hz)
pwm.freq(1000)

# Function to vary the brightness of the LED
def vary_brightness():
    for duty_cycle in range(0, 1024):  # Range from 0 to 1023 (10 bits)
        pwm.duty(duty_cycle)           # Adjust the duty cycle
        time.sleep_ms(10)              # Small pause to observe the change

# Execute the function
vary_brightness()
Copied!

In this example,

  • We import Pin and PWM from the machine module, and time to handle pauses.
  • We define GPIO pin 2 as an output and configure it for PWM.
  • We set the PWM signal frequency to 1000 Hz.
  • We use a for loop to vary the duty cycle from 0 to 1023 (10 bits), which allows controlling the LED brightness.
  • We add a small pause (time.sleep_ms(10)) to observe the gradual change in brightness.

Practical Examples