¿Cómo crear señales PWM en el ESP32 con Arduino IDE? Genera Salidas Analógicas y Controla la Intensidad de un LED

Libro Guía del Microcontrolador ESP32

Aprende a generar señales PWM con el ESP32 usando Arduino IDE. En esta guía te explico dos métodos diferentes: el uso de analogWrite() y el uso de la API LEDC nativa del ESP32. Como ejemplo práctico, construiremos un circuito sencillo para atenuar y encender un LED de forma gradual, el clásico efecto “fade”.

Antes de continuar con este tutorial, deberías tener el soporte de placas ESP32 instalado en tu Arduino IDE. Si aún no lo has hecho, sigue el tutorial de instalación correspondiente a tu sistema operativo (Windows, macOS o Linux).

El controlador PWM del ESP32

El ESP32 incorpora un controlador LED PWM con 6 a 16 canales independientes (el número exacto depende del modelo del chip). Cada canal se puede configurar de forma individual para generar señales PWM con propiedades distintas (frecuencia, resolución y duty cycle). Esto lo convierte en una herramienta muy potente para controlar la intensidad de LEDs, la velocidad de motores o cualquier dispositivo que acepte señales PWM.

Existen dos formas principales de generar señales PWM en el ESP32 y obtener el mismo resultado: puedes usar la función analogWrite(), igual que en las placas Arduino clásicas, o puedes usar las funciones LEDC, que son específicas del ESP32 y ofrecen un control más fino.

Método 1: analogWrite() — el más sencillo

La función más básica es analogWrite(), que acepta como argumentos el GPIO donde quieres generar la señal PWM y el valor del duty cycle (que va de 0 a 255 por defecto, ya que usa 8 bits de resolución):

void analogWrite(uint8_t pin, int value);

Un ejemplo de uso sería:

void analogWrite(2, 180);

Configurar la frecuencia y la resolución

Puedes ajustar la resolución y la frecuencia de la señal PWM en un pin concreto usando las funciones analogWriteResolution() y analogWriteFrequency().

Para establecer la resolución:

void analogWriteResolution(uint8_t pin, uint8_t resolution);

Para establecer la frecuencia:

void analogWriteFrequency(uint8_t pin, uint32_t freq);

Esto te permite adaptar la señal a las necesidades concretas de tu proyecto. Por ejemplo, para un LED una frecuencia de 5 kHz es más que suficiente, mientras que para controlar un motor quizá necesites una frecuencia distinta.

Método 2: la API LEDC — el control avanzado del ESP32

Como alternativa, puedes usar la API LEDC de Arduino-ESP32, que te da un control más directo sobre el hardware PWM del chip. Primero necesitas configurar un pin LEDC. Para ello puedes usar las funciones ledcAttach() o ledcAttachChannel().

ledcAttach()

La función ledcAttach() configura un pin LEDC con una frecuencia y resolución dadas, y selecciona el canal LEDC automáticamente:

bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution);

Esta función devuelve true si la configuración ha sido correcta. Si devuelve false, se ha producido un error y el canal LEDC no se ha configurado.

ledcAttachChannel()

Si prefieres configurar el canal LEDC manualmente, puedes usar ledcAttachChannel() en su lugar:

bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel);

Igual que la anterior, devuelve true si la configuración es exitosa. El último argumento es el número de canal que quieres asignar (del 0 al 15 en el ESP32 clásico).

ledcWrite()

Finalmente, después de configurar el pin LEDC con una de las dos funciones anteriores, usas ledcWrite() para establecer el duty cycle de la señal PWM:

void ledcWrite(uint8_t pin, uint32_t duty);

Esta función devuelve true si el ajuste del duty cycle es correcto. Si devuelve false, se ha producido un error y el duty cycle no se ha aplicado.

Para más información y conocer todas las funciones del controlador LEDC, consulta la documentación oficial de Espressif.

Proyecto: atenuar un LED con el ESP32

Para mostrarte cómo generar señales PWM con el ESP32, vamos a crear dos ejemplos sencillos que aumentan y disminuyen la intensidad de un LED de forma gradual. Veremos un ejemplo usando analogWrite() y otro usando las funciones LEDC.

Esquema de conexión

Conecta un LED al GPIO 16 del ESP32 a través de una resistencia de 330 Ω hacia GND. El LED debe estar orientado con el ánodo hacia el GPIO y el cátodo hacia la resistencia y GND.

Nota: Puedes usar cualquier pin que quieras, siempre que pueda actuar como salida. Todos los pines que pueden actuar como salidas pueden usarse como pines PWM. Recuerda que los GPIO 34 a 39 son solo de entrada y no pueden generar PWM. Para más información, consulta la referencia de pines del ESP32.

Componentes necesarios

Para seguir este tutorial necesitas: un ESP32 DOIT DEVKIT V1 (o cualquier placa ESP32 válida), 3 LEDs de 5 mm (aunque para este ejemplo solo uses uno), 3 resistencias de 330 Ω, una protoboard y cables jumper.

Ejemplo con analogWrite() — código completo

Abre tu Arduino IDE y copia el siguiente código. Este ejemplo aumenta y disminuye la intensidad del LED de forma progresiva usando la función analogWrite().

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Detalles completos del proyecto en https://RandomNerdTutorials.com/esp32-pwm-arduino-ide/
*/

// Número del pin del LED
const int ledPin = 16;  // 16 corresponde al GPIO 16

