Dimmerare una lampadina ad incandescenza 220v usando Arduino



ATTENZIONE, 220 Vac, PERICOLO DI MORTE: in questo articolo si descrivono circuiti elettrici che vengono collegati alla corrente elettrica alternata a 220 volt, c'è rischio di MORTE se riprodotti ed usati da persone poco esperte o se operanti senza criteri di sicurezza. Si declina ogni responsabilità.
(vedi disclaimer di questo blog)

Purtroppo non è possibile creare un variatore di luce ad icandescenza 220v AC usando semplicemente l'uscita pwm di Arduino che piloti un triac con onde quadre variando la frequenza delle stesse.

Se si facesse questo tentativo si otterrebbe un continuo sfarfallio della luce della lampadina da un minimo ad un massimo di intensità luminosa, perché per avere una emissione costante di luce è necessario che l'impulso che pilota il triac sia sincronizzato con il momento in cui l'onda dell'alternata passa attraverso lo zero.

Se si vuole capire il funzionamento si devono fare alcune considerazioni di base base del sistema di dimming in alternata.

Nota bene 1: la corrente alternata (in Italia) ha una frequenza di 50 Hz, quindi passa attraverso lo zero 2 volte ogni 0,02" (1"/50Hz=0,020") e quindi 1 volta ogni 10 millisecondi (ms).

Nota bene 2: il triac quando viene eccitato rimane in conduzione, anche se si toglie l'eccitazione sul gate, fino al successivo passaggio della sinusoide attraverso lo zero.

