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.

PWM dimming
PWM dimming, as in LEDs is not done frequently with AC loads for a number of reasons. It is possible though. Check this instructable to see how.

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 www.inmojo.com, 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

Step 1: Arduino controlled light dimmer: The PCB

You will find two pictures for the PCB: my first one, that I leave here for documentation purposes and a slightly altered new one. The difference is that I left out the zenerdiode as it is not really necessary and I gave the LED itś own (1k) resistor: it is no longer in series with the Optocoupler, that now has a 470 Ohm resistor. I made the PCB via direct toner transfer and then etched it in a hydrochloric acid/Hydrogenperoxide bath. There are plenty of instructables telling how to do that. You can use the attached print design to do the same. Populating the print is quite straightforward. I used IC feet for the opto-couplers and the bridge rectifier.
Download the print here.
Note: You need Fritzing for this. For the direct toner transfer, the printed side of the printed pdf file, goes directly against the copper layer for transfer. Once it is transferred, you will be looking at the ink from the other side and thus see the text normal again. I made slight alterations in thePCB: I removed the zenerdiode and the LED is no longer in series with the optocoupler.

I used a TIC206. That can deliver 4 amperes. Keep in mind though that the copper tracks of the PCB will not be able to withstand 4 Amperes. For any serious load, solder a piece of copper installation wire on the tracks leading from the TRIAC to the connectors and on the track between the two connectors.

In case it is not clear what the inputs are: from top to bottom on the second picture:
Interrupt signal (going to D2 on arduino)
Triac signal (coming from D3 on Arduino)

If you have an H11AA1or IL 250, 251 or 252 opto-coupler then you do not need the bridge rectifier. These have two anti-parellel diodes and thus can handle AC. It is pin compatible with the 4N25, just pop it in and solder 2 wire-bridges between R5 and + and R7 and -. The LTV814 is not pincompatible


