You are on page 1of 34

instructables

Arduino Controlled Light Dimmer

by diy_bloke

WAIT!! before you decide to build this, it is good sinus wave.


to know that a similar dimmer is available at For that a zero crossing detector is necessary. This is
Aliexpress at cost that is hard to beat (currently a circuit that tells the Arduino (or another micro
2.70 euro) controller) when the sinus-wave goes through zero
and therefore gives a defined point on that sinus
WARNING: Some people try to build this with an wave.
optocoupler with zerocrossing coz 'that is better' Opening the Triac after a number of microseconds
right? Some are even told in electronics shops it delay starting from the zero crossing therefore gives a
is better to use such an optocoupler. WRONG. predictable level of dimming.
This will only work with a random fire
optocoupler: NOT igniting at zerocrossing is the Pulse Skip Modulation
principle of this dimmer. 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
Switching an AC load with an Arduino is rather or more cycles are not. Though effective, it is not a
simpel: either a mechanical relay or a solid state relay good way to dim lights as there is a chance for
with an optically isolated Triac. (I say Arduino, but if flickering. Though it might be tempting, in PSM one
you use an 8051 or PIC16F877A microcontroller, should always allow a full sinuswave to be passed to
there is stuff for you too here.) 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
It becomes a bit more tricky if one wants to dim a most AC loads. The difference between leading edge
mains AC lamp with an arduino: just limiting the cutting and PSM is mainly in the software: in both
current through e.g. a transistor is not really possible cases one will need a circuit that detects the zero
due to the large power the transistor then will need to crossing and that can control a triac.
dissipate, resulting in much heat and it is also not
efficient from an energy use point of view. A circuit that can do this is easy to build: The zero
crossing is directly derived from the rectified mains
Phase cutting AC lines – via an optocoupler of course- and gives a
One way of doing it is through phase control with a signal every time the wave goes through zero.
Triac: the Triac then is fully opened, but only during a Because the sine wave first goes through double
part of the sinus AC wave. This is called leading edge phased rectification, the zero-crossing signal is given
cutting. regardless whether the sinus wave goes up through
One could let an Arduino just open the Triac for a zero or down through zero. This signal then can be
number of microseconds, but that has the problem used to trigger an interrupt in the Arduino.
that it is unpredictable during what part of the sinus
wave the triac opens and therefore the dimming level PWM dimming
is unpredictable. One needs a reference point in the PWM dimming, as in LEDs is not done frequently

Arduino Controlled Light Dimmer: Page 1


