In breve:
analogWrite()e PWM non funzionano con un dimmer AC TRIAC. Un TRIAC non è una resistenza né un transistor DC. Regola la potenza tramite controllo di fase: si apre in un momento calcolato con precisione in ogni semiciclo, sincronizzato con il segnale di passaggio per lo zero. Senza passaggio per lo zero e la libreria corretta — il carico sarà solo completamente acceso o completamente spento, senza valori intermedi.
Descrizione del problema
Hai collegato un dimmer AC, trovato il pin DIM — e provato a controllarlo con
analogWrite() come una normale uscita PWM. O hai usato ledc su ESP32.
Risultato: il carico è al 100% o completamente spento. Nessuna luminosità intermedia.
A volte il comportamento è ancora più inaspettato:
- Con valori PWM bassi il carico non si accende affatto
- Con valori alti — salta direttamente a piena potenza
- Un valore del 50% (128 su 255) non dà il 50% di luminosità
Questo non è un bug nel codice né un modulo difettoso. È un'incompatibilità fondamentale tra il metodo di controllo e il tipo di carico.
Situazioni tipiche nei forum:
- «Ho collegato il pin DIM del dimmer al PWM, analogWrite(128) ma la lampada è al massimo»
- «Ho provato PWM sul dimmer TRIAC ma nessun effetto di dimmerizzazione»
- «ESP32 ledc sul pin del dimmer — la luce si accende e si spegne e basta»
- «Perché analogWrite non funziona con il dimmer AC?»
- Pin ZC non collegato affatto — solo DIM su un'uscita PWM
Causa profonda
PWM — per corrente continua (DC)
PWM (modulazione di larghezza di impulso) controlla la potenza tramite commutazione rapida: un transistor si apre e si chiude migliaia di volte al secondo, e il carico riceve una tensione media proporzionale al duty cycle.
PWM 50% duty cycle (carico DC — striscia LED, motore, riscaldatore DC):
Tensione:
┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐
─┘ └──┘ └──┘ └──┘ └──┘ └─
│←ON→│←OFF→│ ← frequenza 1–20 kHz
Potenza media = 50% ✅Questo funziona perché un carico DC risponde alla tensione media. Un riscaldatore scalda a potenza media; un LED lampeggia abbastanza velocemente da non essere notato dall'occhio.
TRIAC — per corrente alternata (AC): funziona diversamente
Un TRIAC è un raddrizzatore controllato al silicio per AC. Si comporta in modo fondamentalmente diverso:
- Si aggancia — una volta che la corrente inizia a scorrere (e supera la corrente di mantenimento), il TRIAC resta aperto fino alla fine del semiciclo, anche se il segnale di gate viene rimosso.
- Si spegne automaticamente al passaggio per lo zero dell'onda sinusoidale — quando la corrente scende sotto la corrente di mantenimento.
- Non risponde al PWM rapido: un singolo impulso di gate di qualsiasi durata apre il TRIAC fino alla fine del semiciclo. 10 µs o 5 ms — il risultato è lo stesso.
Onda sinusoidale AC (50 Hz):
╭──────╮ ╭──────╮
│ │ │ │
────╯ ╰────────╯ ╰────
↑ ↑ ↑ ↑
ZC ZC(-) ZC ZC(-)
(100 impulsi al secondo)TRIAC si apre al ZC — il carico riceve il semiciclo COMPLETO (100%):
╭──────╮ ╭──────╮
│//////│ │//////│
────╯ ╰────────╯ ╰────
↑ si apre ↑ si apre al ZCTRIAC si apre con 5 ms di ritardo — il carico riceve METÀ del semiciclo (~50%):
──────╮ ──────╮
│ │
──────╯──────── ─────╯──────
↑ ↑ ↑ ↑
ZC si apre ZC si apre
(dopo 5 ms) (dopo 5 ms)Perché il PWM "non vede" il TRIAC
Quando applichi 50% PWM (es. 500 Hz) al pin DIM del TRIAC:
- PWM commuta 500 volte al secondo
- Il primo impulso HIGH apre il TRIAC
- Gli impulsi LOW successivi non hanno effetto — il TRIAC si è già agganciato
- Resta aperto fino alla fine del semiciclo (10 ms a 50 Hz)
- Il carico finisce a piena potenza
Nessun passaggio per lo zero — nessun timing — nessuna dimmerizzazione.
Tabella: PWM vs taglio di fase
| Parametro | PWM (DC) | Taglio di fase (AC TRIAC) |
|---|---|---|
| Tipo di segnale | Commutazione continua | Singolo impulso di gate |
| Serve ZC? | No | Sì — obbligatorio |
| Serve libreria? | No (analogWrite) |
Sì |
| Tipo di carico | DC (striscia LED, motore, riscaldatore) | AC (lampada, alogena, riscaldatore) |
| Metodo di controllo | Duty cycle dell'impulso | Ritardo del gate relativo al ZC |
| Frequenza di commutazione | 1–20 kHz | 100–120 Hz (una volta per semiciclo) |
| Intervallo di lavoro | 0–100% | ~10–95% (limitazione del TRIAC) |
Soluzioni
🟢 Per principianti: DimmerLink — collega e usa
Non vuoi occuparti di passaggio per lo zero, angolo di fase e ISR? DimmerLink gestisce tutta la logica internamente — basta impostare un livello.
DimmerLink 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.
Quando sceglierlo:
Cablaggio:
DimmerLink → Arduino/ESP32
VCC → 3.3V (ESP32) / 5V (Arduino)
GND → GND
SDA → SDA (GPIO 21 su ESP32, A4 su Uno)
SCL → SCL (GPIO 22 su ESP32, A5 su Uno)Codice:
// DimmerLink — impostare la luminosità come semplice valore 0–100
// Nessun PWM, passaggio per lo zero o ISR — tutto gestito dentro DimmerLink
// Doc: 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); // spento
delay(2000);
setLevel(50); // luminosità 50%
delay(2000);
setLevel(100); // luminosità massima
}
void loop() {}🔵 Per utenti avanzati: controllo di fase corretto
Vuoi lavorare direttamente con il dimmer senza DimmerLink? Devi collegare il passaggio per lo zero e usare una libreria.
Cosa devi collegare:
| Pin del dimmer | Collegare a |
|---|---|
| VCC | 5V (Arduino) / 3.3V (ESP32) |
| GND | GND |
| ZC | Pin con supporto interrupt (2 o 3 su Arduino Uno; qualsiasi GPIO su ESP32) |
| DIM | Qualsiasi uscita digitale |
Differenza chiave dal PWM: il pin DIM riceve un singolo impulso breve (~100 µs) al momento giusto, calcolato rispetto al ZC. Nessun segnale PWM continuo.
Opzione A: ESP32 con rbdimmerESP32 ✅ Consigliato
// Piattaforma: ESP32 dual-core
// Libreria: rbdimmerESP32 — taglio di fase, non PWM
// https://github.com/robotdyn-dimmer/rbdimmerESP32
#include "rbdimmerESP32.h"
#define ZC_PIN 18 // passaggio per lo zero — OBBLIGATORIO
#define DIM_PIN 19 // controllo TRIAC
rbdimmer dimmer;
void setup() {
dimmer.begin(ZC_PIN, DIM_PIN, 50); // rete 50 Hz
dimmer.setPower(50); // 50% — funziona tramite taglio di fase
}
void loop() {
// Variazione graduale della luminosità
for (int p = 10; p <= 95; p++) {
dimmer.setPower(p);
delay(30);
}
for (int p = 95; p >= 10; p--) {
dimmer.setPower(p);
delay(30);
}
}Cosa succede dentro la libreria:
1. L'interrupt ZC si attiva (t=0)
↓
2. Calcolo del ritardo del gate (fronte di salita, 50 Hz):
delay_us = (100 - power%) × 78
Esempio: 50% → delay = 50 × 78 = 3 900 µs
↓
3. Timer hardware: si attiva dopo 3 900 µs
↓
4. Invio di un impulso breve su DIM (~100 µs)
↓
5. Il TRIAC si apre e resta aperto fino al prossimo ZC
⚠️ Intervallo di lavoro — non 0–100%, ma ~10–95%:
100% → delay = 0 µs (si apre al ZC, potenza massima) ✅
0% → delay = 7 800 µs (78% del semiciclo) → il carico riceve 22%,
non 0%. Per spegnere — non aprire il TRIAC affatto.
< 10% — il TRIAC si apre così tardi che la corrente non può superare
la corrente di mantenimento → sfarfallio instabile.
Le librerie quindi limitano l'intervallo: setPower(0) = spento,
setPower(1–9) ≈ 10%, setPower(95–100) ≈ 95%.Opzione B: Arduino Uno/Mega con RBDdimmer
// Piattaforma: Arduino Uno / Mega / Nano (AVR)
// Libreria: RBDdimmer — https://github.com/robotdyn/dimmer
// ZC È OBBLIGATORIO! Arduino Uno: solo pin 2 o 3
#include <RBDdimmer.h>
#define ZC_PIN 2 // passaggio per lo zero — pin 2 (con supporto interrupt su Uno)
#define DIM_PIN 11 // controllo TRIAC
dimmerLamp dimmer(DIM_PIN, ZC_PIN);
void setup() {
dimmer.begin(NORMAL_MODE, ON);
dimmer.setPower(50); // 50%
}
void loop() {}⚠️ Errori comuni
-
«Ho collegato DIM al PWM, non ho collegato ZC affatto»: Senza ZC, il taglio di fase è fisicamente impossibile. Il pin ZC è una parte obbligatoria del circuito, non un'opzione.
-
«
analogWrite(DIM_PIN, 128)— la lampada non sfarfalla, resta accesa»: Questo è il comportamento previsto.analogWriteapre il TRIAC con il primissimo impulso HIGH e resta agganciato. Usa una libreria con ZC. -
«Ho impostato la frequenza PWM a 100 Hz — niente è cambiato»: Far corrispondere la frequenza PWM alla frequenza di ZC non aiuta. Il TRIAC si aggancia comunque al primo impulso.
-
«PWM funzionava con carico DC — perché non con AC?»: I carichi DC (strisce LED 12V, motori DC) usano controllo a transistor e rispondono alla tensione media. Il TRIAC AC è una fisica diversa. Vedi la tabella sopra.
-
«Posso lasciare DIM su PWM solo per accendere/spegnere?»: Tecnicamente sì — puoi accendere/spegnere il carico con un semplice HIGH/LOW. Ma non è dimmerizzazione. E senza ZC il TRIAC può attivarsi in un punto casuale dell'onda sinusoidale, causando interferenze e stress sul TRIAC.
Controllo rapido
Problemi correlati
- Passaggio per lo zero non rilevato →
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
Hai ancora domande?
Ask on forum.rbdimmer.com or open a GitHub Issue.