Arduino Controlled Light Dimmer: Instructables
Arduino Controlled Light Dimmer: Instructables
by diy_bloke
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
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.
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.
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.
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
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:
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
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
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
}
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.
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
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
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);
}
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.
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
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
String ip = "";
bool startsend = HIGH;
uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x07};
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)
}
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);
Serial.begin(9600);
while (!Serial) {};
Serial.println(F("dimmer"));
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);
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;
}
}
}
dim1=strPayload.toInt();
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 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);
}
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);
https://codebender.cc/embed/sketch:237008
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
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 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.
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
//------------------------------------------------------------------------
---------------------------------
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).
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.
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
//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
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) )
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??
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
Thanks a lot!
With your tutorial I was able to do this dragon ball lamp :)
//www.youtube.com/embed/sMglBAEWoIo
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() {
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?
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.
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
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).
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.
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
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
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.
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)
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.
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..
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