with AC loads for a number of reasons. It is possible coming even close to the PCB. The cooling plate of
though. Check this instructable to see how. the Triac is attached to the mains. Do not touch it
while in operation. Put it in a proper
It goes without saying that there needs to be a enclosure/container.
galvanic separation between the Arduino side of
things and anything connected to the mains. For WAIT: Let me just add a stronger warning here: This
those who do not understand 'galvanic separation' it circuit is safe if it is built and implemented only by
means 'no metal connections' thus ---> opto-couplers. people who know what they are doing. If you have no
BUT, if you do not understand 'galvanic separation', clue or if you are doubting about what you do,
maybe you should not build this. chances are you are going to be DEAD!DO NOT
TOUCH WHEN IT IS CONNECTED TO THE GRID
The circuit pictured here does just that. The mains
220Volt voltage is led through two 30k resistors to a Materials
bridge rectifier that gives a double phased rectified Zerocrossing
signal to a 4N25 opto-coupler. The LED in this opto- 4N25 €0.25 or H11AA1 or IL250, IL251, IL252,
coupler thus goes low with a frequency of 100Hz and LTV814 (see text in the next step)
the signal on the collector is going high with a Resistor 10k €0.10
frequency of 100Hz, in line with the sinusoid wave on bridge rectifier 400 Volt €0.30
the mains net. The signal of the 4N25 is fed to an 2x 30 k resistor 1/2 Watt (resistors will probably
interrupt pin in the Arduino (or other microprocessor). dissipate 400mW max each €0.30
The interrupt routine feeds a signal of a specific 1 connector €0.20
length to one of the I/O pins. The I/O pin signal goes 5.1 Volt zenerdiode (optional)
back to our circuit and opens the LED and a
MOC3021, that triggers the Opto-Thyristor briefly. Lamp driver
The LED in series with the MOC3021 indicates if LED (Note: you can replace the LED with a wire
there is any current going through the MOC3021. bridge as the LED may sometimes cause the lamp to
Mind you though that in dimming operation that light flicker rather than to regulate smoothly)
will not be very visible because it is very short lasting. MOC3021 If you chose another type, make sure it
Should you chose to use the triac switch for has NO zero-crossing detection, I can't stress this
continuous use, the LED will light up clearly. enough DO NOT use e.g. a MOC3042
Resistor 220 Ohm €0.10 (I actually used a 330 Ohm
Mind you that only regular incandescent lamps are and that worked fine)
truly suitable for dimming. It will work with a halogen Resistor 470 Ohm-1k (I ended up using a 560 Ohm
lamp as well, but it will shorten the life span of the and that worked well)
halogen lamp. It will not work with any cfl lamps, TRIAC TIC206 €1.20 or BR136 €0.50
unless they are specifically stated to be suited for a 1 connector €0.20
dimmer. The same goes for LED lamps
Other
NOTE! It is possible that depending on the LED that Piece of PCB 6x3cm
is used, the steering signal just does not cut it and electric wiring
you may end up with a lamp that just flickers rather
than being smoothly regulated. Replacing the LED That is about €3 in parts
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

Arduino Controlled Light Dimmer: Page 2


1. Vcc
Zero Xing Signal out
Dim Signal in
1 1 Ground
1. Vcc
Zero Xing Signal out
Dim Signal in
Ground

Arduino Controlled Light Dimmer: Page 3


Step 1: Arduino Controlled Light Dimmer: the PCB

You will find two pictures for the PCB: my first one, zenerdiode and the LED is no longer in series with
that I leave here for documentation purposes and a the optocoupler.
slightly altered new one. The difference is that I left
out the zenerdiode as it is not really necessary and I I used a TIC206. That can deliver 4 amperes. Keep in
gave the LED itś own (1k) resistor: it is no longer in mind though that the copper tracks of the PCB will
series with the Optocoupler, that now has a 470 Ohm not be able to withstand 4 Amperes. For any serious
resistor. I made the PCB via direct toner transfer and load, solder a piece of copper installation wire on the
then etched it in a hydrochloric tracks leading from the TRIAC to the connectors and
acid/Hydrogenperoxide bath. There are plenty of on the track between the two connectors.
instructables telling how to do that. You can use the
attached print design to do the same. Populating the In case it is not clear what the inputs are: from top to
print is quite straightforward. I used IC feet for the bottom on the second picture:
opto-couplers and the bridge rectifier. +5Volts
Download the print here. Interrupt signal (going to D2 on arduino)
Note: You need Fritzing for this. For the direct toner Triac signal (coming from D3 on Arduino)
transfer, the printed side of the printed pdf file, goes Ground
directly against the copper layer for transfer. Once it
is transferred, you will be looking at the ink from the NOTE:
other side and thus see the text normal again. I made If you have an H11AA1or IL 250, 251 or 252 opto-
slight alterations in thePCB: I removed the coupler then you do not need the bridge rectifier.

These have two anti-parellel diodes and thus can and R7 and -. The LTV814 is not pincompatible
handle AC. It is pin compatible with the 4N25, just
pop it in and solder 2 wire-bridges between R5 and +

1. AC in
2. Load

Arduino Controlled Light Dimmer: Page 4


Step 2: A Word on Inductive Loads: Theory

The presented circuit is suited for pure resistive loads It consists of an additional resistor and capacitor. The
such as incandescent lamps. gate current is below 15mA. If you are using a less
Should you want to use it for inductive loads, then a sensitive triac to control the inductive load, reduce the
snubber circuit is necessary. The figure shows the resistor from 2.4k to 1.2k , providing more current
modifications for use with Inductive loads. Mind you, to drive the triac and increase the capacitor to 200nF.
this is not something I tried as I just wanted to dim This snubber circuit is there to protect the triac from
lamps, but it is based on examples and theory the high voltage generated from an inductive load.
available on the internet. You would have to adapt the The feedback may cause some problem for non-
provided PCB inductive load. The small leakage can be significant
The top figure shows the circuit as is, for dimming a enough to turn on small load (for example a lamp).
lamp. It is in all its simplicity just a resistor to trigger
the gate via the diac in the optocoupler. The value of There are other snubber circuits, e.g. a resistor and
1k may be changed as discussed in the text before. capacitor in series directly over the load
The bottom figure gives an omnipresent circuit for use
in inductive loads.

Step 3: The Software, a Bit of Theory

If you could care less about the theory, but just want the software, go to the next step

The way to use an AC dimmer/fader is quite simple once you understand the basics:

In AC the power fed to the lamp is directly related to the total surface of the sinuswave, the lamp can be regulated
by only allowing a predictable part of that sinuswave to flow through the lamp.

Arduino Controlled Light Dimmer: Page 5


As such we need a reference point on that sinus from where we calculate when the lamp has to be switched on.

The easiest reference point to use is the so called 'zero crossing': the moment that the light goes through zero.
After each zero crossing there is one full half of the sinuswave available to send through the lamp.

So what the software needs to do is to detect the zerocrossing, and then wait for a set amount of time on that
sinuswave to switch on the TRIAC.

There are2 major grid frequencies

in the world: 50Hz in Europe and most of Asia and Africa and 60 Hz in the America's (and parts of the Caribean).
There are 2 major voltages in the world: 110-120V and 220-240V but they are not important for the mathematics
here

For ease of use I will take the 50Hz frequency as an example:


50Hz is 50 waves per second.
Each sinuswave thus takes 1000ms/50=20ms (miliseconds)
As there are 2 sinuspeaks in a wave that means that after every zero detection there is a 10ms period that we can
regulate.
Should we ignite the lamp directly at the beginning of that period, the lamp will receive full power, should we do it
at the end of that 10ms period the lamp will receive no ower and should we do it halfway, the lamp will receive half
power.
As we are using TRIACs, what the software needs to do is to wait for the zero point at the sinuscurve, take note of
that and then wait a specified amount of time within that 10ms period to send a pulse to the TRIAC.
If it sends that pulse at 5ms, the lamp will only burn at half power.

In the Circuit, the zero detection is done by the biphase optocoupler and is available as the X-signal on the board.
There are basically 2 ways for a microcontroller to detect that signal:
1-a continuous 'polling' of the Zero Crossing pin
2-using an interrupt to tell the program that there was a zero crossing
The main difference between the two is that in 'polling' everytime the computer goes through it's main loop it needs
to check the pin. If your program is busy doing a lot of other things, it might be too late in checking the zero
crossing pin, while when using an interrupt, it does not matter what the program is busy with. The interrupt is sort
of 'tapping it on the shoulder' saying "Hey look, something came up that you need to attend to NOW".

After the zero crossing is detected the program needs to wait for a specified amount of time and then switch on the
TRIAC.
Also here, that waiting can be done in two different ways
1- by issuing a 'wait' command
2-by using a timer interrupt

Again, both these methods have their pro's and con's. The 'wait' command ('delay' in Arduino language) literally
let's the computer wait for the required time and it cant do anything else in the mean time. if the lamp is burning at
low power by letting the computer wait say 9ms, that means that every 10ms the computer is told to wait 9ms: ergo
it will be idle 90% of the time. That is fine if your controller is only used to control the lamp, but if it needs to do
other stuff then little time is left.
Using a timer interrupt solves that. Basically what that does is that the program tells the timer: ¨Hey, I just heard
we have a zero crossing, I got to do something else, but you just wait 4.5ms and then switch on the Triac" So the
Arduino Controlled Light Dimmer: Page 6
program goes on it's merry way and 4.5ms (as an example) after it was given notice there was a 0-crossing, the
timer switches on the TRIAC.

Polling: (note this is a rough example for illustration of polling, obviously it needs some enhancement)
int AC_LOAD=3; // We use pin 3 to ignite the TRIAC
int state; // integer to store the status of the zero crossing

void setup()
{
pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
}

void loop()
{
state=digitalRead(AC_LOAD);
if (state=1) {
delayMicroseconds(5000); // =5 ms=half power
digitalWrite(AC_LOAD, HIGH); // triac firing
}

Interrupt driven:
To use an interrupt, first we need to set that up. On the Arduino that is as follows:
void setup()
{
pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
attachInterrupt(0, zero_crosss_int, RISING); // Choose the zero cross interrupt # from the table above
}

What this says is that the interrupt is attached to interrupt 0, it goes to a function called "zero_crosss_int" and it
reacts to a rising flank on the pin.

In the Zero_cross_int function that the program jumps to after the interrupt we determine the time we need to wait
before firing the TRIAC. We will also add a bit of functionality. We don't just want one level set that the lamp burns
on, we are going to add some functionality to regulate the light level in steps.
For that I have chosen the fully arbitrary amount of 128 steps. That means that every step is 10ms/128 =
10000us/128=75us (in fact it is 78, but I get to that later). The total dimtime then is calculated from 75x(1 to 128).
The number between 1-128, which determines our level of dimming, we assign to the variable integer 'dimming'

void zero_crosss_int() // function to be fired at the zero crossing to dim the light
{
int dimtime = (75*dimming); // For 60Hz =>65
delayMicroseconds(dimtime); // Off cycle
digitalWrite(AC_LOAD, HIGH); // triac firing
delayMicroseconds(10); // triac On propagation delay (for 60Hz use 8.33)
digitalWrite(AC_LOAD, LOW); // triac Off
}

What happens here is that the program first calculates the dimtime (=time to wait before the triac is fired)
It then waits that amount of time, subsequently waits that amount of time and fires the Triac. The Triac will switch
off again at the following zero crossing, but we are going to already write a low on the TRIAC pin to avoid
accidental ignition in the next cycle. We need to wait a bit however to know for sure the TRIAC is on, so we wait
10us. Now (10000-10)/128 is still 78 but i found 75 to work well. Feel free to use 78 though.

The only thing then left to do in the main program is to set the level at which we want the lamp to burn:

Arduino Controlled Light Dimmer: Page 7


void loop() {
for (int i=5; i <= 128; i++){
dimming=i;
delay(10);
}

What happens here is a simple loop that regulates the lamp up in a 128 steps. I have chosen not to start at 1 but at
5 because at that level there could be some timing issues that could cause the lamp to flicker.

The above program is only an example of how to control the lamp, obviously you want to add some other
functionality rather than just have a lamp go up and down in brightness.

Using a timer:
If you want your program to be time efficient you will need to use an interrupt for the zero-crossing detection and a
timer to determine the amount of time to wait.
Roughly a program would look as follows:

Initialize
Set up the various constants and variables you need and include the libraries used (such as the TimerOne Library)

Setup
Setp the pins and the 2 interrupts
The zero-crosssing interrupt points to a function and so does the timer interrupt

Zero-cross functie
Set a boolean indicating if a zero cross has occurred

Timer function
If we regulate the brightness again in 128 steps, then the timer function is set up to be called whenever the time of
a step has passed (e.g. 75us) and then checks if the number of steps passed is equal to the number of steps set. If
that is the case, the Triac is switched on

Step 4: Arduino Controlled Light Dimmer: the Software

As discussed in the previous theoretical page, the software is fairly easy.

Arduino Controlled Light Dimmer: Page 8


If you want to develop your own software all you need to do is:
Wait for the zerocrossing
Wait a specific time between 0 and 9090 microseconds (9090=10.000-10)
switch on yr TRIAC
Wait for about 10us (that is the time you need to make sure the TRIAC is on)
switch off yr TRIAC (in fact, you only remove the triggersignal to the TRIAC, the TRIAC will stay on till the next
zerocrossing)

I just briefly sketch the flow of the program that I used:

(make sure you read the 'NOTE' below)

The zero X-ing signal generates an interrupt.


At 50Hz that interrupt is every 10ms or 10.000uS
At 60Hz that interrupt is every 8.333 ms or 8333 uS
The interrupt routine then switches on the Triac after a specific time. That time is set in the main program loop.
As the program varies the dimming from Full to Off in 128 steps (that is just a choice that was made, could be 100
steps as well), at 50 Hz we need the steps to be 75 uS and at 60Hz they need to be 65 uS

It works as follows:
The interrupt function"zero_crosss_int" gets called every time a zero-crossing is detected, which is
100times/second. It's only function is to set the time that the Triac is switched on to the value of the variable
'dimming'
In the main loop of the program the actual value of that variable is set

Arduino Controlled Light Dimmer: Page 9


/*

AC Voltage dimmer with Zero cross detection


Author: Charith Fernanado Adapted by DIY_bloke
License: Creative Commons Attribution Share-Alike 3.0 License.
Attach the Zero cross pin of the module to Arduino External Interrupt pin
Select the correct Interrupt # from the below table
(the Pin numbers are digital pins, NOT physical pins:
digital pin 2 [INT0]=physical pin 4 and digital pin 3 [INT1]= physical pin 5)
check: <a href="http://arduino.cc/en/Reference/attachInterrupt">interrupts</a>

Pin | Interrrupt # | Arduino Platform


---------------------------------------
2 | 0 | All -But it is INT1 on the Leonardo
3 | 1 | All -But it is INT0 on the Leonardo
18 | 5 | Arduino Mega Only
19 | 4 | Arduino Mega Only
20 | 3 | Arduino Mega Only
21 | 2 | Arduino Mega Only
0 | 0 | Leonardo
1 | 3 | Leonardo
7 | 4 | Leonardo
The Arduino Due has no standard interrupt pins as an iterrupt can be attached to almosty any pin.

In the program pin 2 is chosen


*/
int AC_LOAD = 3; // Output to Opto Triac pin
int dimming = 128; // Dimming level (0-128) 0 = ON, 128 = OFF

void setup()
{
pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
attachInterrupt(0, zero_crosss_int, RISING); // Choose the zero cross interrupt # from the table above
}

//the interrupt function must take no parameters and return nothing


void zero_crosss_int() //function to be fired at the zero crossing to dim the light
{
// Firing angle calculation : 1 full 50Hz wave =1/50=20ms
// Every zerocrossing thus: (50Hz)-> 10ms (1/2 Cycle)
// For 60Hz => 8.33ms (10.000/120)
// 10ms=10000us
// (10000us - 10us) / 128 = 75 (Approx) For 60Hz =>65

int dimtime = (75*dimming); // For 60Hz =>65


delayMicroseconds(dimtime); // Wait till firing the TRIAC
digitalWrite(AC_LOAD, HIGH); // Fire the TRIAC
delayMicroseconds(10); // triac On propogation delay
// (for 60Hz use 8.33) Some Triacs need a longer period
digitalWrite(AC_LOAD, LOW); // No longer trigger the TRIAC (the next zero crossing will swith it off) TRIAC
}

void loop() {
for (int i=5; i <= 128; i++){
dimming=i;
delay(10);
}
}

About the software: theoretically in the loop you could let variable 'i' start from '0'. However, since the timing in the
interrupt is a bit of an approximation using '0' (fully on) could screw up the timing a bit. the same goes for 128 (Full
off) though that seems to be less critical. Wether '5' or perhaps '1' is the limit for your set up is a matter of trying,
your range may go from e.g. 2 to 126 instead of 0-128. If anybody has a more precise way to set up the timing in
the interrupt I'd be happy to hear it.
Ofcourse it is not necessary to work with interrupts. It is also possible to keep polling the zero crossing pin for
going to 0.

Arduino Controlled Light Dimmer: Page 10


Though the software works with an interrupt to determine the moment of zero crosssing, it is still not so efficient
because the time (dimtime) we need to wait after the zero crossing before the triac is fired is literally spent 'waiting'
in the zero cross interrupt function.

It would be more efficient to set a timer interrupt to fire at the right moment so in the mean time the arduino can do
something else. Such a program can be found in step 6

NOTE

Let me just reiterate the above statement: This program is a demo of how you can control the dimmer. It is
NOT and efficient program as it spends most of its time waiting. It is therefore NOT the most suitable to
combine with other tasks of the processor. If you need a more efficient program use a timer instead of
delay

Arduino Controlled Light Dimmer: Page 11


Step 5: Arduino Controlled Lightdimmer: the Software II

I found another piece of Software that allows controlling the lamp via the serial port.It triggers on the falling edge of
the zero-crossing signal, so the timing is a bit different.

I have not tested it myself yet, but I see reasons why it should not work: as far as i can see it doesnt receive the
number typed in the serial port but it receives the ascii value of each digit that is typed, so a '0' will be seen as 48

int AC_pin = 3;//Pin to OptoTriac


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

void setup() {
Serial.begin(9600);
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 = Serial.read();
if (dim < 1) {
//Turn TRIAC completely OFF if dim is 0
digitalWrite(AC_pin, LOW);
}

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


digitalWrite(AC_pin, HIGH);
}
}

if (dim > 0 && dim < 255) {


//Dimming part, if dim is not 0 and not 255
delayMicroseconds(34*(255-dim));
digitalWrite(AC_pin, HIGH);
delayMicroseconds(500);
digitalWrite(AC_pin, LOW);
}
}
void loop() {
}

Just a note: The above software is not mine. I think it is better to keep the check of the serial port out of the
interrupt. Also the 500uS delay before the TRIAC is switched OFF is maybe a bit long.

Even more software here

Step 6: Arduino Controlled Light Dimmer: the Software III

The code below uses the timer function rather than a delay and has been confirmed to work on the Leonardo as
well

https://codebender.cc/embed/sketch:171819

Arduino Controlled Light Dimmer: Page 12


Step 7: MQTT Your Dimmer

It is possible to use MQTT to control your dimmer, provided you have a WLAN connection. In this example I am
using an Arduino UNO with Ethernetshield.
The topic is "home/br/sb" with a payload from 0-100 to set the dimming level

#include <Ethernet.h> // Ethernet.h


#include <PubSubClient.h> // PubSubClient.h
#include <TimerOne.h> //TimerOne.h

#define CLIENT_ID "Dimmer"


#define PUBLISH_DELAY 3000

String ip = "";
bool startsend = HIGH;
uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x07};

