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)yledcWrite(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

| Ciclo de trabajo | Valor analogWrite (8 bits) | Tensión media a 5 V | Tensión media a 3,3 V |
|---|---|---|---|
| 0 % | 0 | 0 V | 0 V |
| 25 % | 64 | 1,25 V | 0,83 V |
| 50 % | 128 | 2,5 V | 1,65 V |
| 75 % | 191 | 3,75 V | 2,48 V |
| 100 % | 255 | 5 V | 3,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ón | Frecuencia típica | Motivo |
|---|---|---|
| Brillo de LED | 500 Hz – 5 kHz | Por encima de unos cientos de Hz el ojo no ve parpadeo |
| Motor DC | 1 kHz – 20 kHz | A frecuencias audibles el motor «pita»; por encima de 20 kHz no se oye |
| Servo de modelismo | 50 Hz (periodo de 20 ms) | Es lo que espera el servo |
| Ventilador de PC de 4 pines | 25 kHz | Especificació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
| Placa | Pines PWM | Frecuencia |
|---|---|---|
| Uno R3, Nano, Mini | 3, 5, 6, 9, 10, 11 | 490 Hz (pines 5 y 6: 980 Hz) |
| Uno R4 Minima / WiFi | 3, 5, 6, 9, 10, 11 | 490 Hz |
| Uno WiFi Rev2, Nano Every | 3, 5, 6, 9, 10 | 976 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ón | Valores | Máximo en ledcWrite |
|---|---|---|
| 8 bits | 256 | 255 |
| 10 bits | 1024 | 1023 |
| 12 bits | 4096 | 4095 |
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.

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 pulso | Posición típica |
|---|---|
| ~1 ms | Un extremo (0°) |
| ~1,5 ms | Centro (90°) |
| ~2 ms | Otro 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
| Error | Síntoma | Solución |
|---|---|---|
analogWrite en un pin sin ~ | El LED solo se enciende o se apaga | Usa un pin PWM |
| Motor conectado directo al pin | Reinicios o pin dañado | MOSFET o puente H |
| Código LEDC antiguo en core 3.x | Error de compilación con ledcSetup | Usa ledcAttach y ledcWrite(pin, …) |
ledcWrite con valor mayor que la resolución | Salida siempre al máximo | Ajusta el rango: 8 bits = 0–255 |
| Motor que pita | PWM en frecuencia audible | Sube la frecuencia por encima de 20 kHz (si el driver lo admite) |
| Servo tembloroso | Alimentado desde el pin 5 V del Arduino | Usa una fuente aparte con GND común |



