Picture of Arduino controlled light dimmer

WARNING: Some people try to build this with an optocoupler with zerocrossing coz 'that is better' right? Some are even told in electronics shops it is better to use such an optocoupler. WRONG. This will only work with a random fire optocoupler: NOT igniting at zerocrossing is the principle of this dimmer.

Switching an AC load with an Arduino is rather simpel: either a mechanical relay or a solid state relay with an optically isolated Triac. (I say Arduino, but if you use an 8051 or PIC16F877A microcontroller, there is stuff for you too here.)

It becomes a bit more tricky if one wants to dim a mains AC lamp with an arduino: just limiting the current through e.g. a transistor is not really possible due to the large power the transistor then will need to dissipate, resulting in much heat and it is also not efficient from an energy use point of view.

Phase cutting
One way of doing it is through phase control with a Triac: the Triac then is fully opened, but only during a part of the sinus AC wave. This is called leading edge cutting.
One could let an Arduino just open the Triac for a number of microseconds, but that has the problem that it is unpredictable during what part of the sinus wave the triac opens and therefore the dimming level is unpredictable. One needs a reference point in the sinus wave.
For that a zero crossing detector is necessary. This is a circuit that tells the Arduino (or another micro controller) when the sinus-wave goes through zero and therefore gives a defined point on that sinus wave.
Opening the Triac after a number of microseconds delay starting from the zero crossing therefore gives a predictable level of dimming.

Pulse Skip Modulation
Another way of doing this is by Pulse Skip Modulation. With PSM, one or more full cycles (sinuswaves) are transferred to the load and then one or more cycles are not. Though effective, it is not a good way to dim lights as there is a chance for flickering. Though it might be tempting, in PSM one should always allow a full sinuswave to be passed to the load, not a half sinus as in that case the load will be fed factually from DC which is not a good thing for most AC loads. The difference between leading edge cutting and PSM is mainly in the software: in both cases one will need a circuit that detects the zero crossing and that can control a triac.

A circuit that can do this is easy to build: The zero crossing is directly derived from the rectified mains AC lines – via an optocoupler of course- and gives a signal every time the wave goes through zero. Because the sine wave first goes through double phased rectification, the zero-crossing signal is given regardless whether the sinus wave goes up through zero or down through zero. This signal then can be used to trigger an interrupt in the Arduino.

It goes without saying that there needs to be a galvanic separation between the Arduino side of things and anything connected to the mains. For those who do not understand 'galvanic separation' it means 'no metal connections' thus ---> opto-couplers. BUT, if you do not understand 'galvanic separation', maybe you should not build this.

The circuit pictured here does just that. The mains 220Volt voltage is led through two 30k resistors to a bridge rectifier that gives a double phased rectified signal to a 4N25 opto-coupler. The LED in this opto-coupler thus goes low with a frequency of 100Hz and the signal on the collector is going high with a frequency of 100Hz, in line with the sinusoid wave on the mains net. The signal of the 4N25 is fed to an interrupt pin in the Arduino (or other microprocessor). The interrupt routine feeds a signal of a specific length to one of the I/O pins. The I/O pin signal goes back to our circuit and opens the LED and a MOC3021, that triggers the Opto-Thyristor briefly. The LED in series with the MOC3021 indicates if there is any current going through the MOC3021. Mind you though that in dimming operation that light will not be very visible because it is very short lasting. Should you chose to use the triac switch for continuous use, the LED will light up clearly.

Mind you that only regular incandescent lamps are truly suitable for dimming. It will work with a halogen lamp as well, but it will shorten the life span of the halogen lamp. It will not work with any cfl lamps, unless they are specifically stated to be suited for a dimmer. The same goes for LED lamps

If you are interested in an AC dimmer such as this but you do not want to try building it yourself, there is a somewhat similar dimmer available at, however, that is a 110 Volt 60Hz version (but adaptable for 220 50Hz), that has been out of stock for a while. You will also find a schedule here.

NOTE! It is possible that depending on the LED that is used, the steering signal just does not cut it and you may end up with a lamp that just flickers rather than being smoothly regulated. Replacing the LED with a wire bridge will cure that. The LED is not really necessary. increase the 220 ohm resistor to 470 then

STOP: This circuit is attached to a 110-220 Voltage. Do not build this if you are not confident about what you are doing. Unplug it before coming even close to the PCB. The cooling plate of the Triac is attached to the mains. Do not touch it while in operation. Put it in a proper enclosure/container.