volatile int i=0; // Variable to use as a counter volatile as it is in an interrupt


volatile boolean zero_cross=0; // Boolean to store a "switch" to tell us if we have crossed zero
int AC_pin1 = 4;// Output to Opto Triac
int dim1 = 0;// Dimming level (0-100) 0 = on, 100 = 0ff

int inc=1; // counting up or down, 1=up, -1=down


int freqStep = 100;

EthernetClient ethClient;
PubSubClient mqttClient;
long previousMillis;

void zero_cross_detect() {
zero_cross = true; // set the boolean to true to tell our dimming function that a zero cross has occured
i=0;
digitalWrite(AC_pin1, LOW); // turn off TRIAC (and AC)
}

// Turn on the TRIAC at the appropriate time


void dim_check() {
if(zero_cross == true) {
if(i>=dim1) {
digitalWrite(AC_pin1, HIGH); // turn on light
i=0; // reset time step counter
zero_cross = false; //reset zero cross detection
}
else {
i++; // increment time step counter
}
}
}

void setup() {

attachInterrupt(0, zero_cross_detect, RISING); // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
Arduino Controlled Light Dimmer: Page 13
attachInterrupt(0, zero_cross_detect, RISING); // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
Timer1.initialize(freqStep); // Initialize TimerOne library for the freq we need
Timer1.attachInterrupt(dim_check, freqStep);
pinMode(4, OUTPUT);

// setup serial communication

Serial.begin(9600);
while (!Serial) {};
Serial.println(F("dimmer"));
Serial.println();

// setup ethernet communication using DHCP


if (Ethernet.begin(mac) == 0) {
Serial.println(F("Unable to configure Ethernet using DHCP"));
for (;;);
}

Serial.println(F("Ethernet configured via DHCP"));


Serial.print("IP address: ");
Serial.println(Ethernet.localIP());
Serial.println();

ip = String (Ethernet.localIP()[0]);
ip = ip + ".";
ip = ip + String (Ethernet.localIP()[1]);
ip = ip + ".";
ip = ip + String (Ethernet.localIP()[2]);
ip = ip + ".";
ip = ip + String (Ethernet.localIP()[3]);
//Serial.println(ip);

// setup mqtt client


mqttClient.setClient(ethClient);
mqttClient.setServer( "192.168.1.103", 1883); // <= put here the address of YOUR MQTT server
//Serial.println(F("MQTT client configured"));
mqttClient.setCallback(callback);
Serial.println();
Serial.println(F("Ready to send data"));
previousMillis = millis();
mqttClient.publish("home/br/nb/ip", ip.c_str());
}

void loop() {
// it's time to send new data?
if (millis() - previousMillis > PUBLISH_DELAY) {
sendData();
previousMillis = millis();
}
mqttClient.loop();
Serial.print("dim1 = ");
Serial.println(dim1);
}

void sendData() {
char msgBuffer[20];
if (mqttClient.connect(CLIENT_ID)) {
mqttClient.subscribe("home/br/sb");
if (startsend) {
mqttClient.publish("home/br/nb/ip", ip.c_str());
startsend = LOW;
}
}
}

void callback(char* topic, byte* payload, unsigned int length) {


char msgBuffer[20];
payload[length] = '\0'; // terminate string with '0'
String strPayload = String((char*)payload); // convert to string
Serial.print("strPayload = ");
Serial.println(strPayload); //can use this if using longer southbound topics
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");//MQTT_BROKER
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
Arduino Controlled Light Dimmer: Page 14
Serial.print((char)payload[i]);
}
Serial.println();
Serial.println(payload[0]);

dim1=strPayload.toInt();

Step 8: Software to Set Level Using Up and Down Buttons

Below a code to set the light level with up and down buttons. It uses a timer that checks for the time necessary to
trigger the TRIAC, rather than wait in a delay loop

/*
AC Light Control
Uses up and down buttons to set levels
makes use of a timer interrupt to set the level of dimming
*/
#include <TimerOne.h> // Avaiable from http://www.arduino.cc/playground/Code/Timer1

volatile int i=0; // Variable to use as a counter of dimming steps. It is volatile since it is passed between interrupts
volatile boolean zero_cross=0; // Flag to indicate we have crossed zero
int AC_pin = 3; // Output to Opto Triac
int buton1 = 4; // first button at pin 4
int buton2 = 5; // second button at pin 5
int dim2 = 0; // led control
int dim = 128; // Dimming level (0-128) 0 = on, 128 = 0ff
int pas = 8; // step for count;
int freqStep = 75; // This is the delay-per-brightness step in microseconds. It allows for 128 steps
// If using 60 Hz grid frequency set this to 65

void setup() { // Begin setup


Serial.begin(9600);
pinMode(buton1, INPUT); // set buton1 pin as input
pinMode(buton2, INPUT); // set buton1 pin as input
pinMode(AC_pin, OUTPUT); // Set the Triac pin as output
attachInterrupt(0, zero_cross_detect, RISING); // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
Timer1.initialize(freqStep); // Initialize TimerOne library for the freq we need
Timer1.attachInterrupt(dim_check, freqStep); // Go to dim_check procedure every 75 uS (50Hz) or 65 uS (60Hz)
// Use the TimerOne Library to attach an interrupt

void zero_cross_detect() {
zero_cross = true; // set flag for dim_check function that a zero cross has occured
i=0; // stepcounter to 0.... as we start a new cycle
digitalWrite(AC_pin, LOW);
}

// Turn on the TRIAC at the appropriate time


// We arrive here every 75 (65) uS
// First check if a flag has been set
// Then check if the counter 'i' has reached the dimming level
// if so.... switch on the TRIAC and reset the counter
void dim_check() {
if(zero_cross == true) {
if(i>=dim) {
digitalWrite(AC_pin, HIGH); // turn on light
i=0; // reset time step counter
Arduino Controlled Light Dimmer: Page 15
i=0; // reset time step counter
zero_cross=false; // reset zero cross detection flag
}
else {
i++; // increment time step counter
}
}
}

void loop() {
digitalWrite(buton1, HIGH);
digitalWrite(buton2, HIGH);

if (digitalRead(buton1) == LOW)
{
if (dim<127)
{
dim = dim + pas;
if (dim>127)
{
dim=128;
}
}
}
if (digitalRead(buton2) == LOW)
{
if (dim>5)
{
dim = dim - pas;
if (dim<0)
{
dim=0;
}
}
}
while (digitalRead(buton1) == LOW) { }
delay(10); // waiting little bit...
while (digitalRead(buton2) == LOW) { }
delay(10); // waiting little bit...

dim2 = 255-2*dim;
if (dim2<0)
{
dim2 = 0;
}

Serial.print("dim=");
Serial.print(dim);
Serial.print(" dim2=");
Serial.print(dim2);
Serial.print(" dim1=");
Serial.print(2*dim);
Serial.print('\n');
delay (100);

Step 9: More Interrupt Driven Software

https://codebender.cc/embed/sketch:237008

Arduino Controlled Light Dimmer: Page 16


Step 10: Arduino Controlled Lightdimmer: Result & Expansion

Just a quick cellphone recorded video of it's workings The zero-crossing circuit is ofcourse only needed
once.
Perhaps this is still something for tradition (call it Old
fashioned): x-mas tree lights that work directly on 220
(or 110) Volts. Hang 3 different color lamp strings in
//www.youtube.com/embed/AYB9X7zN-VA
the tree and regulate them with this circuit expanded
with two TRIAC circuits

Frequency
Depending on the grid frequency (either 50 or 60)
different step values need to be set manually.
3 channels
However, it is possible to let the software determine
This circuit can also be used for an RGB mixer, albeit
the frequency in a setup routine, e.g. by meauring the
you need two additional TRIAC circuits. You could
time between two zero crossings or count the number
use this circuit+PCB in duplo for that, but make sure
of zerocriossings within a set time.
you use a random cycle opto-coupler suah as the
MOC3021. Do not use a zerocrossing Opto-coupler
such as the MOC3041.
I now made a 3 channel Ibble

Arduino Controlled Light Dimmer: Page 17


Step 11: 8051 Controlled Lightdimmer: Software

Obviously, one can use the 8051 microcontroller series as well to control the dimmer.
As I dont have an 8051 development system anymore, I cannot test any code, but should you want to develop this
for an 8051, the following example may be of help:

//
//Controlling AC with a 8051
//Untested Code
//Compiles with MicroC Pro for 8051
int dimming;
int x;
int i;

void ex0_isr(void) iv IVT_ADDR_EX0 ilevel 0 ics ICS_AUTO {


/*===================================================*/
int dimtime=(75*dimming);
//delay_us(dimtime);
P0=0xFF; // sets entire PORT 0 high, can also use e.g. P0_1 =1 ;
delay_us(10); //propagationdelay
P0=0x00;
}

void delay(int maal){


for (x=1; x< maal; x++) {
delay_us(75); // 65 for 60Hz
}
}

/*===================================================*/
void main()
{

/*------------------------
Configure INT0 (external interrupt 0) to generate
an interrupt on the falling-edge of /INT0 (P3.2).
Enable the EX0 interrupt and then enable the
global interrupt flag.
------------------------------------------------*/
IT0_bit =1; // Configure interrupt 0 for falling edge on /INT0 (P3.2)
EX0_bit = 1; // Enable EX0 Interrupt
EA_bit = 1; // Enable Global Interrupt Flag
P0 = 0x00; //all pin of PORT0 declared as output

while (1)
{
for(i=5;i<128;i++){
dimming=i;
delay(10);//arbitrary delay between steps
}
}
}

I cannot garantee this code to work as I have no way of testing it. Should anybody try it and have results I would
be glad to hear it.
An application note describing a fan control according to the same principle, can be found here.

Arduino Controlled Light Dimmer: Page 18


Step 12: PIC Controlled Lightdimmer: the Software

If you want to use this circuit with a PIC unsigned char FlagReg;
microcontroller, the software in this link may help you int x;
get further: int maal;
http://www.edaboard.com/thread265546.html int dimming=20;// '20' is just an example. Dimming
should contain a
A good article on zero crossing detection with a PIC // value between 0 and 128 and can be taken from
can be found here: e.g. a
// variable resistor or LDR or a value coming out of a
http://tahmidmc.blogspot.nl/2012/10/zero-crossing-... program
sbit ZC at FlagReg.B0;
The writer Syed Tahmid Mahbub gives a basic
program that detects the zero crossing and then void interrupt(){
triggers the LED with a delay of 20ms . if (INTCON.INTF){ //INTF flag raised, so external
Although I never worked with PIC's before and am no interrupt occured
crack on C programming. I decided to see if i could ZC = 1;
build on his program and make it possible to vary the INTCON.INTF = 0;
light intensity, rather than just give it one value (the }
20ms delay). }
I soon found out that the delay_ms and delay_us
functions in C, are a bit tricky, namely that they don’t void delay(int maal){
accept a variable. The delay time needs to be known for (x=1; x< maal; x++) {
at the time of compilation as it is hard coded. I saw delay_us(75); // 65 for 60Hz
some complicated work-arounds, but I thought a }
simpler solution would be to make a function that }
gives a 75 uS delay (make that 65 for 60Hz) and call
that with a parameter determining how often that void main() {
delay is looped. PORTB = 0;
The maximum number of times the delay is looped is TRISB = 0x01; //RB0 input for interrupt
128. That is because I have randomly chosen that the PORTA = 0;
light should be dimmed in 128 steps (with 0 being full ADCON1 = 7; //Disable ADC
on and 128 being off). TRISA = 0xFF; //Make all PORTA inputs
PORTD
Arduino Controlled Light = 0; Page 19
Dimmer:
A warning though: I have no PIC programmer and I PORTD = 0;
am not planning (yet) to go into pics, happy as I am TRISD = 0; //PORTD all output
with the Atmega and Attiny series. Therefore I cannot OPTION_REG.INTEDG = 0; //interrupt on falling
test the program. I can only say that it compiles edge
without problems, and if you want to use the circuit on INTCON.INTF = 0; //clear interrupt flag
a PIC, it will help you get started. You can also find INTCON.INTE = 1; //enable external interrupt
full projects, including a program, here and here, INTCON.GIE = 1; //enable global interrupt
including an IR remoteand here
//------------------------------------------------------------------------ while (1){
--------------------------------- if (ZC){ //zero crossing occurred
//Programmer: DIY_Bloke delay(dimming); // '20' is an example
//Strongly based on a 0-X program from Syed Tahmid PORTD.B0 = 1; //Send a pulse
Mahbub delay_us(250);
//Compiler: mikroC PRO for PIC v4.60 PORTD.B0 = 0;
//Target PIC: PIC16F877A ZC = 0;
//Program for phase angle control }
//zero crossing signal on pin 33 RB0/INT }
//gating signal to MOC3021 via 220-470R from pin 19 }
RD0/PSP0
//X-tal 4 MHz
//------------------------------------------------------------------------
---------------------------------

Step 13: Problems

Arduino Controlled Light Dimmer: Page 20


If for whatever reason the circuit you built is not -You have a faulty TRIAC. As described above. Yet,
working, other than it starting to smoke. check the gate resistor if it really has the correct
Before you do any work on the circuit UNPLUG IT value, just to make sure
FROM THE MAINS!!
3-The lamp is constantly off
There are mainly 3 things that can happen: As this may also be a software or hardware problem,
first see what hapens with the arduino disconnected.
1-The lamp is flickering Connect the input to a plus 5Volt supply and measure
This is probably the most common problem you can the voltage on the primary side of the optocoupler
encounter and there maybe several reasons for it e.g. (YOUR CIRCUIT SHOULD NOT BE CONNECTED
-a 'dirty' powersupply. TO THE MAINS). If that is a couple of volts, connect
If your powersupply gives off a lot of extra spikes, your circuit to the mains and see what happens. If the
these can be present on the 0X signal pin and mess lamp switches on there is a problem with the input
up the clean Zero crossing signals. Try another signal. If it stays off, you may have a faulty
powersupply. optocoupler, a faulty TRIAC or your circuit somehow
-'timing' problems is not connected to the mains. Another possibility is
using an optocoupler gives a precise zero-crossing that the voltage drop over the LED is preventing the
signal, but it is not extremely narrow. The pulse width optocoupler to open, especially when you are using
of this circuit (at 50Hz) is typically around 600us say 3.3 V as a driving voltage. Make sure you have
(0.6ms) which sounds fast enough. The problem is an LED with a low voltage drop or replace it by a wire
that at 50Hz each half cycle takes only 10ms (8.33ms bridge.
at 60Hz), so the pulse width is over 5% of the total
period. This is why most dimmers can only claim a A piece of code that can help you test the Triac circuit
range of 10%-90% - the zero crossing pulse lasts too is to add the following into the setup
long to allow more range. The solution is to avoid
regulating all the way down or all the way up. Also void setup()
increasing or sometimes decreasing the step-value {
(the number 75 for 50Hz and 65 for 60Hz) may cure pinMode(AC_LOAD, OUTPUT); // Set the AC Load
that. as output
for (int i=0; i < 10; i++) {
2-The lamp is constantly on digitalWrite(AC_LOAD, HIGH); // triac firing
This might be a software or a hardware problem and delay(1000);
the easiest way to sort that out is to make sure the digitalWrite(AC_LOAD, LOW); // triac Off
microcontroller is not connected to the circuit. If the delay(1000);
lamp is still on there are grossly 4 possibilities: }
-You somehow fucked up the circuit, check if it is }
indeed OK and that everything is connected to where This will first fire the TRIAC a few times so you can
it shoudl be connected. see it is working
-The MOC3021 is somehow receiving a positive
input, make sure there are no stray drops of solder Most common fault till now
shorting things that shouldn’t be shorted. Short the
input and ground wire and see if the lamp stays off. From all the people that contacted me about
-The MOC3021 is short circuited at the high voltage problems of the circuit not working, the most common
end. Remove the MOC3021 from its socket and see fault was: faulty wiring: a chip put upside down, a
what happens: if yr lamp stays off there is likely solder joint not good, a wire not connected right.
something wrong with yr MOC3021. If your lamp
stays on, you probably have a faulty TRIAC

Arduino Controlled Light Dimmer: Page 21


Step 14: The Gate Resistor: a Bit of Theory

When cruyising the internet for Triac switches, you Charge will then accumulate in the triac’s gate until
may have come across a large diversion in the value V_{GT} gets build up and the the triac gets activated.
of the gate resistor value. My choice usually is to take
the lowest value that will still protect the gate and the In quadrant I, ( V_{GT} and A1 are more positive than
optocoupler. A2) in order for sufficient charge to build up and
Reader Mali Lagunas did some research in the theory V_{GT} in the main triac to bee reached, the voltage
behind the criteria to choose the value of the gate across the triac must equal V_R+V_{TM}+V_{GT}
resistor. Which i will copy below: Of course V_R=I_{GT}*R . Commonly,
V_{TM}+V_{GT} will both account for approximately
The resistor when placed in this circuit, will have two 3V (datasheet). At the same time, the resistor must
main effects: provide sufficient current to the Triac’s gate, let’s say
a) It will limit/provide the current going into the gate of a minimum of 25 mA (sensitivity of the Triac), thus
the triac (I_{GT})
b) It will cause the voltage to drop when the triac is on V_{triac}= 330ohms*25mA+1.3V+1.1V=10.65V and
(V_R) V_{triac}= 1k-ohms*25mA+1.3V+1.1V=27.4V (the
value in your circuit)
The lowest value this resistor may have (for 220 V
AC) is R=220*sqrt(2)/I_{TMS}, where I_{TMS} is the Which is the voltage needed to activate the triac.
maximum peak current allowed in the photocoupler’s Therefore, the smaller the resistor the less voltage is
phototriac. These are surge values, thus they are required to switch on the main triac. What goes on
transient and account for a limit before breakdown. afterwards is mainly that there is a voltage drop
Therefore in your circuit R would be across A1 and A2 and therefore the phototriac
R=220*sqrt(2)/1=311.12 or 330 ohms, since the voltage and current will drop causing turn-off state (of
MOC3021¢s I_{TMS}=1A. This is consistent with the phototriac). The main triac will be kept switched
I_{GM} which is the peak gate current of the TIC206. on if the holding current I_H is respected. When the
In your schematic you use 1K which would limit the load current is below I_H, the main triac is switched
current to 311mA. off until a pulse from the photodiode is emitted again
in order to polarize V_{GT} and build the required
This “surge” case may take place only when a pulse charge in the next cycle. Q1 and Q3 are the
is received by the phototriac and it is able to conduct quadrants for this setup.
I_{GT}, and of course for a line value of 220*sqrt(2).

Arduino Controlled Light Dimmer: Page 22


Step 15: Dimming: a Bit of Theory

Just as a background to this instructable: There are Trailing edge dimmers commonly use a MOSFET, as
various types of dimmers. What is presented here is a these require almost no control current and are
phase-controlled (aka 'phase-cut') leading edge (aka rugged and reliable. They are also relatively cheap
"forward phase")TRIAC dimmer. and readily available at voltage ratings suitable for
mains operation. Another option is to use an IGBT
Leading Edge Dimmers (insulated gate bipolar transistor), which combines
In this type the dimmer actually cuts parts off the the advantages of both MOSFET and bipolar
beginning of the sinewave. This is the most widely transistor. These are generally more expensive than
used type of dimmer as it is ver suitable for TRIACs. MOSFETs. Again, the waveform is ideal, and it is
After all, A Triac is easy to switch on and it will switch obvious from the actual waveform shown in Figure 9
off by itself once there is a zero crossing because the that there is a significant deviation - especially at full
current drops below the gate hold current power. This is caused because some of the applied
voltage will always be lost because the complex
Trailing Edge Dimmers electronics require some voltage to operate.
Also known as 'reverse phase control' dimmers. A
trailing edge dimmer is a considerably more complex Most trailing edge dimmers have another useful
circuit. The simple circuitry that is common with function - at least when used with incandescent
leading edge types can no longer be used, because lamps. The circuitry is designed to provide a 'soft
most TRIACs cannot be turned off. Gate turn-off start', increasing the voltage to the lamp relatively
(GTO) TRIACs exist, but are far more expensive and slowly. With incandescent lamps, this almost
less common in the relatively small sizes needed for eliminates 'thermal shock' - that brief period at switch-
lighting. To be able to implement a trailing edge on where the lamp draws around 10 times the normal
dimmer, the switching device must turn on as the AC operating current. Thermal shock is responsible for
waveform passes through zero, using a circuit called most early lamp failures - it is rare indeed for any
a zero-crossing detector. After a predetermined time incandescent lamp to fail while it's on. Failure is
set by the control, the switching device is turned off, almost always at the moment the switch is turned on.
and the remaining part of the waveform is not used by By including the soft-start feature lamp life is
the load. increased.

Arduino Controlled Light Dimmer: Page 23


Step 16: Zero Crossing: a Bit of Theory

Though I described the zerocrossing already, I will possible. In practice however I found the 2x 33k to be
spend some more words on it. a good value, leading to a pulse starting abt 200uS
With the 'bridge and opto-coupler' circuit that I used in before the actual zerocrossing. That is very
this project, the principle is very clear: A mains AC acceptable. The current through the 4N25 is
voltage passes through 2 resistors of 33k and is approximately 3.33 mA. Surely we could take that up
rectified by the diode bridge. a notch, but it isn't necessary. With these values the
This rectification results in a pulsating DC voltage that idle use of this circuit is an estimated 0.7 Watts
keeps the optocoupler open, keeping the
zerocrossing signal LOW till the voltage drops to The same actually goes for the circuit with the
'zero' at what point the optocoupler will not be in H11AA1. The advantage of the H11AA1 is that one
conduction anymore and the zerocrossing signal is doesn't need a diode bridge as it has two antiparallel
pulled high, untill the voltage rises again enough to diodes. The same goes for the IL250 series or the
send the optocoupler into conduction again, resulting LTV814
in the zerocrossing pin going LOW. One can reach the same effect with two regular
The 'quality' of that zerocrossing pulse is of course optocouplers such as the 4N25, as the figure shows
depending on a number of factors but mainly on the or with a dual optocoupler.
speed of the optocoupler, the value of the collector
resistor, but not in the least on the value of the two I also provided a circuit in which the width of the
resistors in the mains line. zerocrossing pulse can be regulated.
As said before, the width of the Zerocrossing signal
If that value is too low, your optocoupler will burn out, determines how far before the actual zerocrossing the
but if it is too high, the voltage at which there still is interrupt is generated. Ideally, if you know how wide
enough current going through the optocoupler to keep your zerocrossing signal is, you could take that into
it conducting becomes higher and higher. That means account in the software. Suppose your signal is
that if the resistor value is too high, the switching of 600uS wide and suppose that is a evenly divided
the optocoupler will happen higher on the rising and timing. Then you know that your interrupt is generated
descending flank of the sin wave, resulting in a wide some 300uS before the actual Zerocrossing. You
zerocrossing signal, that starts way before the actual could wait that period after each interrupt to get a
zerocrossing until way after the zerocrossing. more precise handling of the zerocrossing
Ergo: The resistor value should be as low as

Arduino Controlled Light Dimmer: Page 24


I was able to stop my ligtbulb to flickering adding those lines.(Working on ESP8266 on 60Hz )
pin 14 is a digital input linked to the 0-X output .
Using while waiting loop the command became low just after the triac has been trigerred, And no
after a constant of time.
if (dim > 0 && dim < 255) //intencité variable de la lampe avec une resolution de 8 bits 0~255
{
delayMicroseconds(65.33*dim); // Off cycle
digitalWrite(AC_pin, HIGH); // triac firing
delayMicroseconds(6.4);
while(digitalRead(14)==0)
{
}
digitalWrite(AC_pin, LOW); // triac Off
}

Arduino Controlled Light Dimmer: Page 25


hi can you be so kind to share your code I am trying a lot with node mcu but not achieved even
flickering. iam using blynk can you help me please

//Working with blynk, with a slider going from 0 to 180 (ESP8266 110v //60Hz and same PCB)
//Because after 180(*33µs) my triac wasnt able to be fired
#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
char auth[] = "xxx";
char ssid[] = "xxx";
char pass[] = "xxx";
int dim = 0;
float valeur=0;
void setup() {
Blynk.begin(auth, ssid, pass);
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(2), light, FALLING);//Interruption lors d'un passage de la
tension alternative par 0 .
pinMode(0, OUTPUT);
pinMode(14, INPUT);
}
void light()
{
if (dim < 1) //dim a 0 la lampe est eteinte
{
digitalWrite(0,HIGH );
}
if (dim > 179) //dim a 180 la lampe est allumé a 100%
{
digitalWrite(0, LOW);
}
if (dim > 0 && dim < 180) //intensité variable de la lampe avec une resolution de 8 bits 0~179
{
delayMicroseconds(33*dim); // Off cycle
digitalWrite(0, HIGH); // triac firing
while(digitalRead(14)==0)
{
}
digitalWrite(0, LOW); // triac Off

Arduino Controlled Light Dimmer: Page 26


}
}
void loop() {
Blynk.run();
}
BLYNK_WRITE(V12) //Button Widget is writing to pin V12
{
dim=param.asInt();
}

hi jack thanks a lot for the code I am using it, but there are two # include, the file name is not there
so I am puzzled which library to include.
And at
BLYNK_WRITE(V12) //Button Widget is writing to pin V12
it is showing error
exit status 1
expected constructor, destructor, or type conversion before '(' token.
in my country it is 220V/50HZ so do I need to change in microseconds.
plz help ill be very thankful to you

I have modified my code for the lib, and 50Hz mean you have to put 39 instead of 33 µs (
1/(50*2*255) )

Thanks a lot for your help.. highly appreciated.

Hi dear Jack I have copy and pasted the above code. I am just getting on and off form the circuit. I
am using 4n 25 and moc 3021. I have made bridge from 4 x in 4007 with 30 k resistor 320 ohm in
triac gate. 220ohm in Moc3021. I am giving output to moc 3021 from pin 0 i.e D3 of node mcu and
zero cross to pin 14 i.e D5 of node MCU ground attached to ground and 5v connected to external
power supply. the ground of external power supply is connected to the ground of node mcu. and in
blynk app I have assigned pin 0 i.e D3 to slider. on sliding slider it gets on and off only any clue.
what I am doing wrong. I have made connections as shown in picture. please help me

Hi there.. thanks for the tutorial, can i set automation PWM depend on DHT22 sensor using this
module?

Hi diy_bloke
Thanks for this piece of software. I'm using module:
Arduino Controlled Light Dimmer: Page 27
https://www.aliexpress.com/store/product/AC-Light-...
Works excellent with your code (step 6).
For serial communication I'm using the Serial.parseInt() command to send a value between 0 and
128.
What I'm looking for is a method to use the module on a RaspberryPi or OrangePi without using an
Arduino. Any ideas anyone ?

by the way, i see the aliexpress store copied part of my text on pulse skip modulation :-)