<p>Sorry, I have deleted the post by mistake.</p><p>I have put 2 Serial.Print in the code, one is inside &quot;<em>void zero_crosss_int()</em>&quot; function and the other in &quot;<em>for (int i=5; i &lt;= 128; i++)</em>&quot; loop, so when im plugged to 220v 50hz, I only get the Serial.print from zero cross function, and when im unplugged only the one in for loop. I think this is correct because is detecting zero crossing right?. But the bulb is always OFF. </p><p>The only difference in my circuit is that im using KBP210G bridge and BT137600E transistor, I have checked optocoupler pins 4 &amp; 5 and im getting 4.98v also all the juntions &amp; routes are ok. </p><p>Im feeding the circuit with vcc pin from arduino pro mini.</p><p>Any idea of what im messing up?</p><p><br>Thanks for your help!</p>
<p>as you deleted your post, I am not sure anymore what your original problem was.<br>Can I ask why you put the serial print in your interrupt?<br>Should keep the interrupt as short and slim as possible. Your serial print may be screwing up your interrupt, meaning a new interrupt is already generated before it gets out of your interrupt.<br><br>If you then unplug your mains conection, you are not getting any interrupt anymore so the program stays in its loop.<br>Contray to what you say it doesnt stay in its loop because it is detecting zerocross, it stays in its loop because it is NOT detecting zerocross, yoou have unplugged it<br><br></p>
<p>Hi, thanks for you great explanations, sorry for my english but my mother tongue is spanish, I have a question please, I implement the code above and only have two states, ON and OFF although the variables dim, dim2 and dim2 change when i press de buttons, in dim = 128 de lamp is off and and any other value of dim diferentes to 128, turns ON the lamp. Finally when the lamp is OFF whit dim=128, after a while the lamp starts blink, I apreciate a lot youy help, I hope you can answeer me question, thanks.</p>
<p>Seems you are using something else than the demoprogram :-) OK first things first: what happens if you load my demoprogram. Does that work properly? </p>
First, thanks for answer my question, second Yes, when I use the demo program works properly, makes the loop from 0 to 128. Whit the demo program I try to send individual values makes a multiplication between 65 (because in my country works wirh 110V 60Hz) and dimming values but doesn't work, because the lamp turn on totally with each value. Finally I used another program that works with the buttons to up or down the dimming level, which caused my doubt.
<p>ok so the hardware works. That means the problem is in your program. I cant say anything on that without seeing your program</p>
<p>Hi, now the program works, but I did a lot of tests and I have the following results:</p><p>1) With dimming=5; -&gt; the lamp is totalilly ON max poer</p><p>2) from dimming=10 to dimming=109 tthe lamp is lowering its brightness</p><p>3) In dimming=110, the lap starts flashing</p><p>4) from dimming=111 to dimming=118 the lap is on its minimum power</p><p>5) in dimming= 119 the lap increase its power again </p><p>6) in dimming=128 the lamps starts a buccle form max power to low power </p><p>7) in dimming=127, dimming=126, dimming=125 the lamp is on its max power again</p><p>In conclusion:</p><p>1) For values over dimming=110 the performance of the dimmer I don't understand</p><p>2) with dimming= 60 and over the zero cross circuit emits a beep, i think that is normally because i have in my room a normal dimmer that i bought in a store</p><p> Thanks very much, I appreciate your help</p><p>The code I am using:</p><p>int AC_LOAD = 3; // Output to Opto Triac pin</p><p>int dimming = 128; // Dimming level (0-128) 0 = ON, 128 = OFF</p><p>void setup()</p><p>{</p><p> pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output</p><p> attachInterrupt(0, zero_crosss_int, RISING); // Choose the zero cross interrupt # from the table above</p><p>}</p><p>//the interrupt function must take no parameters and return nothing</p><p>void zero_crosss_int() //function to be fired at the zero crossing to dim the light</p><p>{</p><p> // Firing angle calculation : 1 full 50Hz wave =1/50=20ms </p><p> // Every zerocrossing thus: (50Hz)-&gt; 10ms (1/2 Cycle) </p><p> // For 60Hz =&gt; 8.33ms (10.000/120)</p><p> // 10ms=10000us</p><p> // (10000us - 10us) / 128 = 75 (Approx) For 60Hz =&gt;65</p><p> int dimtime = (65*dimming); // For 60Hz =&gt;65 </p><p> delayMicroseconds(dimtime); // Wait till firing the TRIAC </p><p> digitalWrite(AC_LOAD, HIGH); // Fire the TRIAC</p><p> delayMicroseconds(10); // triac On propogation delay </p><p> // (for 60Hz use 8.33) Some Triacs need a longer period</p><p> digitalWrite(AC_LOAD, LOW); // No longer trigger the TRIAC (the next zero crossing will swith it off) TRIAC</p><p>}</p><p>void loop() {</p><p> dimming=30;</p><p> delay(10);</p><p>}</p>
<p>It all suggest that somewhere your timing is off, but before I go any deeper, explain this to me:<br>&quot;2) with dimming= 60 and over the zero cross circuit emits a beep, i <br>think that is normally because i have in my room a normal dimmer that i<br> bought in a store&quot;<br><br>What element produces the beep and what does a store bought dimmer have to do with your problem?</p>
I'm using the zero cross circuit that you propouse in this blog, the dimmer that I have in my room is analog, of those standing on the wall, I think that the triac emits the beep or the lamp I'm not really shure.
<p>TRIACS dont emit beeps</p><p>Not sure what you mean with analog dimmer, but if you are using a store bought dimmer in this circuit I am ot surprised you have problems. <br>1 how do you control it from yr arduino? (i.e. where do the wires go?)<br>2 how do you need to control it? (the dimtime values may mean nothing to yr dimmer)<br>3 can you control it? (maybe it isnt designed to be controlled from a microcontroller)</p>
<p>Sorry, As I said my English is not very good, forget about the analog dimmers, I'm not using that dimmer in the circuit, I think I caused confusion. I'm using de zero cross circuit and de dimmer circuit propouse of you in this blog, sorry again for the confusion</p>
<p>is ok. I was already wondering what a commercial dimmer had to do with it. So that beep that you brought up... from which circuit is that coming?</p>
The beep comes from the light bulb
<p>that surprises me coz lightbulbs generally dont beep.</p><p>Anyway, I might have become sidetracked from your original problem. Is that solved now?</p>
The problem persists, you told me: &quot;It all suggest that somewhere your timing is off...&quot;. I appreciate your help.
<p>OK. I get many questions so sometimes if iot is a bit prolonged I may lose track what the initial problem was.<br>So we can state that the demo program is working, which means that your hardware is working. However when you send an individual value you run into problems.<br>The program you are using is exactly the same as the demo program that is working for you, except for that you replaced <br></p><p>for (int i=5; i &lt;= 128; i++){<br> dimming=i;<br> delay(10);<br> }</p><p> with </p><p> dimming=30;</p><p> delay(10);<br><br>As you can appreciate that is extremely odd as the value 30 and in fact any of the other values that you tried all come along in the loop that actually IS working for you.<br>Additionally, you have a beeping lamp<br>I must say this is all very unlogical. Must oversee something<br>So here is what I like you to do:<br>Load the original demo program again and make sure that indeed works and that the lamp doesnt beep</p><p>then change </p><p>for (int i=5; i &lt;= 128; i++){<br>into</p><p>for (int i=20; i &lt;= 100; i++){<br>and see what that does.<br>If that works narrow the gap to say 30-40 and tell me what that does</p>
<p>OK, my last question: how do you calculate the 30 Ohm? Motorola's 4n25 takes 60mW / 3V and I have the impression that 47 Ohm is better suited for 230V. Am I wrong?</p>
<p>I am not sure what 30 ohm you are referring to</p>
<p>Sorry. On the mains input you have two 30 *Kilo*Ohm resistors. How do you calculate this value? </p>
<p>pls dont overlook my prior reply to this question, but I just wanted to add a bit more. Ideally the resistor value should be as small as possible so the width of the zerocross signal is as small as possible. However, that would lead to a rather high powerdissipation in the resistors.<br>The 4n25 doesnt have 60mW dissipation as you write but max 120mW. However that number is of secundary relevance as we really dont need 40mA to open the 4n25.<br>the rectified voltage of 230 V AC =207 Volt.<br>divided by 60k that gives abt 3.5mA which is enough. Going to 2x47k (not sure where you got that value) would give 2.2mA. That is pushing it a bit. Plus your zerocrosssignal would get wider, giving you timing problems</p>
<p>I think you made a calculation error here. </p><p>The peak to peak voltage after rectification will be 220*sqrt(2) = 311 Volts (not 207V).</p><p>For the purpose of calculating the current, however, you should use the 220V RMS value (because the resistors are on the AC side of the rectifier), so 220/60k = 3.67 mA which is still close to what you calculated, so in the end it does not matter very much.</p>
<p>Thanks. I always used to calculate with 1.4 and it is well possible that 3-4 years ago I used that value to calculate the resistor value based on 1.4x230V.But since then I was told (rectifieing basics on internet) that it should be the average voltage, which was supposed to be 0.9*230. I am not sure if that is true, but as you correctly state: In the end it doesnt matter very much.</p><p>Thanks :-)</p>
<p>by dividing the voltage by the current I wanted to flow.<br>This is a <br>compromise between wanting a decent current to open the phototransistor<br> and a current that wouldnt be too big with regard to the power <br>dissipation</p>
<p>Thank you all for such great projects. I have developed this project and it works all fine. But when I use a sensor with arduino, it gives no response. I think arduino is too much busy in tackling zero-crossings. Can anyone suggest anything about using multiple things with this power control using same arduino board.</p>
<p>seems like instructables is at it again. I answered yesterday, but I cant see my reply anymore. Also I saw you reacted again but cant find that reaction.<br>Anyway I will try again: you probably used the firts program, which is a demo program. It doesnt do much else but wait in a delay.<br>If you want your CPU to do something else, take the 2nd program that uses a timer interrupt to determine that phase cut and leaves the CPU free to do other things</p>
<p>Yet another question. As you write, the zero-crossing detection consumes ~800mW.</p><p>For a 365 days / 24h device that is a lot (thinking at the coal or uranium burnt for that). </p><p>So lets save energy: for the important dim-position &quot;switched off&quot; it might be reasonable to operate mains input by an optocoupler-driven relais that cuts this down to 0mW. Does this seem reasonable to you?</p>
<p>indeed it is a lot. A relay however also draws power, though probably not that much, but it is a needlessly complicated solution. Better try this then: </p><p><a href="http://www.3e-club.ru/files/2009-12-09/zero-cross/full1.jpg">http://www.3e-club.ru/files/2009-12-09/zero-cross/...</a></p>
How conet to adrui no
<p>thats all in the text. The zerocross signal goes to one of th einterrupt pins that you define in the software (if INT 0 it is pin 2) The trigger input comes from a digital pin that you can freely chose in the software</p>
Please code to email cowboyxuan@yahoo.com thank you<br>
<p>Hi diy_bloke,</p><p>thank you for this very nice and understandable tutorial. In the circuit diagram it is not absoluetely clear to me: you do well control the phase and not null?</p><p>I would like to drice an AC motor (for house ventilation) with it. But I am afraid that when switching off, the motor induces voltage that destroys the triac. How can I protect it for such use?</p>
<p>thank you for your kind words. I am not really sure what you mean in your first paragraph as there is no such thing as controlling the null or the phase, or at least i do not know exactly what you mean with it. Do you mean if it makes a difference where the neutral and live phase go when connecting to the grid? No not at all.</p><p>driving a fan is one of the most asked questions on this tutorial :-) Yes you can. Though a triac is far from optimal to drive an inductive load, in most cases it will work, but you need to include a snubber (resistor +capacitor)</p>
<p>Thank you for the quick answer. &quot;Null&quot; was the new language frenglish (mix or french and english:) I meant neutral phase of course, as you guessed. Although electrically it is unimportant where you switch, one would (at least in Europe) always switch live phase to avoid tension on the machine parts when beeing switched off. I am happy to hear that your circuit allows this. Remains the snubber, I will try to learn this. Thank you!</p>
<p>well as I connect it with a regular plug, without marking that plug it would be impossible to know if the phase (brown) and neutral (blue) connected to the 'right' wires.<br>If it is build in with a permanent connection yes i would interrupt the 'live' phase (brown wire). To make it correct, the interrupted wire to the load should be black :-)</p>
<p>is it possible use zero crossing to dim LED dimmable bulb ?? </p>
<p>yes.... if you have the proper dimmable leds. not all are suitable</p>
do you have any reccomendations ? have you try it before ?
<p>I never tried leds in combination with this circuit. As it seems you still have to buy the leds and still have to build the circuit, I would recommend you dont use this dimmer but get a dedicated led dimmer. If you still insist on using this dimmer, get a retrofit LED labelled to work with a 'traditional' dimmer.</p>
<p>I restructured the circuit a bit and omitted the LED. <a href="http://www.instructables.com/id/Intel-Edison-Controlled-AC-Dimmer/" rel="nofollow">Works great</a> using 120VAC!</p>
<p>Great work</p><p>The circuit can do very well without the LED and in all honesty when i designed <br>as such, I had a red led in mind, not realising people might use other <br>color leds and thus not leave enough voltage for the optocoupler.<br>If I<br> have two small remark on your circuit, like me you use 2x 33k resistors. <br>However you you use them with 110 Volt. That is not a huge problem and <br>obviously it is working for you but it makes the zerocrossing puls a <br>tadd wider. That means that people could possibly experience a bit of <br>timing problems when using short delays on the rising flank or long <br>delays on the falling flank.<br>Not saying that WILL happen, but there is a chance<br>The second remark is that I am not really a fan of having a copper trace pass through optocouplers that carry a high voltage. It will probably be ok but it is best to avoid it. One wire bridge would have solved that on yr PCB.<br><br>Nevertheless good work</p>
Thanks diy_bloke. What would you suggest for the two resistor values for an ideal zero-cross pulse at 120VAC?
<p>I would leave it as it is since it is working fine for you.<br>generally in order to get a sharp pulse the resistors have to be as small as possible, but still big enough to limit the max current through your optocoupler and not to dissipate too much power.<br>your optocoupler has a max forward current of 60mA. The max Voltage it gets is 115 Volt, so theoretically a 2.3k resistor would be possible. However this would generate 5.75 Watt of heat. 2 resistors of 15 k would be fine, but again, in your case i would leave it as is</p>
<p>It seems that even with a wider pulse, as long as the pulse starts at the same time each interval, it should be ok, right?</p><p>The MCU code that is driving it polls the zero-cross pin instead of having an interrupt so I'd hope the pulse width wouldn't be so small as to be skipped or undetected though I'm unsure the approximate time it takes to cycle the loop in a worst case scenario.</p>
<p>yes it starts at the same time but i will illustrate the 'problem' by a bit of exaggeration: at 60 Hz your period for dimming is 8.3mS. Suppose you a have a zerocrossing pulse that is 4mS wide (it isnt ofcourse) and it begins 2mS before the actual zerocrossing and ends 2 mS afterthe actual zerocrossing. That means that you cannot dim during the full period anymore.<br><br>Suppose you want your lamp to be fully ON, so you switch on the TRIAC immediately at the zerocrossing pulse. However, that is 2mS before the actual zerocross that will suddenly switch off your TRIAC, so instead of Full ON it is dimmed to almost zero</p>
<p>Is there any reason you couldn't account for that in code? Shouldn't matter if you're behind as long as it's on time in reference to when the triac turns off at zero cross, right? I did test the circuit with a multimeter and I'm able to get a pretty full range from 0-119+VAC so it works well in practice. I also like the idea of less power consumption and heat.</p>
<p>sure that is possible. if you know the width of your pulse can account for that. Say it is 200uSec, then you know your real zerocross is 100uS after the interrupt.</p><p>As you have a full range there is no need to change the resistors.</p><p>Minimizing the powerconsumption is very well possible. the simplest is to use a transformer, but then you will be introducing a hoist of otherproblems. You may want to try this: </p><p><a href="http://www.3e-club.ru/files/2009-12-09/zero-cross/full1.jpg">http://www.3e-club.ru/files/2009-12-09/zero-cross/...</a></p>
<p>Regarding power consumption, I was referring to the difference between 2.3k where more power is consumed emitted as heat and 33k where less power is consumed. As you said, there's no reason to fix it now since it ain't broke.</p>
<p>ah OK, I misunderstood. I thought that was a separate idea :-)<br>Indeed, if it aint broken dont fix it</p>
<p>Thank you for your tutorial! Now I am about to implement 8 channel dimmer... ;-) </p>
<p>looks great. good luck with the 8 channels. Thanks for sharing pics</p>

About This Instructable




Bio: I am a physician by trade. After a career in the pharmeceutical world I decided to take it a bit slower and do things I ... More »
More by diy_bloke:Building a Simple and cheap egg incubator Comparison of capacitive soil probes Send sensor data (DHT11 & BMP180) to ThingSpeak with an Arduino, using ENC28J60 Ethercard 
Add instructable to: