En este tutorial vamos a ver cómo usar señales PWM en MicroPython para generar salidas pseudo-analógicas con las que controlar, por ejemplo, la intensidad de LEDs o la velocidad de motores.
El PWM (modulación por ancho de pulso) es una técnica que hemos visto frecuentemente en el blog, que nos permite generar señales “más o menos analógicas” de forma barata con un microcontrolador.
Básicamente, como es caro tener hardware para hacer una señal analógica real, lo que hacemos es un ciclo donde encendemos y apagamos una señal digital cada cierto tiempo.
- Ciclo de trabajo (Duty Cycle): Es el porcentaje de tiempo que la señal está en estado alto. Por ejemplo, un ciclo de trabajo del 50% significa que la señal está encendida la mitad del tiempo y apagada la otra mitad.
- Frecuencia: Es el número de veces que la señal se repite por segundo, medida en Hertz (Hz).
La frecuencia PWM debe ajustarse según el dispositivo que se esté controlando. En general, una frecuencia entre 500 Hz y 1 kHz suele ser adecuada en muchos casos.
Si el dispositivo es “lento” (tiene mucha inercia) en comparación a la frecuencia del PWM, puede que se comporte ante nuestra señal más o menos como si fuera una seña analógica.
Pero no todos los dispositivos van a aceptar tu señal pseudo-analógica. Algunos de ellos pueden comportarse erráticamente e incluso podemos dañarlos si no están preparados para los niveles de tensión.
Si quieres aprender más consulta,
Configuración de PWM en MicroPython
Para utilizar PWM en MicroPython, primero debemos importar el módulo machine
, que proporciona las funciones necesarias para interactuar con el hardware (como ya hacíamos en las salidas digitales)
Luego, configuramos un pin GPIO como salida PWM asi,
pwm = PWM(led_pin)
Ahora podemos usar algunas de los métodos de PWM para configurar nuestra salida pseudo-analógica. Por ejemplo
Comando | Descripción |
---|---|
pwm.freq(freq) | Establece o devuelve la frecuencia de la señal PWM en hercios (Hz). |
pwm.duty(duty_cycle) | Ajusta el ciclo de trabajo, variando el brillo del LED (valor entre 0 y 1023). |
pwm.deinit() | Desactiva la señal PWM en el pin especificado. |
pwm.duty_u16(duty_cycle) | Ajusta el ciclo de trabajo con resolución de 16 bits (valor entre 0 y 65535). |
pwm.init(freq, duty) | Inicializa el PWM con una frecuencia y un ciclo de trabajo específicos. |
Ejemplo práctico
Vamos a verlo mejor si ponemos un ejemplo sencillo. Vamos a controlar la intensidad de un LED utilizando un PWM.
from machine import Pin, PWM
import time
# Configuración del pin GPIO donde está conectado el LED
led_pin = Pin(2, Pin.OUT) # Usamos el pin GPIO 2 (común en ESP32/ESP8266)
pwm = PWM(led_pin) # Configuramos el pin como salida PWM
# Configuración de la frecuencia PWM (por ejemplo, 1000 Hz)
pwm.freq(1000)
# Función para variar el brillo del LED
def variar_brillo():
for duty_cycle in range(0, 1024): # Rango de 0 a 1023 (10 bits)
pwm.duty(duty_cycle) # Ajustamos el ciclo de trabajo
time.sleep_ms(10) # Pequeña pausa para observar el cambio
# Ejecutar la función
variar_brillo()
En este ejemplo,
- Importamos
Pin
yPWM
del módulomachine
, ytime
para manejar pausas. - Definimos el pin GPIO 2 como salida y lo configuramos para PWM.
- Establecemos la frecuencia de la señal PWM en 1000 Hz.
- Usamos un bucle
for
para variar el ciclo de trabajo de 0 a 1023 (10 bits), lo que permite controlar el brillo del LED. - Añadimos una pequeña pausa (
time.sleep_ms(10)
) para observar el cambio gradual en el brillo.
Ejemplos prácticos
Control de brillo de LEDs RGB
De igual forma que podemos controlar un LED con una señal PWM, podemos usar tres para controlar un LED RGB, permitiendo variar el color a través de la intensidad de cada canal (rojo, verde y azul).
from machine import Pin, PWM
import time
# Configuración de los pines para los LEDs RGB
red = PWM(Pin(2, Pin.OUT))
green = PWM(Pin(4, Pin.OUT))
blue = PWM(Pin(5, Pin.OUT))
# Configuración de la frecuencia PWM
red.freq(1000)
green.freq(1000)
blue.freq(1000)
# Función para variar el color del LED RGB
def variar_color():
for i in range(0, 1024):
red.duty(i)
green.duty(1023 - i)
blue.duty(i // 2)
time.sleep_ms(10)
# Ejecutar la función
variar_color()
Control de un motor con PWM
Ahora, vamos a aplicar PWM para controlar la velocidad de un motor. Este ejemplo es útil en aplicaciones como robots o sistemas de automatización.
from machine import Pin, PWM
import time
# Configuración del pin GPIO donde está conectado el motor
motor_pin = Pin(4, Pin.OUT) # Usamos el pin GPIO 4
pwm = PWM(motor_pin) # Configuramos el pin como salida PWM
# Configuración de la frecuencia PWM (por ejemplo, 500 Hz)
pwm.freq(500)
# Función para variar la velocidad del motor
def variar_velocidad():
for duty_cycle in range(0, 1024): # Rango de 0 a 1023 (10 bits)
pwm.duty(duty_cycle) # Ajustamos el ciclo de trabajo
time.sleep_ms(20) # Pequeña pausa para observar el cambio
# Ejecutar la función
variar_velocidad()
En este caso, el motor variará su velocidad según el ciclo de trabajo aplicado. Un ciclo de trabajo del 50% hará que el motor gire a la mitad de su velocidad máxima.
Ojito con los motores, que depende del tamaño, no les suele gustar nada de nada las señalas PWM. Te pueden freír un pin digital por las tensiones inducidas.
Generación de tonos con un zumbador
Los zumbadores pasivos requieren una señal PWM para generar tonos audibles. Supongamos un zumbador conectado al GPIO15 (a través de una resistencia).
from machine import Pin, PWM
import time
# Configuración del PWM
buzzer = PWM(Pin(15))
def beep(frequency, duration):
"""
Genera un tono en el zumbador.
:param frequency: Frecuencia en Hz.
:param duration: Duración en segundos.
"""
buzzer.freq(frequency)
buzzer.duty_u16(32768) # Ciclo de trabajo al 50%
time.sleep(duration)
buzzer.duty_u16(0) # Apagar el zumbador
# Generar tonos
try:
beep(440, 1) # La4 - 440 Hz durante 1 segundo
beep(880, 0.5) # La5 - 880 Hz durante 0.5 segundos
except KeyboardInterrupt:
buzzer.deinit()