@diy_bloke Hi, firstly thank you for sharing this. It's really a lot of work you put into writing this. I
am trying to use your code in step 4 with the same Dimmer module from Aliexpress but I cannot
get it to work.. How do I connect the dimmer module to the Arduino? @ndirksen could you show
me how you connect your arduino and the dimmer module??

Thank you for your kind words.


the module from aliexpress has a Z-C pin, that goes to your interrupt pin on the UNO (pin 2). It also
has a PWM pin that goes to the output pin (pin 3) of the UNO (it is not really a PWM signal, the
Chinese just labelled it that way)

My pleasure. I see that my original reply to you wasnt placed or disappered somehow
The method for raspberry or orange pie is in principle the same. Need an interrupt pin and an
output pin. I am no crack in Python, but I am pretty sure that can be used for programming such a
thing.
Thanks for that link, that kinda makes it better to buy a module than to diy it yrself

This is probably one of the most fun and well documented theory, circuit and software project. In
mine, I am using an esp8266, so I had to really spend lot's of time to figure out the interrupt
handling on esp8266. My goal is to build a homekit (aka Siri) dimmer! and now I am integrating
both software parts of that project and will publish a gist. Big Thanks to the OP. My circuit is a
temporary prototype where I am trying to squeeze as much as possible in small area. Nothing will
heat up as I will be driving at most 40W worth of LEDs and using a 1W resistor and a LittleFuse for
protection.

