micropython-salidas-analogicas-pwm

PWM Analog Outputs with MicroPython

  • 5 min

In this tutorial, we will see how to use PWM signals in MicroPython to generate pseudo-analog outputs to control, for example, the intensity of LEDs or the speed of motors.

PWM (pulse width modulation) is a technique that we have often seen on the blog, which allows us to generate “more or less analog” signals cheaply with a microcontroller.

Basically, since it is expensive to have hardware to make a real analog signal, what we do is a cycle where we turn a digital signal on and off every certain amount of time.

  • Duty Cycle: It is the percentage of time the signal is in a high state. For example, a duty cycle of 50% means that 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 adequate in many cases.

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

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

PWM Configuration in MicroPython

To use PWM in MicroPython, we first need to 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)

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 brightness of the LED (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 specific frequency and duty cycle.

Practical Example

Let’s see it better with a simple example. We will control the intensity 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()

In this example,

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

Practical Examples