WAIT: Let me just add a stronger warning here: This circuit is safe if it is built and implemented only by people who know what they are doing. If you have no clue or if you are doubting about what you do, chances are you are going to be DEAD!

4N25 €0.25 or H11AA1 or IL250, IL251, IL252, LTV814 (see text in the next step)
Resistor 10k €0.10
bridge rectifier 400 Volt €0.30
2x 30 k resistor 1/2 Watt (resistors will probably dissipate 400mW max each €0.30
1 connector €0.20
5.1 Volt zenerdiode (optional)

Lamp driver
LED (Note: you can replace the LED with a wire bridge as the LED may sometimes cause the lamp to flicker rather than to regulate smoothly)
MOC3021 If you chose another type, make sure it has NO zero-crossing detection, I can't stress this enough DO NOT use e.g. a MOC3042
Resistor 220 Ohm €0.10 (I actually used a 330 Ohm and that worked fine)
Resistor 470 Ohm-1k (I ended up using a 560 Ohm and that worked well)
TRIAC TIC206 €1.20 or BR136 €0.50
1 connector €0.20

Piece of PCB 6x3cm
electric wiring

That is about €3 in parts

Remove these adsRemove these ads by Signing Up
1-40 of 468Next »
Murphi6 days ago

Hi, after reading several times the post I decided to do it, but I have two questions..

-For make the pcb, we must print at paper something like this:

But I don´t see in fritzing this option..I select the PCB tab in the soft and I see this:

If I print, it prints as the second capture, no? What I have to do to see tracks in black ?? Sorry, but it´s first time that I use Fritzing...

-The triac that I have is BTA12-600 BW (12a and up to 800v), and I guess it works fine, right??

Thanks and regards

diy_bloke (author)  Murphi6 days ago

Go to 'File-Export-As Image-pdf'
Then just print that pdf on some glossy paper.
depending on your settings you may get more than 1 pdf: for the coppertracks, for the silkscreen etc. Pick the one that is right. as the ink layer is put on the copper, make sure it is the one that is mirrorred. THAT IS USUALLY NOT THE ONE THAT IS CALLED 'MIRRORRED'
Th epicture you showed is just the component lay-out
BTA12-600 is fine

Ok, thanks for your advice..In fritzing I select "maximum" for width..

I will make the circuit tomorrow and the print monday or tuesday (I don´t have laser printer and the correct paper..)

Thank you for your support and regards.

diy_bloke (author)  Murphi5 days ago

good luck

diy_bloke (author)  Murphi6 days ago

just a final piece of advice: the standard coppertracks in Fritzing are a bit narrow. Make them wider by selecting a larger track width

Where do you connect the zero-crossing pin in arduino
diy_bloke (author)  Tanishq Jaiswal9 days ago

that depends on the interrupt you want to use, but the example program I provided it should be attached to D2

muhammad8612 days ago

Hi DIY bloke.Thanks becoz it works and furthermore it works with a LED lamp(the dimmable one).However i realised that the i value should be from i=10 to i=120 for incandescent light. It should not go to i=128 becoz it will ficker at i=128.Somewhere from i=120 to i=125 should be a good point to end. Please correct me if i am wrong.This is what i observed.

diy_bloke (author)  muhammad8612 days ago

That is good to hear. You are lucky on the LED lamp as some work and some do no.
With regard to the lowest and higehst values, yes, because the zerocross detection is not an ideal narrow pulse and the period length of the grid may vary, choosing extreme values like <5 or >125 may give some flickering.
If you have time, add a picture in the 'I made it' section. I always like to see how peoples makes turn out

MuratE113 days ago

can you show me links to Arduino?

diy_bloke (author)  MuratE113 days ago

u asked this also in a pm. i replied there

choucsou14 days ago


Thanks for this tutorial.

You have two AC wires on input and two "AC" wires on output.

What if we try to deal with one only on each side ? This mean the light will be in serial with the dimmer. And that the zero crossing signal will be read on the "corrected" AC (by the triac).

So the triac and the lamp are in serial and the zero crossing detection is on the triac in parallel.

Do you think it could work ?

Please have a look at

You install it in serial with the lamp. The third wire is for command


diy_bloke (author)  choucsou13 days ago

sure that works. after all it is just a switch.

but.............. the zerocross signal needs to get input from both terminals onthe grid

MuratE113 days ago

can you show me links to Arduino?

MuratE113 days ago

can you show me links to Arduino?

andre663517 days ago


What is the maximum load power(W) for the bulb? Would it work with 2 or 3 incandescent bulbs connected in parallel in which all the bulbs would dim at the same time?

diy_bloke (author)  andre663517 days ago

The maximumload depends on the TRIAC. The TIC 206 can handle 4 amps RMS, so if you are using it 2ith 220 Volt, the max load is 880 Watt.
You can put as many incandescent bulbs in parallel as you like, as long as the total load does not exceed 880 Watts.
So 2 or 3 lamps of say 100 Watt is no problem at all

Thanks for the info. I will also add a radiator for the triac just to keep it safe.

Today I started to make holes in the PCB. I was using a 1 mm bit, and it seems large to me. Should I use an 0.8 mm bit? I also have an 0.6 mm one but I think it is too small for some holes. What drill bit sizes have you used? I tried to see in Fritzing the hole size, but I didn't found this option.

diy_bloke (author)  andre663515 days ago

I think I used 0.8

diy_bloke (author)  diy_bloke17 days ago


muhammad8617 days ago

hi the ground is it common ground for the neutral wire and arduino ground?

diy_bloke (author)  muhammad8616 days ago

No please never connect those. See my earlier reply

Hi thanks just needed to confirm.I kind of realised it when i saw the neutral wire not being connected to common ground on your diagram.Anyway i found out my MOC3052 is spoilt.I don know why maybe becoz i connected to common ground.

Also i realised that the optotriac and triac is not able to take huge voltages(240V).Is it ok to increase the resistance of the resistor connected to the optotriac(right now u only put 1k)? and is it ok to connect a resistor to the MT2 terminal of the triac, T1(CONNECTED directly to mains supply) .

diy_bloke (author)  muhammad8616 days ago

Muhammed, I do not have much experience with the 3052 but it should be able to take 600 volts on its output leads.
The TIC206 should be able to work with a 1k gate resistor. In fact I am using a 560 Ohm resistor.
I am not sure why or where you exactly want to connect the resistor to M2 to. Yes, M2, but leading where?
The circuit as I supplied is proven to work many times so I am not sure why you would want to change it.

Hi thanks just needed to confirm.I kind of realised it when i saw the neutral wire not being connected to common ground on your diagram.Anyway i found out my MOC3052 is spoilt.I don know why maybe becoz i connected to common ground.

Also i realised that the optotriac and triac is not able to take huge voltages(240V).Is it ok to increase the resistance of the resistor connected to the optotriac(right now u only put 1k)? and is it ok to connect a resistor to the MT2 terminal of the triac, T1(CONNECTED directly to mains supply) .

muhammad8616 days ago

Oh man my comment also went off.

Hi DIY_bloke,Is the ground from arduino and the neutral wire connected as a common ground or do you SEPARATE them?

diy_bloke (author)  muhammad8616 days ago

indeed sometimes I have to press 'make comment' twice. If I dont pay attention, the comment gets lost.


the optocoplers are there to completely isolate the arduino from the mains voltage.
Please reread everything I wrote in bold as well as what I write about galvanic isolation.

At best you will blow up yr Arduino but at worst you will be toast!!

Hi DiY_Bloke, I made both the circuits according to your given diagrams. zero-crossing works fine and the dimmer input generated by arduino is totally fine. when i fire triac without any delay the bulb is on. But when we fire triac after 1 ms delay the bulb doesnt get on and the output voltage is dropped to zero and all the voltage appears accross triac. So we are only able to fire triac without delay. But when delay of 1 ms or greater is introduced the circuit doesnt work.
Kindly help us!!
we are using BT136 and Moc3021.
the pulse width to triac for latch is set to 600us.
If u say we can also show you output waveforms.
thank you

diy_bloke (author)  Arslan Waheed22 days ago

there is something very wrong with instructables as i replied almost immediately and now i cant see my reply. Anyway, it is a very odd problem you describe.
It kinda makes me nervous that you talk about two circuits that you built, coz it is in reality only one circuit, but i presume you mean the zerocrossing section and the trigger section.
the strange thing is that you should be able to ignite yr triac at practically every moment in the cycle, so also at 1mS after the zero cross.
Which software are u using? Have you tried my program that cycles through a number of levels??

What i like you to try is to disrefard tge zerocrossing for a while and just make the input on the optocoupler high and low a few times randomly, to make sure the triac does ignite at random moments.
Please let me know how that goes and make sure you also try the first program i provided

Harry021 month ago

Hi DiY_Bloke

I have made it work, it is really great I had found this I had made few mod on to the PCB, I add a fuse and separated the two AC input/Output to the PCB sides (so I had to print my PCB using two sides)

I have tested the SW and it also works! :) tested the inmojo sample and also works (I'm based on the UK) but I'm trying to send the dimming value via serial, and I cant make it work, (the Sample III here, did not work either) , do you have any advise as I need to send the dimming value via serial

Thank you

diy_bloke (author)  Harry021 month ago

Well let me start by saying I am happy you made it :-)
It seems to be one of my most popular designs :-)
I always appreciate hearing about builds and if you like, post a picture with the 'I made it' option :-)
Anyway as your module works, your problem must be in the software. In principe you need to send a number to the Serial port that is then read and used as 'dim value'
You say you used Sample III but I presume you mean Sample II. Anyway, now I look at it more diligently (it isnt my code), I wonder how that could work as the 'light' procedure, that checks the serial port, isnt called anywhere.
You need to call that from your 'loop' or even use it as the 'loop'.
Let me know if that works