hi sir I have tried a lot with the node mcu but haven't achived any success can you please provide
the code

I Made It and it's working smoothly.

Arduino Controlled Light Dimmer: Page 28


looking great, thanks for sharing

great, thank you for sharing

Thanks a lot!
With your tutorial I was able to do this dragon ball lamp :)

//www.youtube.com/embed/sMglBAEWoIo

stil looking at it, I think you did fantastic job

I am happy it helped you. Thanks for sharing your pics and video

Hi, i am trying to built this project. my connection is as in fig 1. the o/p of opto coupler 4N35(zero
crossing signal) is as in fig 2. But the light is not glowing. I have used this program as provided by
you.
int AC_LOAD = 3;
int dimming = 128;
void setup() {
pinMode(AC_LOAD, OUTPUT);
attachInterrupt(0, zero_crosss_int, RISING);
}
void zero_crosss_int()
{
int dimtime = (75*dimming);
delayMicroseconds(dimtime);
digitalWrite(AC_LOAD, HIGH);
delayMicroseconds(10);
digitalWrite(AC_LOAD, LOW);
}
void loop() {

Arduino Controlled Light Dimmer: Page 29


for (int i=5; i <= 128; i++){
dimming=i;
delay(10);
}
}
Can you help me why it is not working. Thank you.

I replied on your similar question in the 'question section', but I will repeat it here:
There could be several issues. Let's first try and pinpoint the problem.
So for the moment forget the Arduino and the sync pulses: If you just put 5Volt on the, entrance (so
where in yr circuit it says "Arduino pin 3" , what happens then?

Hi, very exhaustive and well-documented Instructable!


I stumbled upon this page while looking for some example for this piece of stuff:
http://robotdyn.com/ac-light-dimmer-module-1-chann...
BTW the PSM description on that page is absolutely identical to yours, I guess that they have to
give you some credits.

I have some problems with flickering (code problem) and with dimming led tube (230V). Tyristor
need som minimal current to stay open. More about this is here (page 4-6):
http://www.solomon-systech.com/files/ck/files/Tech...
I add relay for complete high voltage circuit disconnect. On PCB is arduino pro mini and AC/DC
source. This pcb is ready for 868MHz connect with OpenHAB.

Looks great. Not really a Thyristor but a Triac :-)


But yes with very small loads, Triacs have a problem sometimes to stay open.
I actually added a code for openhab recently but that was for MQTT.
RF868Mhz is definitely a good option too
I probably would not build this circuit again :-) as there now is a module available on Aliexpress,
that is only slightly more expensive than if you build it from scratch :-)

Hi,
Great tutorial. I put more or less your circuitry on a PCB and my LED bulbs are flickering, specially
when dimtime is high (over 5500us). I am using the following components:
- TPC817S1B as Octocoupler

