Saltar al contenido
GEEKnodes

Electrónica

PWM explicado: ciclo de trabajo, analogWrite en Arduino y LEDC en ESP32

Qué es el PWM, cómo funcionan el ciclo de trabajo y la frecuencia, cómo usar analogWrite en Arduino y LEDC en ESP32 para LED, motores y servos.

El PWM es la forma que tienen los microcontroladores de «simular» una salida analógica usando solo dos estados: encendido y apagado. Con él regulas el brillo de un LED, la velocidad de un motor o la posición de un servo. En esta guía aprenderás qué son el ciclo de trabajo y la frecuencia, y cómo generar PWM con analogWrite en Arduino y con LEDC en ESP32.

En resumen

  • PWM = una señal cuadrada que se enciende y apaga muy rápido; lo que cambia es cuánto tiempo está encendida.
  • El ciclo de trabajo (duty cycle) es ese porcentaje: 50 % en un pin de 5 V equivale de media a 2,5 V.
  • En Arduino Uno, analogWrite(pin, 0–255) funciona a unos 490 Hz (980 Hz en los pines 5 y 6).
  • En ESP32 (core 3.x) se usa ledcAttach(pin, frecuencia, resolución) y ledcWrite(pin, valor).

Qué es el PWM

PWM significa Pulse Width Modulation, modulación por ancho de pulso. Un pin digital solo puede estar a 0 V o a la tensión de alimentación (5 V o 3,3 V). Pero si lo enciendes y apagas cientos o miles de veces por segundo, la carga «ve» un valor medio.

Dos parámetros definen la señal:

  • Frecuencia: cuántos ciclos completos hay por segundo (Hz).
  • Ciclo de trabajo: qué porcentaje de cada ciclo está la señal en alto.

Ciclo de trabajo y tensión media

La tensión media es proporcional al ciclo de trabajo:

V media = ciclo de trabajo × V alimentación
Tres señales PWM de 5 V al 25 %, 50 % y 75 % de ciclo de trabajo con su tensión media de 1,25 V, 2,5 V y 3,75 V
Misma frecuencia, distinto tiempo en alto: la tensión media sigue al ciclo de trabajo
Ciclo de trabajoValor analogWrite (8 bits)Tensión media a 5 VTensión media a 3,3 V
0 %00 V0 V
25 %641,25 V0,83 V
50 %1282,5 V1,65 V
75 %1913,75 V2,48 V
100 %2555 V3,3 V

Importante: no es una tensión analógica real. Si mides con un multímetro verás el valor medio, pero un osciloscopio mostrará la señal cuadrada. Para una tensión analógica de verdad necesitas un filtro RC o un DAC.

Qué frecuencia usar

AplicaciónFrecuencia típicaMotivo
Brillo de LED500 Hz – 5 kHzPor encima de unos cientos de Hz el ojo no ve parpadeo
Motor DC1 kHz – 20 kHzA frecuencias audibles el motor «pita»; por encima de 20 kHz no se oye
Servo de modelismo50 Hz (periodo de 20 ms)Es lo que espera el servo
Ventilador de PC de 4 pines25 kHzEspecificación de los ventiladores PWM

PWM en Arduino: analogWrite

En las placas Arduino clásicas, analogWrite() genera PWM con una resolución de 8 bits (0–255).

analogWrite(pin, valor);  // valor de 0 (apagado) a 255 (siempre encendido)

No hace falta configurar el pin con pinMode() antes de usarla.

Pines y frecuencias según la referencia oficial

PlacaPines PWMFrecuencia
Uno R3, Nano, Mini3, 5, 6, 9, 10, 11490 Hz (pines 5 y 6: 980 Hz)
Uno R4 Minima / WiFi3, 5, 6, 9, 10, 11490 Hz
Uno WiFi Rev2, Nano Every3, 5, 6, 9, 10976 Hz

En la placa, los pines PWM suelen estar marcados con el símbolo ~.

Ejemplo: LED que se enciende y apaga suavemente

LED con su resistencia (220 Ω) en el pin 9. Si dudas del valor, usa la calculadora de resistencia para LED.

const int LED = 9;

void setup() {
  // analogWrite no necesita pinMode
}

void loop() {
  for (int brillo = 0; brillo <= 255; brillo++) {
    analogWrite(LED, brillo);
    delay(5);
  }
  for (int brillo = 255; brillo >= 0; brillo--) {
    analogWrite(LED, brillo);
    delay(5);
  }
}

El brillo no es lineal

El ojo humano percibe el brillo de forma logarítmica: pasar de 0 a 25 se nota mucho, pasar de 200 a 255 apenas. Para un fundido que parezca uniforme se aplica una corrección gamma, por ejemplo elevando el valor normalizado al cuadrado o al cubo antes de escribirlo.