yes, I had tested it too, I had added the light() onto the loop, and it just keep flickering and no actual dimming occurs

I'm a bit confused, as I had tested the same without the loop, as this works as the interruption will call the serial and the light() function is executed, but again I try to add a value via serial and its not taken

int AC_pin = 3;//Pin to OptoTriac

int dim = 0; //Initial brightness level from 0 to 255, change as you like!

void setup() {


pinMode(AC_pin, OUTPUT);

attachInterrupt(0, light, FALLING);//When arduino Pin 2 is FALLING from HIGH to LOW, run light procedure!


void light() {

if (Serial.available()) {

dim =;

if (dim < 1) {

//Turn TRIAC completely OFF if dim is 0

digitalWrite(AC_pin, LOW);

Serial.println ("im low");


if (dim > 254) { //Turn TRIAC completely ON if dim is 255

digitalWrite(AC_pin, HIGH);

Serial.println ("im High");



if (dim > 2 && dim < 254) {

//Dimming part, if dim is not 0 and not 255


digitalWrite(AC_pin, HIGH);


digitalWrite(AC_pin, LOW);

Serial.write (dim);




void loop() {


ebjorno1 month ago
Are you able to sell me one for £10?
diy_bloke (author)  ebjorno1 month ago

I haven't really considered that till now, but I have no idea how much it would cost to send it to UK.. Also.. how much in a hurry are you?

I'm going to use it to control some lights for a film production. Can you find a price that you're happy with and email me at I'm not in a hurry, but would appreciate if you could send it within a week or so. Thanks!

Little bit confusing on the PCB printed what was up and what down or which pin is actually connected. But with that solver nice work

diy_bloke (author)  ralf.vandenburg1 month ago

I am glad u like it ralf.
With regard to the pin connections: in Step 1 there is a picture with clear indication what is what:

but maybe it is easy to overlook that one. I am happy though u figured it out.enjoy

oh i forgot to mention that i also liked the detail explaination of the matter you gave well done.

i've encountered a really weird issue only i used the components you descibed and after a few hours of operations time it seems the TRIAC (TIC206 4A ) is leaking current. I've used the diagnostics you're suggested. Also the fritzing file uses a 1Kohm resistor while in the picture 3 (right bellow) on step 1 suggests a 560 Ohms resistor.

(I've build this part 3 times and it happend all 3 times, so I suppose i got something wrong here)

diy_bloke (author)  ralf.vandenburg1 month ago

Hmm With regard to the resistor, I explained that in the text (BOM) one can use a 470Ohm-1k and I ended up using a 560 Ohm.
With regard to your other problem: why you think it is leaking current? Because it will not shut off?
Did you build it on a PCB or on a breadboard?
using for incandescent lamps or other devices?
Did you put any snubbers on it?
I have build it several times and actually never had any problems with it. I have had fresh from the shop faulty Triacs or Thyristors before, but that is really an incident and if it happened with all 3 circuits you built that would be unlikely.
Anyway, let me know and maybe we can find out what the problem is.

I've build it upon a test PCB, used the lamp on the photo attached. The board has the Zero cross detector in the center and the white pieces are the MOC3021. I think the TRIAC is leaking because the octocoupler is still functioning when i put a +5V the lamp is fully on but when off the lamp burns dimmed. Also i've had the demo program working the lamp goes slowly off only after a few hours it wouldn't go off it remains dimmed on.



Hope you could give any suggestions

1-40 of 468Next »