Arduino Controlled Light Dimmer: Page 30


- MOC3023S-TA
- BT136-600E,127 as TRIAC
I also have on the PCB a AC/DC to step down but checked the voltage and it is very stable at
4.88Vdc. Do you know why is the lamp flickering? Any suggestion?
Thanks in advance!

There can by problem with tyristor current. Tyristor need som minimal current to stay open. More
about this is here (page 4-6):
http://www.solomon-systech.com/files/ck/files/Tech...
You can try add ordinary lihgt bulb (aditional load).
Or You have problem with code. Try use fixed dim value (no analogRead).

Thank you. What sort of Ledbulbs are you using?

Philips, Osram, unbranded... Always exactly the same effect. When off time is over 5ms, they start
flickering...

Dimming LED bulbs is always a bit tricky. Does it say these bulbs are suitable for 'traditional
dimmers'?
The way the dimmer works is by phase cutting. That is very suitable for pure resistance loads such
as incandescent lamps but the electronics in an LED bulb usually do not take kindly to that.

What exactly are you feeding with the "AC/DC" on yr pcb?

I have tested also halogen bulbs and exactly same behaviour. With the flyback converter (AC/DC),
I am feeding the esp32, the octocoupler and a couple of sensors. Btw, the octocoupler is very
close to the transformer, can that have any influence?
What is really weird is bulb only flickers when off is over 5ms, this is, its luminosity is very low.
When luminosity is high, no flickering at all...
Do you have any idea of what can happen?

apologies for my late reply, I had some health issues. The proximity of optocoupler and trafo
should not make any difference.Just to establish a baseline, could u try with a regeular
incandescent lamp to see if that goes well

Incandescent bulbs have exactly the same issue

well the timing is rather precarious. What is possible is that on yr lowest setting, the waiting period
either under or overshoots the cycle, especially because the 0 cross signal has a specific pulswidth
that eats into the cycle. Additionally there is a little bit of a rounding error in the timing of the steps.
There are two things you can do: instead of triggering on the RISING flank, try the FALLING. or

Arduino Controlled Light Dimmer: Page 31


limit the timing for the flickering levels (as it is not your true minimum

Lastly, there still could be noise on yr Voltline, add a capacitor

Given you are using an esp32, I am wondering if you are using interrupts for both zero crossing
check and the timer, do that and make sure nothing else is running on the esp32 to isolate issues. I
used the same circuit w some minor modifs and I can dim two different 7W LED dimmable lamps
successfully with no flicker, but they buzz slightly at certain levels which is expected w this circuit
and LEDs.
If you get an issue with incandescent, then definitely check your circuit. There are clearance rules
when having AC and DC circuitry, and lot's of bad things can happen if you don't respect that. Post
a pic of your PCB. GL and be safe :-)

I am not sure if I fully understand what you want. Is it just a regular TRIAC switch you need?. Are
you sure it is a triac you need? if it is just low voltage DC it seems a thyristor would be better, or
maybe a FET or a relay

Hello, bloke.

Really awesome tutorial !


i've used the code from steps 6 by Ed1960 and it works great (im using arduino uno R3).
i
want to use this circuit with sensor LDR where the condition is when
the lux is 10 (dark) the brightness of the lamp is 100%, when the lux is
50 (not to bright) the brightness = 60%.
what should i add inside the code ?
Thanks before btw :)

All the programs are in fact demos that vary the dimming.
The code in step 6 contains in the main loop the following section:
dim+=inc;
if((dim>=128) || (dim<=0))
inc*=-1;
delay(18);
that makes the dim value vary between 0 and 128. So what u need to do is to take out that section
and replace it with your own protocol that determines "dim".
So you need to add an LDR and then MAP the analogreading to the required dim value (0=on, 128
is off)

I am trying to make a dimmer sketch for a 8 channel dimmer.


Wich can be controlled by openhab2 With mqtt
Hope that some one can help me with making it

Pepijn, Input from everyone welcome ofcourse, In the instructable there is to begin with a link to a
3 channel dimmer.
Arduino Controlled Light Dimmer: Page 32
With regard to mqtt from openhab that is possible.
The only thing you need is to add the pubsubclient and ethernet and subsequently send the dim
value as a number via MQTT

Hello, im trying to make the circuit to control a 1000W heater and want to see the output signal
using oscilloscope so i didnt put the load yet, but the TRIAC i used explode when connected the
circuit to the AC. My power grid is 220V 50Hz. I did changed a few thing on the circuit
- i took out the LED path since i think its only to indicate when the triac signal is sent to the
MOC3021
- i used BTA12-600B as TRIAC
- i used H11AA1 as optocoupler to detect the zero crossing
- i used pin 13 arduino mega at HIGH to substitute the +5V because i used all the other 5V pin
As for the code i only change the dimming value to 64 and put it in void setup().
I tried to check the parts(H11AA1, MOC3021 and the resistors) to find if they were faulty, but they
worked fine. I also checked the soldering to find if any of them shorted using multimeter buzzer but
found nothing. Im stuck on this and dont even know why its explode. Any help would be
appreciated.
Many thanks in advance.

There are only a few reasons why a triac would 'explode' and that is mainly too high a
voltage/amperage.
And as your triac didn't have a load, the only reason I can think of was that there is a faulty
connection in your circuit.
So the only thing I can advise is 'check and double check'
are you using a PCB?

im using blank PCB (the one with lots of holes). Yeah i probably missed something shorted. Going
to remake the circuit.
Thanks for the advice. good day.

We call that 'veroboard' :-)


yes, easy to make a mistake. I have made mistakes in circuits that I checked and rechecked 3-4
times and didn't see it, and then suddenly it is like 'how could i have missed that!!'

Good luck

Hi buddy, Thanx for the article. I want to control AC fan operating at 230V, 50 Hz.
I want to control the speed of fan at 4 steps. the speed should be applied by same button by
pressing repeatedly.
My question is this circuit is ok for that?
If I have to add snubber circuit, pls let me know which range of RC network should be added. and
pls guide me..

Arduino Controlled Light Dimmer: Page 33


How to use with Fan is I think the single most asked question here. Well, it is hard to say as there
are many different types of fans, but broadly speaking a triac is not ideal for an inductive load, but it
can be done.
With regard to the snubber, use e.g. a 33 ohm resistor and a 10-20nf capacitor. Beware that a
snubber sometimes can cause problems as well (e.g. keeping the triac on).
what you want can be done with this circuit (but a lot will depend on yr fan). to have that done with
one button is a matter of programming

hello, kudos and thanks to your work and continuous support for a 5 year old DIY :)
I am currently validating the “theory” for the Triac gate resistor, and I found an entry that seems to
contradict the TIC206 datasheet, namely Igm, peak gate current.
In your very nicely detailed section on that topic, “This is consistent with I_{GM} which is the peak
gate current of the TIC206.” Which almost implies that Igm is 1A while datasheet list +- 0.2A.
Depending on the interpretation, the gate resistor would then have to be changed to limit the triac’s
peak gate current to < 0.2A. Am I correct in my analysis?
Thanks again!

Thank you for your input. You refer to step13. Actually, as i state at the beginning of that step, it
was a contribution of a reader (Mali Lagunas).
At the time I checked the text ofcourse and as I understood it, it meant that there was enough
current available, but I might have misunderstood, and definitely the IGM of the TIC206 is not 1
amp
But you are right the gate resistor could (and maybe should) be enlarged

Hey @diy_bloke, I saw a comment where somebody mentions that he is


getting a warm temperature where the 30k resistors are, in my case 15k
1/2w since Im in a 127V grid, the temperature rises to 60 degrees in
this area, is this temp normal? or should it be ambient temp to the touch? Regards.

Arduino Controlled Light Dimmer: Page 34

You might also like