Passa al contenuto

Passaggio per lo zero non rilevato: il dimmer AC non risponde ai comandi

Dimmer AC bloccato a piena luminosità o senza risposta? Il mancato rilevamento del passaggio per lo zero è la causa più comune — pin di interrupt sbagliato, alimentazione assente sul circuito ZC o rumore. Diagnostica in 5 passi con codice di test e soluzione per Arduino ed ESP32.

In breve: Un dimmer AC non può regolare il carico se il microcontrollore non riceve il segnale di passaggio per lo zero (il momento in cui la sinusoide attraversa lo zero). Senza questo segnale è impossibile calcolare il momento di innesco del TRIAC. Cause: pin sbagliato (non supporta gli interrupt), cablaggio ZC errato, rumore sulla linea del segnale o errore software (modalità di interrupt sbagliata). Segui la checklist qui sotto passo per passo.



Descrizione del problema

Hai collegato un dimmer AC, caricato il codice di esempio — ma il carico non risponde o è sempre a piena luminosità. Il cablaggio sembra corretto, nessun errore di compilazione.

La causa più comune in questi casi è che il passaggio per lo zero non viene rilevato dal microcontrollore. La dimmerizzazione con taglio di fase funziona con questo principio: rilevare il passaggio per lo zero della sinusoide → attendere il ritardo calcolato → innescare il TRIAC. Senza passaggio per lo zero non c'è temporizzazione, e il dimmer o non accende il carico o lo mantiene al 100% senza regolazione.

Sintomi tipici:

  • Carico sempre a piena luminosità (TRIAC sempre aperto)
  • Carico non si accende affatto
  • setPower(50) non ha effetto — carico completamente acceso o spento
  • Il contatore di passaggi per lo zero non si incrementa nel monitor seriale (con debug)
  • Il codice compila senza errori ma il dimmer «non funziona»

Messaggi tipici nei forum:

  • «Il dimmer non dimmerizza — lampada sempre a piena luminosità»
  • «setPower non ha effetto»
  • «L'interrupt di passaggio per lo zero non scatta»
  • «Il dimmer funziona a volte, casualmente»



Causa profonda

Il segnale di passaggio per lo zero è generato da un circuito rilevatore di passaggio per lo zero integrato nel dimmer AC o collegato esternamente. Tipicamente è un optoaccoppiatore + partitore resistivo che produce un breve impulso a ogni passaggio per lo zero della sinusoide.

Frequenza degli impulsi: 100 Hz (rete 50 Hz) / 120 Hz (rete 60 Hz). Un impulso per ogni semiciclo.

Per ricevere questi impulsi il microcontrollore usa un interrupt esterno (attachInterrupt()). Se l'interrupt non è configurato correttamente o il segnale non raggiunge il pin giusto — il gestore ISR non viene mai chiamato, la temporizzazione non può essere calcolata, e il dimmer non funziona.

Cause principali di malfunzionamento:

  1. Pin sbagliato (non supporta gli interrupt) — errore più comune su Arduino
  2. Cablaggio ZC errato — il segnale non raggiunge il pin
  3. Modalità di interrupt sbagliata (FALLING invece di RISING o viceversa — dipende dal circuito)
  4. Rumore — molteplici scatti falsi in un semiciclo
  5. Problema di alimentazione del circuito ZC — nessun VCC sul rilevatore di passaggio per lo zero



Soluzioni



🟢 Per principianti: DimmerLink — passaggio per lo zero integrato

Non vuoi occuparti di pin di interrupt, RISING/FALLING e rumore elettrico? DimmerLink ha il proprio rilevatore di passaggio per lo zero e controlla il TRIAC in modo autonomo.

DimmerLink detects zero-cross in hardware and handles TRIAC firing timing internally. Your microcontroller only sets the brightness level — no ISR, no interrupts, no pin headaches.

Quando scegliere questa soluzione:

  • ☐ Non riesci a capire i pin di interrupt su Arduino
  • ☐ Usi Raspberry Pi (nessun tempo reale per gli interrupt)
  • ☐ Usi ESP32-S2/C3/H2 (single-core, l'ISR non funziona)
  • ☐ Vuoi una soluzione affidabile senza debug del circuito ZC
  • DimmerLink → Arduino/ESP32 cablaggio:

    • VCC → 3.3V (ESP32) o 5V (Arduino)
    • GND → GND
    • SDA → SDA (GPIO 21 su ESP32, A4 su Arduino Uno)
    • SCL → SCL (GPIO 22 su ESP32, A5 su Arduino Uno)

    Codice:

    cpp
    // DimmerLink — rilevatore di passaggio per lo zero e controllo TRIAC nel modulo
    // Il microcontrollore imposta solo il livello di luminosità
    // Documentazione: 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();        // SDA/SCL predefiniti per la tua scheda
        setLevel(50);        // luminosità 50%
    }
    void loop() {
        // Nessun ISR, nessun interrupt, nessun passaggio per lo zero sull'MCU
    }

    Risultato: Il dimmer funziona senza dipendere dai pin di interrupt o dal segnale di passaggio per lo zero sul microcontrollore.



    🔵 Per utenti avanzati: diagnosticare e correggere lo ZC

    Vuoi mantenere la connessione ISR diretta? Segui i passi diagnostici.


    Diagnostica: passi 1–5

    Passo 1: Verificare che il pin supporti gli interrupt

    Questa è la causa n. 1 su Arduino.

    cpp
    // Arduino Uno / Nano / Mini:
    // ✅ Supportano gli interrupt: SOLO pin 2 e 3
    // ❌ Tutti gli altri pin (4, 5, 6...) — interrupt non supportati
    // Corretto:
    attachInterrupt(digitalPinToInterrupt(2), zeroCrossISR, RISING);  // pin 2 ✅
    attachInterrupt(digitalPinToInterrupt(3), zeroCrossISR, RISING);  // pin 3 ✅
    // Sbagliato:
    attachInterrupt(4, zeroCrossISR, RISING);  // ❌ pin 4 — non supporta gli interrupt
    // Su Uno, attachInterrupt(4) si riferisce a INT4, che non esiste

    Su ESP32 — qualsiasi GPIO supporta gli interrupt:

    cpp
    // ESP32: qualsiasi GPIO — tutti funzionano
    attachInterrupt(digitalPinToInterrupt(18), zeroCrossISR, RISING);  // ✅
    attachInterrupt(digitalPinToInterrupt(34), zeroCrossISR, RISING);  // ✅

    Su ESP8266 — tutti i GPIO tranne GPIO 16 supportano gli interrupt; consigliati 4, 5, 12, 13, 14 (nessuna dipendenza dalla modalità di avvio).


    Passo 2: Aggiungere un contatore per verifica

    Il test più semplice — contare gli impulsi in 1 secondo:

    cpp
    // Diagnostica passaggio per lo zero: ~100 impulsi/sec attesi (rete 50 Hz)
    // o ~120 impulsi/sec (rete 60 Hz)
    #define ZC_PIN 2  // ← assicurati che sia un pin con supporto interrupt
    volatile uint32_t zcCount = 0;
    #ifdef ESP32
    void IRAM_ATTR zeroCrossISR() {  // IRAM_ATTR richiesto su ESP32
    #else
    void zeroCrossISR() {             // Arduino/ESP8266: IRAM_ATTR non necessario
    #endif
        zcCount++;
    }
    void setup() {
        Serial.begin(115200);
        pinMode(ZC_PIN, INPUT);
        attachInterrupt(digitalPinToInterrupt(ZC_PIN), zeroCrossISR, RISING);
    }
    void loop() {
        delay(1000);
        Serial.print("Impulsi ZC al secondo: ");
        Serial.println(zcCount);
        zcCount = 0;
        // Risultati attesi:
        // ~100 — rete 50 Hz, tutto OK
        // ~120 — rete 60 Hz, tutto OK
        //   0  — ZC non rilevato (problema di cablaggio o pin)
        //  >200 — rumore, scatti falsi (problema di filtro RC)
    }

    Passo 3: Verificare il cablaggio ZC

    Cablaggio tipico RBDimmer → Arduino/ESP32:

    text
    RBDimmer  →  Arduino/ESP32
    -------      -------------
    VCC       →  5V (Arduino) / 3.3V (ESP32)
    GND       →  GND
    ZC        →  Pin con supporto interrupt (2 o 3 su Arduino Uno)
    DIM       →  Qualsiasi uscita digitale

    Checklist:

  • ☐ Pin ZC collegato al GPIO corretto con supporto interrupt
  • ☐ VCC fornito al modulo (senza alimentazione il circuito ZC non funziona)
  • ☐ GND comune — sezioni logica e potenza
  • ☐ Il cavo ZC non corre parallelo ai cavi 220V (induce rumore)
  • ☐ Connettore ZC non scambiato con DIM (su alcuni moduli sono adiacenti)

  • Passo 4: Verificare la modalità di interrupt (RISING/FALLING/CHANGE)

    La modalità dipende dal circuito rilevatore ZC del tuo modulo specifico:

    cpp
    // La maggior parte dei moduli RBDimmer: RISING (impulso sul fronte di salita)
    attachInterrupt(digitalPinToInterrupt(ZC_PIN), zeroCrossISR, RISING);
    // Alcuni circuiti con optoaccoppiatore invertente: FALLING
    attachInterrupt(digitalPinToInterrupt(ZC_PIN), zeroCrossISR, FALLING);
    // Se non sei sicuro — prova CHANGE (cattura entrambi i fronti):
    // Nota: con CHANGE il contatore mostrerà ~200 Hz invece di 100 Hz
    attachInterrupt(digitalPinToInterrupt(ZC_PIN), zeroCrossISR, CHANGE);

    Usa un oscilloscopio o un analizzatore logico per verificare la forma del segnale ZC — identifica se devi catturare il fronte di salita o di discesa.


    Passo 5: Filtrare il rumore

    Se il contatore mostra >200 (su rete 50 Hz) — scatti falsi dovuti al rumore. Questo è particolarmente comune con cavi lunghi o vicinanza al carico:

    cpp
    // Antirimbalzo software per ZC: ignorare impulsi troppo vicini al precedente
    // Periodo del semiciclo a 50 Hz = 10 000 µs → filtrare tutto sotto 8 000 µs
    volatile uint32_t lastZC = 0;
    void IRAM_ATTR zeroCrossISR() {
        uint32_t now = micros();
        if (now - lastZC > 8000) {  // intervallo minimo di 8 ms tra impulsi ZC
            lastZC = now;
            // la tua logica di temporizzazione TRIAC qui
        }
    }

    Filtro hardware: un filtro RC sulla linea ZC (resistenza 1 kΩ + condensatore 100 nF tra ZC e GND) rimuove il rumore ad alta frequenza.



    Correzione: scegli la tua opzione

    Opzione A: rbdimmerESP32 su ESP32 ✅

    Quando: ESP32 dual-core con connessione diretta al dimmer. La libreria gestisce ZC e temporizzazione automaticamente:

    cpp
    // Piattaforma: ESP32 dual-core
    // Libreria: rbdimmerESP32
    #include "rbdimmerESP32.h"
    #define ZC_PIN  18  // qualsiasi GPIO ESP32
    #define DIM_PIN 19  // qualsiasi GPIO ESP32
    rbdimmer dimmer;
    void setup() {
        Serial.begin(115200);
        dimmer.begin(ZC_PIN, DIM_PIN, 50);  // rete 50 Hz
        dimmer.setPower(50);
        Serial.println("Dimmer inizializzato");
    }
    void loop() {}

    Errori comuni:

    • ZC_PIN e DIM_PIN scambiati in dimmer.begin() — verifica quale pin va al carico e quale al passaggio per lo zero.
    • Frequenza di rete sbagliata (terzo parametro) — 50 o 60 Hz.

    Opzione B: Arduino Uno/Mega con RBDdimmer
    cpp
    // Piattaforma: Arduino Uno / Mega / Nano (AVR)
    // Libreria: RBDdimmer — https://github.com/robotdyn/dimmer
    // ATTENZIONE: per ESP32 usa rbdimmerESP32, non questa libreria!
    #include <RBDdimmer.h>
    // ⚠️ Arduino Uno: ZC SOLO su pin 2 o 3
    #define ZC_PIN   2   // supporta interrupt ✅
    #define DIM_PIN  11  // qualsiasi uscita digitale
    dimmerLamp dimmer(DIM_PIN, ZC_PIN);
    void setup() {
        Serial.begin(9600);
        dimmer.begin(NORMAL_MODE, ON);
        dimmer.setPower(50);  // 50%
        Serial.println("Dimmer pronto");
    }
    void loop() {}


    ⚠️ Errori comuni

    • «Uso il pin 4 su Arduino Uno — non funziona»: I pin 4, 5, 6, ... su Uno non supportano gli interrupt esterni. Solo i pin 2 e 3. Questo è l'errore più comune dei principianti.

    • «attachInterrupt(4, ...) compila — dovrebbe funzionare»: Compila, ma non funzionerà. attachInterrupt(4, ...) su Uno si riferisce a INT4 (numero di interrupt hardware), non a GPIO 4. Usa sempre digitalPinToInterrupt(pin).

    • «Aggiunto contatore — sempre 0»: Tre possibili cause: 1. Pin sbagliato (non supporta interrupt) — verifica sopra 2. Nessuna alimentazione sul modulo ZC 3. Pin ZC non fisicamente collegato alla scheda

    • «Contatore mostra 300–400 invece di 100»: Scatti falsi dovuti al rumore. Aggiungi antirimbalzo software (vedi sopra) o un filtro RC hardware.

    • «Pin 34 su ESP32 non funziona per ZC»: GPIO 34–39 su ESP32 sono solo ingresso — supportano gli interrupt. Ma non hanno pull-up/pull-down interno. Aggiungi una resistenza esterna da 10 kΩ a 3,3V.

    • «Funziona senza carico, si rompe con carico collegato»: Il rumore elettrico dal carico (specialmente motori, trasformatori) si accoppia nella linea ZC. Separa fisicamente i cavi di potenza e segnale.




    Controllo rapido

    Prima di pubblicare sul forum, verifica:

  • ☐ Arduino: pin ZC — solo 2 o 3 (Uno/Nano). Gli altri non funzionano.
  • ☐ Il VCC è fornito al circuito ZC del dimmer?
  • ☐ Il pin ZC è fisicamente collegato alla scheda (non solo DIM)?
  • ☐ Contatore di passaggi per lo zero in 1 secondo: ~100 (50 Hz) o ~120 (60 Hz)?
  • ☐ Contatore `>200`? Rumore — aggiungi antirimbalzo o filtro RC.
  • ☐ Modalità di interrupt: `RISING` o `FALLING` per il tuo circuito?
  • ☐ ESP32: stai usando `rbdimmerESP32`, non la vecchia `RBDdimmer`?


  • Tabella di compatibilità dei pin di interrupt

    Scheda Pin con supporto interrupt Nota
    Arduino Uno 2, 3 Solo questi due
    Arduino Nano 2, 3 Solo questi due
    Arduino Mega 2, 3, 18, 19, 20, 21 Sei pin
    ESP32 Tutti i GPIO (0–39) Tranne riservati
    ESP8266 Tutti i GPIO tranne GPIO 16 Consigliati 4,5,12,13,14 (no boot)
    Raspberry Pi Tutti i GPIO (via pigpio) Nessun tempo reale — preferire DimmerLink



    Problemi correlati

    • ESP32 + dimmer AC: Guru Meditation Errortroubleshooting/esp32-iram-attr.md
    • Sfarfallio LED con dimmerload-types/led-flicker-triac-dimmer.md
    • Il dimmer non regola i LEDload-types/led-lamp-compatibility-triac.md



    Hai ancora domande?

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

    Condividi articolo
    Accedi per lasciare un commento