Introduction: 3 Channel Dimmer/fader for Arduino or Other Microcontroller

Picture of 3 Channel Dimmer/fader for Arduino or Other Microcontroller

In an earlier instructable I presented a simple AC TRIAC fader/dimmer that could be controlled with an Arduino. In various reactions I got, a number of people expressed their interest in a 3 channel RGB fader. But since I have not seen any results of those yet. I decided to try myself. I was actually triggered (no pun intended by coming across the T1M5F600 TRIAC (LiteOn) that was quite cheap (0.20 eurocents) and was specified as 1A 600V with a 5mA gate current. It is in a TO92 housing and 1A seems quite enough to switch a coloured lamp who usually dont have a high Wattage to begin with.

For the dimmer
3x 470 Ohm resistor
3x MOC3021 (or other type without zero crossing)
3x T1MF5F600 Triac
1x header 4 or 5 pin
4x connector
(and of course a red, blue and green lamp)

For the zero-crossing detection
2x 33kOhm resistor
1x10k resistor
1x IL251 bidirectional OptoCoupler or similar like EL814, LTV814


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!

The circuit is quite standard. It consists of 3 Triac's that are triggered via a MOC3021. One can use other Triac optocouplers as long as they do not have an inbuilt zero-cross network as we want o decide ourselves when to open the triac.

The circuit that does the zero cross detection is kept quite simple: A bidirectional opto-coupler is fed with 220V AC where the two 33k resistors cause current limitation and a voltage drop. To be on the safe side Both resistors should be 1 Watt. It is possible to use highly sensitive optocouplers and thus limit the current needed and with that limit the dissipation in the resistors (e.g. by using a 4N33), but I do not know any of those that are also bidirectional. So if you'd want to use those, you would also need a bridge rectifier. See my other article: Arduino controlled lightdimmer

It is also possible of course to get the zero-crossing signal from the secundary side of a transformer.

Step 1: 3 Channel Dimmer/fader for Arduino or Other Microcontroller: the PCB

The PCB houses the 3 dimming circuits as well as the Zero cross detection. A PCB design is provided for direct toner transfer. The stocking of the PCB is quite straightforward. Note that the Triac, the M5F600 is in a TO92 case and the pin layout is different from most other Triacs in the TO220 casing.

Note that the IL250 should be mounted with its notch pointing down, whereas the other opto-couplers should be mounted with the notch pointing up

Step 2: 3 Channel Dimmer/fader for Arduino or Other Microcontroller: Software

This is just for demonstration or testing purpose.

As this program is just to illustrate, the loop cycles between 0 and 127..

 AC Light Control
 Ryan McLaughlin <>
 with slight modifications

#include <TimerOne.h>           //
#define PINS 3
volatile int pinCount[PINS];    // make volatile to make available in interrupt
volatile boolean zero_cross=0;  // Boolean to store a "switch" to tell us if we have crossed zero
int AC_pins[] = {3,4,5};        // Stup the pin numbers
int AC_dim[PINS];               // Holds Dimming levels (0-128)  0 = on, 128 = 0ff
int freqStep = 78;              // Set the delay for the frequency of power (65 for 60Hz, 78 for 50Hz) per step (using 128 steps)
                                // freqStep may need some adjustment depending on your power the formula 
                                // you need to us is (500000/AC_freq)/NumSteps = freqStep
void setup() {
  for(int a=0; a < PINS; a++) { //set the pins to output
   pinCount[a] = 0;             // keeps track of the time in the cycle 
   AC_dim[a] = 0;               // dimming level set to zero
  attachInterrupt(0, zero_cross_detect, FALLING);  // Attach Interrupt to Pin 2 (interrupt 0) for Zero Cross Detection
  Timer1.initialize(freqStep);                     // Initialize TimerOne library for the freq we need
  Timer1.attachInterrupt(dim_check, freqStep);     // Use the TimerOne Library to attach an interrupt
                                                   // to the function we use to check to see if it is 
                                                   // the right time to fire the triac.  This function 
                                                   // will now run every freqStep in microseconds.                                            

void zero_cross_detect() {        // function to be fired at the zero crossing                           
   zero_cross = 1;                // set flag to tell dimming function zero cross has occured
}                                 // End zero_cross_detect

void dim_check() {                   // Function will fire the triac at the proper time
 if(zero_cross == 1) {               // First check to make sure the zero-cross has happened else do nothing
   for(int a=0; a < PINS; a++) {
     if(pinCount[a] >= AC_dim[a]) {       // Check and see if i has reached the dimming value we want
       digitalWrite(AC_pins[a], HIGH);    // Fire the Triac 
       delayMicroseconds(5);              // Pause briefly to ensure the triac turned on
       digitalWrite(AC_pins[a], LOW);     // Turn off the Triac gate (Triac will turn off at the next zero cross)
       pinCount[a] = 0;                   // Reset the accumulator
       zero_cross = 0;                    // Reset the zero_cross so it may be turned on again at the next zero_cross_detect    
     } else {
       pinCount[a]++;                     // If the dimming value has not been reached, incriment the counter

void loop() {
  // This is simply making all outputs cycle through bright-dark, out of time with each other.
 for(int i=0; i<127; i ++) {
   for(int a=0; a < PINS; a++) {
      int ii = i+42;               //this is the bit that puts the blinking lights out of sync with one another
      if(ii > 127) ii -= 127;
      AC_dim[a] = ii;

Step 3: 3 Channel Dimmer/fader: Tips for Software

though it may seem a bit daunting to develop software for a 3-channel dimmer, it is not so hard as long as you keep focussed on the essentials the software needs to do:
-Wait for the zerocross interrupt to happen.
-Wait a set time before tiggering the TRIAC
-Trigger the TRIAC

For 3 channels that is not much different, you just have to keep track of 3 time variables. You can do that with "delays" but that is rather complicated. You can do that with "micros" and keep checking the 3 time variables against the time passed since the zerocross. Finally, you can do it with a timer interrupt.

The way timer interrupts are normally used if you are dimming one channel, is to set the interrupt for the desired time and when the interrupt occurs to trigger the TRIAC. With 3 channels that is impossible because you do not have 3 timer interrupts.

A better way is to set the timer interrupt to occur for 78uS. That divides the period of a 50Hz grid frequency in 128 steps (remember the re are 2 zerocrossings per 50Hz period, so you have in fact a 100 Hz signal, thus 10mS to do the work in before the next zerocrossing interrupt. 10mS/128=78.125uS). For 60Hz a value of 65 would be good.
You then let the timer interrupt service routine set a counter that in fact counts the number of 78uS steps that have passed since the zerocrossing interrupt occurred.
Your 3 time variables -each for every channel- are expressed in a level between 0 and 128. In the main loop check those against the counter set by your timer interrupt and when it is at the desired level.... ignite the corresponding TRIAC.

If you have no idea how to set timer interrupts, check this article.


adillbeck (author)2017-11-07

I can't seem to find the M5F600 TRIAC anywhere... Is this one similar?
It's a TO-92, 600V, 1A. I'll be using it with 110V AC (American) current. Thanks!

diy_bloke (author)adillbeck2017-11-08

apologies for my late reply. I was indisposed for a few days.
I had chosen the M5F600 Triac mainly because small, cheap and a sensitive gate but I am not stuck on it. The BT136 u link to seems to have rather similar specs though I am not entirely sure abut the gate sensitivity, but I am quite sure it will work.
Mind you though that a TO92 cant handle really big currents like the TO220.
For full current you mey need some form of heatsink, which is always a bit trickier with a TO92

diy_bloke (author)diy_bloke2017-11-08

Sorry, BT131, typo

adillbeck (author)diy_bloke2017-11-09

Thanks for the reply. I'll be using it with smaller currents, at least this time, just to have a way to dim a couple table lamps.

Am I right in assuming that I can make this into a two channel if I just leave the blue circuit part off? Or turn it into a 4 channel if I add another one?
I'll probably keep it at 3, but I'm curious how modular this could end up being?

I have worked with mains power and relays before but not TRIACS or optocouplers, so I'm going to be doing a lot of studying to make sure I do it right.

I couldn't get any IL251 or EL814 unless I wanted 1000 of them, so I went with the LTV814.

I'm pretty excited for my component order to show up.

diy_bloke (author)adillbeck2017-11-09

yes you can leave any of the channels off, or add a channel. The max number I tried was 6, that is gonna be a bit tricky to keep delay time, but it is possible.
the LTV814 is a fine chip. used it on many occasions. Just remember it is not pin compatible to the il251, but I think it is fully compatibel with the EL814.

I know the excitement :-)
But realize that the programming is a bit demanding as you likely have to keep a separate timer (millis() is fine) for each channel, unless you are using steady ligthing patterns

adillbeck (author)diy_bloke2017-11-11

Got my components, and built one channel of the circuit. I'm a little curious... does it matter which main terminal on the BT131 I wire the load up to?

I tried wiring it up one way and nothing happened, so I tried it the other way, and nothing happened, and then I figured out I had a wire loose, and once I fixed that it worked fine. I'm just curious if it would have worked the first way or not.

Also, I tried one of these dimmable LED bulbs first:

And it did dim, but it buzzed and hummed if it wasn't at full power.

Then I tried a normal incandescent bulb that I happened to still have laying around, and it worked fine with no buzzing.
I'm curious if there are any tricks I can try to get the LED bulb to work without buzzing, since it's kind of hard to find incandescent bulbs nowadays.

I'll upload a picture once I get the second channel wired and clean it up a little.

diy_bloke (author)adillbeck2017-11-12

as afar as I know it makes no difference. after all it is in series with the load.
I am happy you worked out the problem with the loose wire :-)
Dimmable lEDs are not always that easy to dim without special dimmers. At least yours showed some response. Incandescents are still the best companion for TRIACS

adillbeck (author)diy_bloke2017-11-10

The one part of the diagram that I'm a little hazy on ATM is the il251 (or LTV814 in my case). I have the datasheet for the 814, so I think I can figure out a lot of it. On the right side of the wiring diagram where the 33K resisters are pins 1 and 2, and that will be wired to the 110VAC lines to set the timing of the zero points so that the power can be managed to dim the light.
But on the left side of the il251 you have three lines, One is +Vcc, one is 0-Xing, and the last is ground.
If I'm reading the program correctly, 0-Xing is connected to pin 2 (interrupt 0), and of course ground is connected to the common ground, and I think +Vcc would be connected to the 5v on the ardunino with a 10k resistor?

So on the LTV814 the collector (LTV814 pin 4) would be connected to both 5V(10kR) and pin 2 (interrupt 0), and the emitter (LTV814 pin 3) would be connected to ground. When the AC cycle hits zero, Interrupt 0 will be pulled high, and when the new cycle starts it'll be pulled low again and interrupt the program.

Hopefully I have that all correct, but if not let me know where I'm confused.

mayurr14 (author)2017-09-25

sir ,can you give me the bridge number...

diy_bloke (author)mayurr142017-09-26

The one I used is the DF02, that is 400 V 1 A but basically any 400 Volt with appropriate current will do

mayurr14 (author)diy_bloke2017-10-02

Thank you sir for your help.i successfully do this project and it is in working condition .If i want change the bulb timing than which kind of change i which line in program.

diy_bloke (author)mayurr142017-10-03

Mayurr I am happy you got it working. The supplied program ofcourse is only a demo program. I keep the dimming values in the Array AC_dim[PINS];
Whether in your final setup that is the best to do completely depends on your program

mayurr14 (author)2017-09-25

sir ,can you give me the bridge number...

diy_bloke (author)mayurr142017-09-25

400V, the amperage depends on your load

mayurr14 (author)2017-09-24

sorry sir ,but i can not understand bridge connection or the link that yiu sen .i am 1st year student and i thimk i do this is big think for me .i complte whole cicuit but i do not have IL251 so my project was incopmlate .if you want to help me than tell me thhat insatnt of IL251 hoe to replace EL812 with proper diagram or picture. this is my last try sir......

diy_bloke (author)mayurr142017-09-24

I am not sure how i can make it clearer: the 3 channel dimmer has 2
resistors coming from the grid, going ro the the IL251. You want to use
an EL812 so you need a bridge in between the 2 resistors and the EL812.
In the picture you see exactly how to do that.
Look at the two resistors, the bridge and the optocoupler, ignore the rest.
see 2 resistors, they go to the AC connectors of the bridge, the + and -
of the bridge then go to the optocoupler which in your case is the
EL812. The 400V you were asking about is the spec of the bridge. I think the picture I sent is a proper circuit, but as you are a first year student I now have spelled it out on a resend of that picure.
As I said before, I start to get really worried about you building this as you sem to have trouble understanding circuits, can I again draw your attention to my warning at the beginning of this instructable. If you are not sure about what you are doing I would strongly advise you not to build this. It is connected to the grid and that carries a lethal voltage

mayurr14 (author)2017-09-24

sir,the picture(link) you send is not clean so i can't this EL812 is used?.what is 400 v? and with MOC3021 there is one diode?

if you give me the answer than i continue this please HELP me.....

diy_bloke (author)mayurr142017-09-24

look at how the bridge is connected to the resistors and optocoupler. That is what you need to do. ignore the rest

mayurr14 (author)2017-09-21


diy_bloke (author)mayurr142017-09-21

what problem, other than what i replied to already?

mayurr14 (author)diy_bloke2017-09-22

Sir I need bridge connection of EL812

diy_bloke (author)mayurr142017-09-24

click on the link i sent earlier and do it like that

mayurr14 (author)2017-09-21

sir in your code i have this kind of error message .can you help me..''C:\Users\Abc\Desktop\mr\mr.ino:7:80: fatal error: TimerOne.h: No such file or directory

#include <TimerOne.h> //


compilation terminated.

exit status 1

Error compiling for board Arduino/Genuino Uno.''

diy_bloke (author)mayurr142017-09-21

That is an easy one: install TimerOne library

mayurr14 (author)diy_bloke2017-09-21

Sir can you help me to connect EL812 in bridge circuit .So that can be use instant of IL 251

diy_bloke (author)mayurr142017-09-24

yes, do it as in the picture I sent

diy_bloke (author)mayurr142017-09-21

Do it like this

Having said that, I am starting to worry a bit, yuo seem to have very limited knowledge of electronics, seem to have no real knowledge of the arduino. No problem with that, we all have to learn, but this is a project carrying high voltages that could kill you. Are you sure this is a project you want to build?

mayurr14 (author)2017-09-19

can we replace IL251 with EL817

diy_bloke (author)mayurr142017-09-20

The EL817 is a single phase optocoupler and the IL251 a double phase. You can use the EL817 but then you have to ad a bridge rectifier

mayurr14 (author)2017-09-17

Code and arduino connection

diy_bloke (author)mayurr142017-09-18


diy_bloke (author)mayurr142017-09-17

I understand you are anxious to make this project but really no need to ask the same question several times in a row

mayurr14 (author)2017-09-16


diy_bloke (author)mayurr142017-09-16

Mayur tha is actually all stated in the program:
Connect the 0-x-ing with Pin D2 (interrupt 0)
and the R G B inputs to pin D3 D4 and D5

mayurr14 (author)diy_bloke2017-09-17

Please sir send me the complete code and arduino connection s

diy_bloke (author)mayurr142017-09-17

There is really no need to repeat your question 4-5 times

mayurr14 (author)diy_bloke2017-09-16

Sir ,i don't understand the D1 D2 D3 .If you have any other diagram with arduino pin connection than please send me .And also send me program for this project . Please help me ....

diy_bloke (author)mayurr142017-09-17

Your Arduino has in and output pins referred to as D0-D13

D3, D4, D5 are the ones you need, not 1-3. They are on your Arduino board
There is no need to send you a program, the program is in the instructable in step 2 where it says 'Software'

Attached an image of the arduino with a great big red arrow pointing to digital I/O D3-D5
D2 is where you connect your interrupt.
This is really very very basic arduino information

Hmm seems I cannot upload an immage right now.
here is the link:

Go to the lower right hand side of the board where its says 'Digital pins' There you see 0-13

mayurr14 (author)2017-09-17

Please sir send me the codw

mayurr14 (author)2017-09-16


John BryanI (author)2016-09-11

Hi! Disclaimer: I am a new with arduino and these kind of things. I would like to ask how would I be able to control dimming easier with these? I am working on a project where I will be dimming an incandescent bulb, an AC motor, and a water heater. However, the dimming values will be dictated by the arduino using conditions that I will set (using fuzzy logic) and with the reading of my temperature and humidity sensor. I am already a bit familiar with PWM dimming and I find its codes more understandable than interrupt so I'm hoping to make the codes a bit similar to that. Also, will the interrupt affect the countdown timer I will be using as a background function? How can I make each channel work independently of the others? Sorry for the questions if it seems so much. I just really need help understanding these things. Thank you!

diy_bloke (author)John BryanI2016-09-12

You are partly right. Indeed the software is more complicated than for instance with PWM, but the channels do work independent from eachother (but not independent from the interrupt).
If you use this circuit you will have to deal with interrupts.... or you need to frequently poll the zerocross pin, but that is less reliable.

if you want to stick to PWM........ you can use my pwm dimmer. However that is only suitable for DC devices, so it is going to be difficult for an AC motor.
in that instructable however I discuss a circuit by Ton Giesberts, that as far as I know can be used for AC, but in my opinion is not as ideal (for DC) as my circuit.
So you could decide to build my PWM circuit for your incandescent bulbs and Giesberts circuit for your motor. What your heater needs I am not sure

John BryanI (author)diy_bloke2016-09-12

Thank you so much for the response! :)

I think the heater runs with the same concept as the incandescent bulb since the bulb lights up by heating the filament inside.

Can Giesbert's circuit handle the motor if it will be running continuously for 24 hours for several days? Same question for your PWM dimmer. The device I will be building should run 24 hours for 21-30 days straight. Thank you!

diy_bloke (author)John BryanI2016-09-13

My dimmer cannot handle any ac motor as it is DC.
Whether Giesbert's circuit can depends largely on the demands the motor is having. What is the wattage of the motor?

John BryanI (author)diy_bloke2016-09-13

sorry for the misinformation. the motor is just a blower fan type, around 40W

diy_bloke (author)John BryanI2016-09-14

then giesbert's circuit should have no problems with it

NattawutK2 (author)2016-04-02

Hi! I have a problem. i use your code with 220VAC 50Hz, then the lamp always blink. What should i do to make it smoother.

diy_bloke (author)NattawutK22016-04-02

is it just on one lamp or on all 3?

NattawutK2 (author)diy_bloke2016-04-02

On all lamp.

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:Working With the Funduino W5100 Ethernet Module.Uploading Data to ThingSpeak With MQTTAdding an MCP23017 I/O Extender to Arduino or ESP8266
Add instructable to: