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:
- Pin sbagliato (non supporta gli interrupt) — errore più comune su Arduino
- Cablaggio ZC errato — il segnale non raggiunge il pin
- Modalità di interrupt sbagliata (
FALLINGinvece diRISINGo viceversa — dipende dal circuito) - Rumore — molteplici scatti falsi in un semiciclo
- 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:
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:
// 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.
// 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 esisteSu ESP32 — qualsiasi GPIO supporta gli interrupt:
// 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:
// 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:
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 digitaleChecklist:
Passo 4: Verificare la modalità di interrupt (RISING/FALLING/CHANGE)
La modalità dipende dal circuito rilevatore ZC del tuo modulo specifico:
// 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:
// 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:
// 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
// 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 sempredigitalPinToInterrupt(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:
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 Error →
troubleshooting/esp32-iram-attr.md - Sfarfallio LED con dimmer →
load-types/led-flicker-triac-dimmer.md - Il dimmer non regola i LED →
load-types/led-lamp-compatibility-triac.md
Hai ancora domande?
Ask on forum.rbdimmer.com or open a GitHub Issue.