PWM en ESP32: LEDC

El ESP32 genera PWM con su periférico LEDC (LED Control). A diferencia del Arduino Uno, permite elegir frecuencia y resolución en casi cualquier pin de salida.

API del core 3.x de Arduino-ESP32

Desde la versión 3.0 del core, ledcSetup() y ledcAttachPin() se eliminaron y se sustituyeron por una sola función. Los canales se asignan automáticamente.

ledcAttach(pin, frecuencia, resolucion);  // resolución en bits
ledcWrite(pin, ciclo);                    // ciclo de 0 a (2^resolucion - 1)
ledcDetach(pin);                          // liberar el pin

Según la documentación de Espressif, la resolución admite de 1 a 14 bits en general, y hasta 20 bits en el ESP32 original. Cuanto mayor es la frecuencia, menor es la resolución máxima disponible.

Ejemplo: fundido de LED en ESP32

const int LED = 2;
const int FRECUENCIA = 5000;  // 5 kHz
const int RESOLUCION = 8;     // 0–255

void setup() {
  ledcAttach(LED, FRECUENCIA, RESOLUCION);
}

void loop() {
  for (int ciclo = 0; ciclo <= 255; ciclo++) {
    ledcWrite(LED, ciclo);
    delay(5);
  }
  for (int ciclo = 255; ciclo >= 0; ciclo--) {
    ledcWrite(LED, ciclo);
    delay(5);
  }
}

Si copias un ejemplo antiguo con ledcSetup(canal, ...) y no compila, es por este cambio de API: adáptalo a ledcAttach o instala la versión 2.0.17 del core para mantener el código antiguo.

Resolución y valores máximos

ResoluciónValoresMáximo en ledcWrite
8 bits256255
10 bits10241023
12 bits40964095

Usos prácticos del PWM

Brillo de LED y tiras LED

Un LED suelto se conecta al pin con su resistencia. Para una tira LED de 12 V necesitas un MOSFET de nivel lógico entre la tira y GND, controlado por el pin PWM. Lo explicamos en el transistor como interruptor.

Velocidad de motores DC

El motor nunca se conecta directo al pin. Usa:

  • Un MOSFET más diodo flyback si solo necesitas un sentido de giro.
  • Un puente H (L298N, TB6612FNG, DRV8833) si necesitas cambiar de sentido.
Pin PWM del microcontrolador a la puerta de un MOSFET que conmuta un motor DC con diodo flyback en paralelo
El pin solo da la señal: el MOSFET mueve la corriente y el diodo protege del pico

El PWM regula la velocidad: con un ciclo bajo, puede que el motor no arranque por el rozamiento. Suele hacer falta un mínimo (por ejemplo, 30–40 %) para que empiece a girar.

Servos

Un servo de modelismo no se controla con el ciclo de trabajo en porcentaje, sino con el ancho del pulso dentro de una señal de 50 Hz:

Ancho de pulsoPosición típica
~1 msUn extremo (0°)
~1,5 msCentro (90°)
~2 msOtro extremo (180°)

Los márgenes exactos varían según el modelo. Lo más cómodo es usar la librería Servo:

#include <Servo.h>

Servo servo;

void setup() {
  servo.attach(9);
}

void loop() {
  servo.write(0);
  delay(1000);
  servo.write(90);
  delay(1000);
  servo.write(180);
  delay(1000);
}

En el Arduino Uno, la librería Servo usa un temporizador que desactiva analogWrite() en los pines 9 y 10. En ESP32 se usa una librería específica, como ESP32Servo.

Errores habituales

ErrorSíntomaSolución
analogWrite en un pin sin ~El LED solo se enciende o se apagaUsa un pin PWM
Motor conectado directo al pinReinicios o pin dañadoMOSFET o puente H
Código LEDC antiguo en core 3.xError de compilación con ledcSetupUsa ledcAttach y ledcWrite(pin, …)
ledcWrite con valor mayor que la resoluciónSalida siempre al máximoAjusta el rango: 8 bits = 0–255
Motor que pitaPWM en frecuencia audibleSube la frecuencia por encima de 20 kHz (si el driver lo admite)
Servo temblorosoAlimentado desde el pin 5 V del ArduinoUsa una fuente aparte con GND común

Relacionados

Preferencias de accesibilidad

Perfiles rápidos

Texto y lectura

Tamaño del texto
Por defecto
Altura de línea
Por defecto
Espaciado entre letras
Por defecto
Espaciado entre palabras
Por defecto

Color

Movimiento y orientación

Cursor