3 Channel Dimmer/fader for Arduino or Other Microcontroller





Introduction: 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 <ryanjmclaughlin@gmail.com>
 with slight modifications

#include <TimerOne.h>           // http://www.arduino.cc/playground/Code/Timer1
#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.


  • Done ! with some ada...-garrettx

    garrettx made it!


  • Epilog Challenge 9

    Epilog Challenge 9
  • First Time Author Contest 2018

    First Time Author Contest 2018
  • Sew Warm Contest 2018

    Sew Warm Contest 2018

We have a be nice policy.
Please be positive and constructive.




I wanted to build the same for 4 channel dim circuit. With push button to increase and decrease dim levels. Please post code for 4 channel dimmer with push buttons.

kumaran, maybe you misunderstand the concept of instructables.
I publish things I make and am more than willing to answer any questions.
However, I am not a free coder for your specific wishes to make what in fact is a different project
I am sure you are able to do it yourself. Should you want me to do it I will need to charge you for my time.
I will give u a few pointers though:
set up a timer that interrupts say every 10usec
Check the dim values of your 4 channels against the accumulated timer interrupts and if match, ignite the triac.
set the dim values with yr up and down buttons

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

Sorry, BT131, typo

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.

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

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.

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

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.