Passa al contenuto

Il dimmer AC TRIAC non è PWM: come funziona la dimmerizzazione con taglio di fase

analogWrite o ledc sul pin DIM del tuo dimmer AC dà solo luminosità massima — il TRIAC non risponde al PWM. La dimmerizzazione con taglio di fase richiede un segnale di passaggio per lo zero e una libreria appropriata. Spiegato con diagrammi ASCII e codice funzionante.

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.

text
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:

  1. 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.
  2. Si spegne automaticamente al passaggio per lo zero dell'onda sinusoidale — quando la corrente scende sotto la corrente di mantenimento.
  3. 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.
text
Onda sinusoidale AC (50 Hz):
    ╭──────╮         ╭──────╮
    │      │         │      │
────╯      ╰────────╯      ╰────
    ↑      ↑         ↑      ↑
   ZC    ZC(-)      ZC    ZC(-)
   (100 impulsi al secondo)
text
TRIAC si apre al ZC — il carico riceve il semiciclo COMPLETO (100%):
    ╭──────╮         ╭──────╮
    │//////│         │//////│
────╯      ╰────────╯      ╰────
↑ si apre              ↑ si apre al ZC
text
TRIAC 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)
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:

  • ☐ Vuoi semplicemente impostare la luminosità senza studiare il taglio di fase
  • ☐ Raspberry Pi (nessun tempo reale per ISR)
  • ☐ ESP32-S2/C3/H2 (single-core, ISR non supportato)
  • ☐ Serve controllo simultaneo WiFi/MQTT senza crash
  • Cablaggio:

    text
    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:

    cpp
    // 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

    cpp
    // 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:

    text
    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

    cpp
    // 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. analogWrite apre 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

  • ☐ Pin ZC collegato a un GPIO con supporto interrupt? Senza questo, niente funziona.
  • ☐ Stai usando una libreria con passaggio per lo zero (rbdimmerESP32 / RBDdimmer / DimmerLink)?
  • ☐ Hai rimosso `analogWrite()` / `ledc` dal pin DIM?
  • ☐ Arduino Uno: ZC sul pin 2 o 3 (non 4, 5 o altri)?
  • ☐ ESP32 single-core (S2/C3/H2)? → Usa DimmerLink.


  • Problemi correlati

    • Passaggio per lo zero non rilevatotroubleshooting/zero-cross-detection-errors.md
    • ESP32 + TRIAC: Guru Meditation Errortroubleshooting/esp32-iram-attr.md
    • Trailing vs Leading Edgeload-types/trailing-vs-leading-edge.md



    Hai ancora domande?

    Ask on forum.rbdimmer.com or open a GitHub Issue.

    Condividi articolo
    Accedi per lasciare un commento