Questo significa che se si vuole variare la luminosità della lampadina, si dovrà eccitare il triac ogni decimillesimo di secondo, ma soprattutto vuol dire che per ridurre la luminosità della lampadina si dovrà attendere un certo tempo (successivo al passaggio dell'onda attraverso lo zero) prima di eccitare il triac, che sarà inversamente proporzionale al tempo di accensione della lampadina... ad esempio, se si vuole che il diming sia minimo si dovranno attendere circa 9 ms prima di eccitare il gate del triac, dopodiché quest'ultimo condurrà per 1 ms (9+1=10 ms) fino al successivo passaggio dell'onda attraverso lo zero. E così ogni 10 ms. Se questo concetto non è ben chiaro ripartire dal punto "Nota bene 1" e procedere con calma guardando le figure...

Passiamo al progetto.

Passo 1
Per prima cosa è necessario costruire un sensore da collegare ad Arduino che intercetti l'onda sinusoidale della corrente alternata 220 nel momento in cui transita attraverso il punto zero.
Il seguente schema è funzionante:
L'alternata passa ora nel primo ora nel secondo fotoaccoppiatore attraverso i piedini 1 e 2, mandando in conduzione alternativamente i piedini 4 e 5. I piedini 3 e 6 non devono essere usati.
Il tutto può essere messo in una scatola con un po' di aerazione per raffreddare le resistenze da 2 Watt:

Passo 2
E' necessaria anche una interfaccia tra l'uscita di Arduino e la lampadina ad incandescenza.

Il seguente schema è funzionante:

Notare che il MOC3020 non é un optoisolato zero crossing ma random. E' importante controllare che l'optoisolato non sia zero crossing perché, se lo fosse, non farebbe funzionare il dimmeraggio sempre per le questioni riportate ai punti "Nota bene 1" e "2", perché è compito dell'Arduino rilevare il punto di passaggio dallo zero!
La resistenza da 820 è regolata per l'alimentazione a +5 volt, se dovesse essere alimentata con 3,3 volt ridurla a 39 Ohm

Passo 3
Lo sketch di Arduino:
l'ho testato su un Arduino Mega;
premendo una volta la luce si accende dimmerata
premendo un'altra volta la luce si spegne dimmerata
tenendo premuto la luce aumenta fino al massimo poi diminuisce fino al minimo, si ferma al rilascio del pulsante



int T0 = 0;
int T1 = 0;
int ST0 = 0;
int ST1 = 0;
int var = 8900; //valore in mcsec attesa accensione triac, più è basso più sta acceso
int inc = 50;
int Luce = 0;
int PrintSer = 0;
int accendi = 0;
int spegni = 0;
int my_time = 0;
int my_time2 = 0;
int my_main_time = millis();
int my_main_delay = 10;
int my_var_time = 0;
int my_var_delay = 1000;
int my_timer = 0;
int tmp = 0;

//###################################################################################################
void setup() {
  attachInterrupt(0, zero_cross_detect, CHANGE); // interrupt pin 0, controlla zero cross
  pinMode(10, OUTPUT);                           // output verso opto isolante
  pinMode(3, INPUT);                             // input verso il pulsante in pull up
  Serial.begin(9600);                            // Inizializzazione seriale per debug
}
//###################################################################################################
void loop() {
  my_time = millis();
  my_time2 = my_timer;
 if(my_time>my_main_time+my_main_delay){
   Fn_Pulsante();
 }
}
//###################################################################################################

//---------------------------------------------------------------------------------------------------
void zero_cross_detect() {
  if(var <= 8900 && var >= 1100){
  delayMicroseconds(var/2);                        // attende mcsec var (che può essere da 1000 a 9000)
      tone(10, 500, 1);
  }
    my_timer = my_timer + 1; // incremento questo timer perchè millis() non è regolare negli interrupts
    if(my_timer > 10000){
      my_timer = 0;
    }
}
//---------------------------------------------------------------------------------------------------
  void Fn_Accendi(){
  accendi = 1;
  var = var - inc;
  if(var < 1100){
    var = 1100;
    Luce = 1;
    accendi = 0;
    T1 = 0;
    T0 = 0;
  }
  }
//---------------------------------------------------------------------------------------------------
  void Fn_Spegni(){
    spegni = 1;
  var = var + inc;
  if(var > 8900){
    var = 8900;
    Luce = 0;
    spegni = 0;
    T1 = 0;
    T0 = 0;
  }
  }
  //---------------------------------------------------------------------------------------------------
  void Fn_Pulsante(){
  if(digitalRead(3) == LOW){                     // se viene premuto il pulsante...
    if(ST0==0){
      T0 = my_timer;
      ST0 = 1;
      ST1 = 0;
    }
      var = var - inc;                              // aumenta il valore var

    PrintSer = 1;
    }
  if(digitalRead(3) == HIGH){
    if(ST1==0){
    T1 = my_timer;
    ST1 = 1;
    ST0 = 0;
    }
    if(PrintSer==1){
    Serial.print("var = ");
    Serial.print(var);
    Serial.print("     T0 = ");
    Serial.print(T0);
    Serial.print("     T1 = ");
    Serial.print(T1);
    Serial.print("     T1 - T0 = ");
    Serial.println(T1 - T0);
    PrintSer = 0;
    }
    if((T1 - T0 > 5 && T1 - T0 < 200) || (10000 - (T0 + T1) > 5 && 10000 - (T0 + T1) < 200) || accendi == 1 || spegni == 1){
      if(Luce == 0){
        Fn_Accendi();
      }else if(Luce == 1){
        Fn_Spegni();
      }
    }
  }

    
    if(var > 8900){                             // se var = 9000 mcsec... (luminosità minima)
      var = 8900;                                // reimposta var a 1000 mcsec (luminosità massima)
      inc = -inc;
    }
    if(var < 1100){                             // se var = 9000 mcsec... (luminosità minima)
      var = 1100;                              // reimposta var a 1000 mcsec (luminosità massima)
      inc = -inc;
    }
    my_main_time = millis();
  }




Passo 4
Collegare Arduino:
  • l'uscita del sensore del passo 1 passaggio attraverso lo zero va collegato al pin 2 di Arduino (interrupt 0)
  • il pin 10 di Arduino va collegato all'optoisolante dell'interfaccia del passo 2
  • al pin 3 si deve collegare il pulsante di pilotaggio con resistenza in configurazione "pull up"
Purtroppo non è possibile pilotare più di una lampada con un singolo arduino...


Ciao. Carlo. 

[keywords: dimmeraggio dimmare dimmerare diming variatore variare 220 arduino]


24 commenti:

  1. Scusa l'ignoranza ma per interfaccia del passo due ti riferisci al pin 1 dell'optoisolante ?

    RispondiElimina
    Risposte
    1. Nel passo 2 con "interfaccia" intendo tutto il circuitino che è disegnato nella figura (che è diverso da quello del sensore zero crossing, è un'altra interfaccia) , dove i pin 2 e 3 dell'optoisolato MOC3020 (l'integrato nella parte superiore della figura) vanno collegati al pin 10 di arduino dicahiarato nel void loop() dello sketch (previo led e resistenza in serie), mentre il pin 1 dell'optoisolato va collegato ad un pin "+ 5 volt" di Arduino.
      A valle dell'optoisolato c'è il triac BTA16 600B che si occupa di pilotare la lampada ad incandescenza (sarebbe bene mettere un fusibile da 2A in serie).
      Interfaccia molto semplice, ma efficace.
      N.B. a monte dell'optoisolato circolano 5 volt corrente continua, a valle la 220 volt corrente alternata!
      Spero di avere capito la domanda e di essere stato chiaro. Ciao.

      Elimina
    2. Errata corrige della risposta: ...dichiarato nel void setup().. [non ...dichiarato nel void loop()...]

      Elimina
  2. Ciao Carlo, ho fatto varie ricerche su internet prima di arrivare alla pagina del tuo blog, io non possiedo Arduino, ma vorrei fare questa cosa e dimmerare una lampadina con Flyport Wifi della Openpicus, non so se lo conosci, se no, ti dico che é come un Arduino in miniatura, ma monta a bordo un PIC24 e un transceiver wifi tutto nelle dimensioni di 3x4 cm circa... lo possiedo giá da circa 6 mesi e ci ho fatto vari esperimenti, te lo consiglio vivamente, é un prodotto molto interessante, molto piú potente di qualsiasi Arduino, anche se ha meno IN/OUT... e fa tutto quello che potresti fare con un Arduino + la WiFi Shield, compreso WebServer. Vorrei chiederti un consiglio... uello che sto cercando di fare io é mettere Flyport dentro una normale scatoletta a muro e comandarlo dal PC o smartphone Android (sviluppo apps anche con basic4android) Per ora sono riuscito a comandare le uscite di Flyport sia da Apps da me scritte che anche da Browser. Mettendo un relé potrei giá comandare una lampasina o cmq un carico 220v, ma io voglio mettere pure uno slider e appunto dimmerare una lampadina. Per il SW non dovrebbe esseci problema inquanto anche Flyport si programma in C e quindi mi basterebbe adattare leggermente il tuo codice.... Flyport é alimentato a 3.3v. Secondo tele resistenze da 2 watt scaldano troppo per poterle mettere dentro una scatoletta a muto, quelle dove ci sono le prrese e interruttori per intenderci? Ho letto che i Triac aggiungono molti disturbi alla rete e sui nuovi contatori ENEL digitali creano molti problemi, tu che ne pensi? Ciao e grazie Massimo

    RispondiElimina
    Risposte
    1. Ciao Massimo, ho fatto qualche prova.
      Le resistenze da 2W che sono lato 220 scaldano circa 45-48°C se lasciate libere all'esterno della scatola.
      La temperatura delle resistenze sale a 50-53°C se alloggiate nella scatolina che ho postato in figura (con i forellini di aerazione aperti).
      Chiudendo i fori di aerazione la temperatura è salita attorno ai 61-62°C.
      Il tutto con una temperatura ambientale attorno ai 21°C. Bisogna considerare che d'estate le temperature aumentano.
      Il volume di quella scatolina è approssimativamente pari alla metà di quello della scatolina 503 da muro (quindi nella 503 c'è più spazio).
      Secondo me, però, siamo un pò al limite.
      Per ridurre la temperatura (ed il consumo) penso che sarebbe meglio sostituire ognuna delle due resistenze da 2W, con un condensatore più una resistenza in serie, come approssimativamente un condensatore da 330K pF (0,33 μF) 630v e una resistenza da 220 ohm 1/2W, ma bisogna fare bene i calcoli controllando il datasheet del optoisolato 4N35.
      Per quanto riguarda il disturbo del triac immesso in rete (ho anch'io il contatore elettronico) posso dirti che, per quanto riguarda la mia esperienza, non ho mai notato problemi nonostante abbia, fin dal 2002, tutte le luci di casa (circa 15 punti luce) dimmate con circuiti sostanzialmente identici a quello che ho postato, ed anche le valvole di riscaldamento (più di una decina) pilotate da triac.
      Fammi sapere gli sviluppi. Ciao. ;-)

      Elimina
    2. Ciao Carlo, grazie per i test effettuati e le dritte... la cosa mi interessa molto e l'ho in testa da parecchio tempo, ma devo aspettare ancora un po di tempo quando un signore mio amico che si occupa di impiantistica avrá un attimo per darmi una mano. Io mi intendo un po di elettronica ma mai avuto a che fare (tranne la costruzione di un alimentatore) con la corrente di rete, quindi preferisco aspettare. Siccome apprezzo il tuo grande interesse vorrei fare in modo di aiutarti anche io. A tal proposito ti chiedo se hai dei devices Android e se vorresti comandare con questi o con un PC la tua casa domotica anche se ti trovi fuori casa, intendo da qualsiasi parte del mondo. Mi spiego meglio, ho scritto un'app che fa questo: si istalla su un device Android aggiuntivo (qualsiasi va bene basta che ha wifi) il quale va lasciato a casa collegato al caricabatterie e mediante router anchesso lasciato acceso fa una richiesta HTTP nella rete ogni minuto per prelevare l'indirizzo IP Pubblico che ti ha assegnato in quel momento il tuo gestore e se questo cambia ti invia una mail con il nuovo IP. In questo modo, ovunque ti trovi (se 6 coperto da wifi) ti arriva una notifica con il nuovo IP e se lo utilizzi in varie apps di controllo, puoi usare queste apps allo stesso modo come se fossi a casa tua potendo accedere alla tua rete privata (LAN). Come saprai l'indirizzo IP assegnato dal gestore cambia ogni volta che spegni/riaccendi o riavvii il router, a volte anche mentre il router é acceso, se ad esempio c'e un calo di tensione e va via la corrente, la mia app si accorge che il router si è spento (manca la rete) attende che ritorni la corrente e quando ritorna e il router si riavvia, notifica via mail il nuovo IP. Ovvio che per controllare apparecchiature con Arduino bisogna avere la Wifi Shield che riceve comandi dalla rete, si possono scrivere applicazioni adhoc oppure poi se si implementa con Arduino un WebServer si possono anche vedere le sue pagine su qualsiasi Browser ed interagire con esse e un sistema domotico anche dall'esterno. Se puó interessarti la mia app fammi sapere l'indirizzo mail del cell dove vorresti essere avvisato se l'IP Pubblico cambia, io poi lo inseriró nella mia app e dopo averla compilata te la invio. Mi piacerebbe potessi provarla, l'ho scritta per inviare dati musicali (midi) via internet ma mi piacerebbe vederne un uso nella Domotica. Fammi sapere. Ciao. Massimo

      Elimina
    3. Ti ringrazio molto, ma ho già un account su no-ip che viene aggiornato da Arduino e che mi fa appunto il servizio di tenersi sincronizzato con il mio IP dinamico. E' comunque una idea interessante quella di spedire l'IP ad un indirizzo mail, complimenti. Non sentirti in debito, sono felice che il mio piccolo articolo ti sia stato di aiuto e di spunto. Ciao, Carlo.

      Elimina
    4. Ciao, complimenti per il progetto, volevo commentare due questioni:
      1 usare i condensatori al posto delle resistenze è molto meglio per i consumi ed il riscaldamento ma secondo me introduce uno sfasamento ed un ritardo nella lettura dello zero che deve essere precisa. Che ne pensate?
      2 Teoricamente è possibile comandare più lampade occorre però non utilizzare delaymicros() (che blocca tutti i processi) ma continuare a fare confronti con l'orologio interno di arduino con la funzione micros(). Se avro tempo proverò a modificare lo sketch. Saluti Daniele.

      Elimina
    5. Grazie Daniele.
      1) Per i condensatori è possibile che ci sia un ritardo, forse si può compensare via software.
      2) Penso anch'io che sostituendo il delaymicros() si possa tentare di far fare qualcosaltro ad arduino nei millisecondi di attesa.
      Se hai tempo di modificare lo sketch e di fare qualche prova fammi sapere che sono interessato.
      Purtroppo io in questo periodo non ci riesco per l'accavallarsi di troppi impegni.
      Ciao.

      Elimina
  3. Ciao, prima di tutto grazie per l'ottima guida.
    Ti chiedo se la limitazione consista nel gestire una sola lampadina (o motore?), questo perché si usa un interrupt?
    Grazie ancora.

    RispondiElimina
    Risposte
    1. Veramente non lo ricordo più.
      Mi sembra che l'avessi scritto perchè c'era un problema di "tempo" di impegno del programma in qualche istruzione.
      Riguardando il listato, mi pare che dipenda dal fatto che nel void zero_cross_detect() la delayMicroseconds(var/2) fermi il programma per i microsecondi necessari per attendere di mandare in chiusura l'uscita, e questo ogni 10 millisecondi, quindi, con questo sistema non ci sarebbe il tempo di gestire una seconda uscita.
      Si potrebbe ragionare se, con un sistema di simulazione multitasking, sostituendo il delayMicroseconds, possano essere gestite una o più uscite. Bisogna provare, ma la vedo dura.
      Ciao.

      Elimina
  4. Questo commento è stato eliminato dall'autore.

    RispondiElimina
  5. Ciao, per prima cosa complimenti per il tutorial, poi volevo chiedere se fosse possibile utilizzare due pulsanti invece che uno, uno per aumentare e l'altro per diminuire.
    Vorrei variare la velocità di una pompa per acquario in modo da modificarne la portata di acqua.

    Grazie

    RispondiElimina
    Risposte
    1. Certo, è possibile, bisogna dichiarare in "void setup()"
      ad esempio "pinMode(4, input);" per collegare un pulsante in più nel pin 4 di Arduino, e nella funzione "void Fn_Pulsante()" aggiungere "if(digitalRead(4) == LOW){" e fargli modificare la variabile var al contrario: "var = var + inc;" poi bisogna eliminare le righe che richiamano le funzioni accendi e spegni che, mi pare, non servirebbero più.
      Questo è più o meno il dafarsi, però non riesco a postarti un listato esatto e completo, perché in questo periodo non ho la possibilità di fare esperimenti per mancanza di tempo. Ciao.

      Elimina
  6. Scusami ma al passo 4 "l'uscita del sensore del passo 1 passaggio attraverso lo zero va collegato al pin 0 di Arduino" non deve essere il pin 2 che gestisce l'interrupt 0 ? Ciao

    RispondiElimina
    Risposte
    1. Direi che hai ragione, mi sono evidentemente sbagliato. Provvedo a correggere. Grazie!

      Elimina
  7. Ciao,
    è possibile usare l'arduino 2009 o, è necessario il mega.

    "void setup() {
    attachInterrupt(0, zero_cross_detect, CHANGE); // interrupt pin 0, controlla zero cross"

    scondo quanto sopra l'interrupt è gestito dal pin 0, cosa centra il pin 2 ?

    RispondiElimina
  8. adesso ci sono, lo zero si riferisce all'interrupt. tutto chiaro.

    RispondiElimina
  9. salve!ottimo articolo......
    questo circuito potrebbe pilotare una pompa per acquario?
    Grazie

    RispondiElimina
    Risposte
    1. Ciao Sandro e grazie.
      Credo che con i motori "sincroni", come generalmente sono quelli per acquario, non funzioni perché diminuisce solo la potenza ma non la velocità di rotazione.
      Carlo.

      Elimina
  10. Ciao Carlo,
    Perdona la domanda banale, ma il condensatore da 33nanFarad esattamente a cosa serve?
    Grazie
    Michele

    RispondiElimina
    Risposte
    1. Siamo a valle del fotoaccoppiatore, sul versante 220 v alternata, qui viene sfruttata la reattanza capacitativa del condensatore per limitare la corrente che passa attraverso la resistenza da 180 Ohm.
      Ciao!

      Elimina
  11. ciao ho realizzato il progetto e funziona perfettamente al primo colpo, mi è servito per testare una unità zero crossing e triac , grazie mille sei stato davvero molto utile.

    RispondiElimina