Resumen:
analogWrite()y PWM no funcionan con un dimmer AC TRIAC. Un TRIAC no es una resistencia ni un transistor DC. Regula la potencia mediante control de fase: se abre en un momento calculado con precisión en cada semiciclo, sincronizado con la señal de cruce por cero. Sin cruce por cero y la biblioteca correcta — la carga solo estará completamente encendida o apagada, sin valores intermedios.
Descripción del problema
Conectaste un dimmer AC, encontraste el pin DIM — e intentaste controlarlo con
analogWrite() como una salida PWM normal. O usaste ledc en ESP32.
Resultado: la carga está al 100% o completamente apagada. Sin brillo intermedio.
A veces el comportamiento es aún más inesperado:
- Con valores PWM bajos, la carga no enciende en absoluto
- Con valores altos — salta directamente a potencia máxima
- Un valor de 50% (128 de 255) no da 50% de brillo
Esto no es un error de código ni un módulo defectuoso. Es una incompatibilidad fundamental entre el método de control y el tipo de carga.
Situaciones típicas en foros:
- «Conecté el pin DIM del dimmer a PWM, analogWrite(128), pero la lámpara está a máxima potencia»
- «Probé PWM en el dimmer TRIAC, pero no hay efecto de atenuación»
- «ESP32 ledc en el pin del dimmer — la luz solo se enciende y se apaga»
- «¿Por qué analogWrite no funciona con el dimmer AC?»
- Pin ZC no conectado en absoluto — solo DIM en una salida PWM
Causa raíz
PWM — para corriente continua (DC)
PWM (modulación por ancho de pulso) controla la potencia mediante conmutación rápida: un transistor se abre y se cierra miles de veces por segundo, y la carga recibe un voltaje promedio proporcional al ciclo de trabajo.
PWM 50% ciclo de trabajo (carga DC — tira LED, motor, calentador DC):
Voltaje:
┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐
─┘ └──┘ └──┘ └──┘ └──┘ └─
│←ON→│←OFF→│ ← frecuencia 1–20 kHz
Potencia promedio = 50% ✅Esto funciona porque una carga DC responde al voltaje promedio. Un calentador calienta a potencia promedio; un LED parpadea lo suficientemente rápido para que el ojo no lo note.
TRIAC — para corriente alterna (AC): funciona diferente
Un TRIAC es un rectificador controlado por silicio para AC. Se comporta de manera fundamentalmente diferente:
- Se enclava — una vez que la corriente comienza a fluir (y supera la corriente de mantenimiento), el TRIAC permanece abierto hasta el final del semiciclo, incluso si la señal de compuerta se retira.
- Se apaga automáticamente en el cruce por cero de la onda sinusoidal — cuando la corriente cae por debajo de la corriente de mantenimiento.
- No responde al PWM rápido: un solo pulso de compuerta de cualquier duración abre el TRIAC hasta el final del semiciclo. 10 µs o 5 ms — el resultado es el mismo.
Onda sinusoidal AC (50 Hz):
╭──────╮ ╭──────╮
│ │ │ │
────╯ ╰────────╯ ╰────
↑ ↑ ↑ ↑
ZC ZC(-) ZC ZC(-)
(100 pulsos por segundo)TRIAC se abre en ZC — la carga recibe el semiciclo COMPLETO (100%):
╭──────╮ ╭──────╮
│//////│ │//////│
────╯ ╰────────╯ ╰────
↑ se abre ↑ se abre en ZCTRIAC se abre con 5 ms de retraso — la carga recibe la MITAD del semiciclo (~50%):
──────╮ ──────╮
│ │
──────╯──────── ─────╯──────
↑ ↑ ↑ ↑
ZC se abre ZC se abre
(después de 5 ms) (después de 5 ms)Por qué el PWM "no ve" el TRIAC
Cuando aplicas 50% PWM (p. ej., 500 Hz) al pin DIM del TRIAC:
- PWM conmuta 500 veces por segundo
- El primer pulso HIGH abre el TRIAC
- Los pulsos LOW posteriores no significan nada — el TRIAC ya está enclavado
- Permanece abierto hasta el final del semiciclo (10 ms a 50 Hz)
- La carga termina a potencia máxima
Sin cruce por cero — sin temporización — sin atenuación.
Tabla: PWM vs corte de fase
| Parámetro | PWM (DC) | Corte de fase (AC TRIAC) |
|---|---|---|
| Tipo de señal | Conmutación continua | Pulso de compuerta único |
| ¿Necesita ZC? | No | Sí — obligatorio |
| ¿Necesita biblioteca? | No (analogWrite) |
Sí |
| Tipo de carga | DC (tira LED, motor, calentador) | AC (lámpara, halógena, calentador) |
| Método de control | Ciclo de trabajo del pulso | Retraso de compuerta relativo a ZC |
| Frecuencia de conmutación | 1–20 kHz | 100–120 Hz (una vez por semiciclo) |
| Rango de trabajo | 0–100% | ~10–95% (limitación del TRIAC) |
Soluciones
🟢 Para principiantes: DimmerLink — conectar y usar
¿No quieres lidiar con cruce por cero, ángulo de fase e ISR? DimmerLink maneja toda la lógica internamente — solo configura un nivel.
Cualquier ESP32 is a controller with its own zero-cross detector and TRIAC phase control. Your microcontroller only sends a brightness level (0–100%) via I2C or UART. No PWM, no zero-cross on the MCU side.
Cuándo elegirlo:
Cableado:
DimmerLink → Arduino/ESP32
VCC → 3.3V (ESP32) / 5V (Arduino)
GND → GND
SDA → SDA (GPIO 21 en ESP32, A4 en Uno)
SCL → SCL (GPIO 22 en ESP32, A5 en Uno)Código:
// DimmerLink — configurar brillo como un simple valor 0–100
// Sin PWM, cruce por cero o ISR — todo gestionado dentro de DimmerLink
// Docs: https://www.rbdimmer.com/docs/dimmerlink-I2CCommunication
#include <Wire.h>
#define DIMMER_ADDR 0x50
#define REG_LEVEL 0x10
void setLevel(uint8_t level) { // level: 0–100%
Wire.beginTransmission(DIMMER_ADDR);
Wire.write(REG_LEVEL);
Wire.write(level);
Wire.endTransmission();
}
void setup() {
Wire.begin();
setLevel(0); // apagado
delay(2000);
setLevel(50); // brillo 50%
delay(2000);
setLevel(100); // brillo máximo
}
void loop() {}🔵 Para usuarios avanzados: control de fase correcto
¿Quieres trabajar con el dimmer directamente sin DimmerLink? Necesitas conectar el cruce por cero y usar una biblioteca.
Qué necesitas conectar:
| Pin del dimmer | Conectar a |
|---|---|
| VCC | 5V (Arduino) / 3.3V (ESP32) |
| GND | GND |
| ZC | Pin con capacidad de interrupción (2 o 3 en Arduino Uno; cualquier GPIO en ESP32) |
| DIM | Cualquier salida digital |
Diferencia clave con PWM: el pin DIM recibe un único pulso corto (~100 µs) en el momento correcto, calculado en relación al ZC. Sin señal PWM continua.
Opción A: ESP32 con rbdimmerESP32 ✅ Recomendado
// Plataforma: ESP32 de doble núcleo
// Biblioteca: rbdimmerESP32 — corte de fase, no PWM
// https://github.com/robotdyn-dimmer/rbdimmerESP32
#include "rbdimmerESP32.h"
#define ZC_PIN 18 // cruce por cero — OBLIGATORIO
#define DIM_PIN 19 // control TRIAC
rbdimmer dimmer;
void setup() {
dimmer.begin(ZC_PIN, DIM_PIN, 50); // red 50 Hz
dimmer.setPower(50); // 50% — funciona por corte de fase
}
void loop() {
// Barrido suave de brillo
for (int p = 10; p <= 95; p++) {
dimmer.setPower(p);
delay(30);
}
for (int p = 95; p >= 10; p--) {
dimmer.setPower(p);
delay(30);
}
}Qué sucede dentro de la biblioteca:
1. Se dispara la interrupción ZC (t=0)
↓
2. Calcular retraso de compuerta (borde de ataque, 50 Hz):
delay_us = (100 - power%) × 78
Ejemplo: 50% → delay = 50 × 78 = 3 900 µs
↓
3. Timer de hardware: se dispara después de 3 900 µs
↓
4. Enviar pulso corto a DIM (~100 µs)
↓
5. TRIAC se abre y permanece abierto hasta el siguiente ZC
⚠️ Rango de trabajo — no 0–100%, sino ~10–95%:
100% → delay = 0 µs (se abre en ZC, potencia máxima) ✅
0% → delay = 7 800 µs (78% del semiciclo) → la carga recibe 22%,
no 0%. Para apagar — no abrir el TRIAC en absoluto.
< 10% — TRIAC se abre tan tarde que la corriente no puede superar
la corriente de mantenimiento → parpadeo inestable.
Las bibliotecas por lo tanto limitan el rango: setPower(0) = apagado,
setPower(1–9) ≈ 10%, setPower(95–100) ≈ 95%.Opción B: Arduino Uno/Mega con RBDdimmer
// Plataforma: Arduino Uno / Mega / Nano (AVR)
// Biblioteca: RBDdimmer — https://github.com/robotdyn/dimmer
// ¡ZC ES OBLIGATORIO! Arduino Uno: solo pines 2 o 3
#include <RBDdimmer.h>
#define ZC_PIN 2 // cruce por cero — pin 2 (con capacidad de interrupción en Uno)
#define DIM_PIN 11 // control TRIAC
dimmerLamp dimmer(DIM_PIN, ZC_PIN);
void setup() {
dimmer.begin(NORMAL_MODE, ON);
dimmer.setPower(50); // 50%
}
void loop() {}⚠️ Errores comunes
-
«Conecté DIM a PWM, no conecté ZC en absoluto»: Sin ZC, el corte de fase es físicamente imposible. El pin ZC es una parte obligatoria del circuito, no opcional.
-
«
analogWrite(DIM_PIN, 128)— la lámpara no parpadea, solo está encendida»: Ese es el comportamiento esperado.analogWriteabre el TRIAC con el primer pulso HIGH y permanece enclavado. Use una biblioteca con ZC. -
«Configuré la frecuencia PWM a 100 Hz — nada cambió»: Igualar la frecuencia PWM a la tasa de ZC no ayuda. El TRIAC se enclava de todos modos con el primer pulso.
-
«PWM funcionó con carga DC — ¿por qué no con AC?»: Las cargas DC (tiras LED 12V, motores DC) usan control por transistor y responden al voltaje promedio. El TRIAC AC es una física diferente. Vea la tabla anterior.
-
«¿Puedo dejar DIM en PWM solo para encender/apagar?»: Técnicamente sí — puedes encender/apagar la carga con un simple HIGH/LOW. Pero eso no es atenuación. Y sin ZC, el TRIAC puede dispararse en un punto aleatorio de la onda sinusoidal, causando interferencias y estrés en el TRIAC.
Verificación rápida
Problemas relacionados
- Cruce por cero no detectado →
troubleshooting/zero-cross-detection-errors.md - ESP32 + TRIAC: Guru Meditation Error →
troubleshooting/esp32-iram-attr.md - Trailing vs Leading Edge →
load-types/trailing-vs-leading-edge.md
¿Todavía tienes preguntas?
Ask on forum.rbdimmer.com or open a GitHub Issue.