void setup() {
  // Configura el LED como salida
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // Aumenta la intensidad del LED
  for (int dutyCycle = 0; dutyCycle <= 255; dutyCycle++) {
    // Cambia la intensidad del LED con PWM
    analogWrite(ledPin, dutyCycle);
    delay(15);
  }

  // Disminuye la intensidad del LED
  for (int dutyCycle = 255; dutyCycle >= 0; dutyCycle--) {
    // Cambia la intensidad del LED con PWM
    analogWrite(ledPin, dutyCycle);
    delay(15);
  }
}

Cómo funciona este código paso a paso

Empiezas definiendo el pin al que está conectado el LED. En este ejemplo, el LED está en el GPIO 16:

const int ledPin = 16;

En setup() se configura el LED como salida usando pinMode():

pinMode(ledPin, OUTPUT);

Dentro de loop(), el primer bucle for varía el duty cycle entre 0 y 255 para aumentar la intensidad del LED de forma gradual. Fíjate en el uso de analogWrite(): solo tienes que pasarle como argumentos el pin del LED y el duty cycle:

for (int dutyCycle = 0; dutyCycle <= 255; dutyCycle++) {
  analogWrite(ledPin, dutyCycle);
  delay(15);
}

El segundo bucle hace lo contrario: varía el duty cycle entre 255 y 0 para disminuir la intensidad:

for (int dutyCycle = 255; dutyCycle >= 0; dutyCycle--) {
  analogWrite(ledPin, dutyCycle);
  delay(15);
}

El delay(15) entre iteraciones hace que la transición sea suave y visible al ojo humano. Si lo reduces, el efecto será más rápido; si lo aumentas, más lento.

Probando el ejemplo

Sube el código a tu ESP32. Asegúrate de tener la placa correcta y el puerto COM seleccionado. Observa tu circuito: deberías ver un LED que aumenta y disminuye su intensidad gradualmente, creando el clásico efecto “respiración”.

Ejemplo con la API LEDC — código completo

Ahora veamos el mismo efecto pero usando las funciones LEDC específicas del ESP32, que te dan un control más preciso:

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Detalles completos del proyecto en https://RandomNerdTutorials.com/esp32-pwm-arduino-ide/
*/

// Número del pin del LED
const int ledPin = 16;  // 16 corresponde al GPIO 16

// Propiedades del PWM
const int freq = 5000;
const int resolution = 8;

void setup() {
  // Configura el PWM del LED
  ledcAttach(ledPin, freq, resolution);

  // Si quieres asignar un canal específico, usa lo siguiente:
  // ledcAttachChannel(ledPin, freq, resolution, 0);
}

void loop() {
  // Aumenta la intensidad del LED
  for (int dutyCycle = 0; dutyCycle <= 255; dutyCycle++) {
    ledcWrite(ledPin, dutyCycle);
    delay(15);
  }

  // Disminuye la intensidad del LED
  for (int dutyCycle = 255; dutyCycle >= 0; dutyCycle--) {
    ledcWrite(ledPin, dutyCycle);
    delay(15);
  }
}

Cómo funciona este código paso a paso

Primero se define el pin del LED, igual que antes (GPIO 16), y se establecen las propiedades del PWM: frecuencia y resolución.

const int freq = 5000;
const int resolution = 8;

Como estamos usando una resolución de 8 bits, el duty cycle se controla con un valor de 0 a 255, igual que con analogWrite().

En setup() se configura el pin LEDC con ledcAttach(), pasando el pin, la frecuencia y la resolución:

ledcAttach(ledPin, freq, resolution);

Esto configura el pin LEDC con la frecuencia y resolución definidas, y le asigna un canal PWM por defecto (seleccionado automáticamente).

Si quieres configurar el canal PWM manualmente, debes usar ledcAttachChannel() en su lugar. El último argumento es el número de canal PWM:

ledcAttachChannel(ledPin, freq, resolution, 0);

Finalmente, en loop() se aumenta y disminuye la intensidad del LED con ledcWrite(), que es la función equivalente a analogWrite() en la API LEDC:

ledcWrite(ledPin, dutyCycle);

Probando el ejemplo

Sube el código a tu ESP32, asegurándote de tener la placa y el puerto correctos. Verás el mismo efecto que en el ejemplo anterior: un LED que se enciende y se apaga de forma gradual.

¿Cuál de los dos métodos deberías usar?

La elección depende de tus necesidades:

Usa analogWrite() si quieres una solución simple y rápida, similar a la de Arduino clásico, y no necesitas controlar el canal PWM específico.

Usa la API LEDC si necesitas controlar múltiples canales PWM de forma independiente, ajustar la frecuencia y la resolución de forma individual, o integrar el PWM con otras funciones avanzadas del ESP32. Es la opción más recomendada para proyectos profesionales.

Conclusión

En resumen, en este artículo has aprendido a usar el controlador LED PWM del ESP32 con Arduino IDE para atenuar un LED. Los conceptos que has visto se pueden aplicar a cualquier otra salida que acepte PWM, como motores DC, servos, tiras LED direccionables o altavoces, simplemente ajustando la frecuencia y resolución adecuadas para cada dispositivo.

Dominar el PWM es uno de esos pasos que abren la puerta a un montón de proyectos nuevos. Con esta base, ya puedes empezar a controlar el mundo real de forma analógica usando solo señales digitales.

Si quieres seguir aprendiendo, los siguientes temas naturales son el ADC del ESP32 (para leer señales analógicas) y las interrupciones y timers (para reaccionar a eventos externos sin bloquear el programa).

Vistas: 0

Descubre más desde CIBERED

Suscríbete y recibe las últimas entradas en tu correo electrónico.

Scroll al inicio