Dimmer-Arduino

Switching an AC load with an Arduino is rather simpel: either a mechanical Relay or a solid state relay with an optically isolated Triac.
It becomes a bit more tricky if one wants to dim a mains AC lamp with an arduino: just limiting the current through a Triac is not really possible due to the large power the triac then will need to dissipate, resulting in much heat and it is also not efficient from an energy use point of view.

The proper way to do it is through phase control: the Triac then is fully opened, but only during a part of the sinoid AC wave.
One could an Arduino just let open the Triac for a number of microseconds, but that has the problem that it is unpredictable during what part of the sinuswave the triac opens and therefore the dimming level is unpredictable. One needs a reference point in the sinus wave.
For that a zero crossing detector is necessary. This is a circuit that tells the Arduino (or another microcontroller) when the sinus wave goes through zero and therefore gives a defined point on that sinus wave.
Opening the Triac for a number of microseconds after the zero crossing therefore gives a predictable level of dimming.

This circuit, it is an example.
0-crossing

Such a circuit is easy to build: The zero crossing is directly derived from the rectified mains AC lines – via an optocoupler of course- and gives a signal every time the wave goes through zero. Because the sine wave first goes through double phased rectification (see figure below), the zero-crossing signal is given regardless whether the sinus wave goes up through zero or down through zero. This signal then can be used to steer an interrupt in the Arduino. sine Opening the Triac is done via a tried and tested opto coupled Triac circuit. For the Triac a TIC206 can be used, but a BT136 (a bit cheaper)  would probably work as well. With regard to the MOC3021: that has a forward voltage of about 1.2-1.4 Volts and a trigger current of 8-15 mA. An LED has a forward voltage of about 2Volts. Presuming a 5V digital steering signal that gives a resistor value between (5-3.2)/0.015= 120 Ohm and (5-3.2)/0.008=225 Ohm, making 220 a decent choice. In reality an LED may have a slightly lower forward voltage and a 330 Ohm resistor was found to work as well. It is important NOT to chose an opto-Triac here with an inbuilt zero-crossing filter. The MOC3041 or the MOC3061 for that matter therefore is not usable in this circuit. The MOC 3021 is. NOTE: some people have experienced flicker as a result of a weak input signal. As the voltage drop over an LED may vary depending on the color. it is safer to replace the LED by a wire bridge and increase the 220 Ohm resistor to 330 or 470 Ohm With regard to the 30k resistors: The 1/2 Watt should do it as the resistors dissipate some 400mW. If you think that is too much, replace the 4N25 with a 4N33 and the two 30k resistors with two 100 k resistors. Be careful though in using sensitive optocouplers as the 4N32 as they will easily be fully in saturation.

This is the complete circuit of the dimmer
dimmer2

All one needs then is the software. Fortunately someone already has done the basic work. I just adapted the code slightly:

/*
AC Voltage dimmer with Zero cross detection
Author: Charith Fernanado http://www.inmojo.com
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)

 Pin    |  Interrrupt # | Arduino Platform
 ---------------------------------------
 2      |  0            |  All
 3      |  1            |  All
 18     |  5            |  Arduino Mega Only
 19     |  4            |  Arduino Mega Only
 20     |  3            |  Arduino Mega Only
 21     |  2            |  Arduino Mega Only

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
/* Due to timing problems, the use of ‘0’ can sometimes make the circuit 
flicker. It is safer to use a value slightly higher than ‘0’
*/
void setup()
{
  pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
  attachInterrupt(0, zero_crosss_int, RISING);  
// Chooses '0' as interrupt for the zero-crossing
}
// 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

  // 10ms=10000us
  // (10000us - 10us) / 128 = 75 (Approx) For 60Hz =>65
  int dimtime = (75*dimming);    // For 60Hz =>65     
  delayMicroseconds(dimtime);    // Off cycle
  digitalWrite(AC_LOAD, HIGH);   // triac firing
  delayMicroseconds(10);         // triac On propogation delay
                                 //(for 60Hz use 8.33)
  digitalWrite(AC_LOAD, LOW);    // triac Off
}
void loop()  {
 for (int i=5; i <= 128; i++)
{
 dimming=i;
 delay(10);
 }
 }

dimmer-print2

Print design. Mirrorred.

Dimmer-P1040650

On thing to consider is that if you are building a system in which you are not using a ready made PSU but rather supply your own PSU, built from a transformer and a rectifier, you could consider picking up the 0-crossing from the secundary side of the transformer.

A possible circuit could look like this:

voeding-big

E. ten Winkel

About these ads
This entry was posted in dimmer. Bookmark the permalink.

84 Responses to Dimmer-Arduino

  1. C says:

    Swell. I will try this. I am on 115V/60Hz
    You supplied the values for 60Hz but what to do with the 30K resistors? Should I double them or half them and what about their Wattage? Sorry, I am not so skilled

  2. Jos says:

    Greetings, I have a few (silly?) questions; I’m a math guy and (so) I know nothing about hardware; my brother built the thing and it seems to work but I don’t understand why; it’s probably because I don’t know how a triac works …

    From the code I can see that half a cycle takes up 10000us and the AC_LOAD pin is set to high for 10us somewhere during that cycle. My calculator shows that (10000us-10us)/128 == 78.046875us so wouldn’t 78us be a better approximation instead of 75us? Why is the (half) cycle divided in 128 parts? Wouldn’t 256 parts be more ‘natural’?

    My other question deals with the processor itself: during that delay can the processor still be interrupted or is it effectively dead during that delay period? (sorry about this, I couldn’t find an answer from Google anywhere).

    Thanks for reading and

    kind regards,

    Jos

    • Arduino says:

      Josh, apologies for my late reply. 78 uS may indeed be a better approximation, I have just picked a nice number close by

      wether 256 would be a more natural process is up to taste, even at 256 the speed of the change is more important than the size of the step. For my purpose steps 0f 128th seemed satisfying but there is no problem in taking smaller steps

      Thanks for your interest :-)

  3. Jos says:

    No problem; in the mean time I took a diferent approach: your solution makes the processor wait until it has to send a pulse to the triac; in my application that’s a waste of time so I used a timer that interrupts the processor again when the time has come to send a pulse. I divide the 0.01s in 256 parts and prescale the timer by /8; that makes 20.000 ticks per 0.01 second and works very well while my processor can do other things; near the ‘edge’ of the zero crossing interrupt I simply leave the triac on or off because the current is too low to properly switch it to an on state (this value differs per triac type).

    • Arduino says:

      That is in fact a good solution Josh. The example I gave was just that, an example. I have given a solution with a timer interrupt as well

  4. Nativepr says:

    Can I use a arduino to dimm 220v for a still?
    Thanks for your answer

  5. Andy says:

    Has anyone else had problems with flicker / bright flashes from the bulb?

    I can’t seem to get a smooth transition, even with the ‘dimtime’ variable set to a fixed value I get the same problems where I would expect a steady brightness.

    I will be heading to a local Hackspace on Sunday (where they have an oscilloscope) and will post what I find out.

    • Andy says:

      I’ve had a look at my 5V supply on a scope. The waveform is terrible. No wonder the arduino gets extra rising edges. Made my own 5V supply and it works great now.

    • Arduino says:

      I am happy you already found out what th eproblem is, yr 5Volt psu. Thanks for posting it

  6. Arduinodiy says:

    That is an interesting approach. My program was just a quick way to show the workings but if yoy set a timer interrupt that would be more efficient.
    Would you care to share your code?

  7. Jeff says:

    I found a great deal of trouble with “flicker/bright flashes” at around 40-50% power. The way to fix this is to ditch the diode bridge as a zero cross detector. Instead drop the mains through 150K resistance (I used 3*47K in series) to directly drive the opto input, but (most important) put a diode in parallel with the opto input, reverse direction. So now on the positive swing of the live, the opto input is “lit”, and on the negative swing the parallel diode catches the voltage on the opto input from going more than ~.7volts reverse polarity, and the opto input is “dark”. Now you get a nice square wave on the opto collector or “the zero crossing out”, changing 0-5v and 5v to 0v etc. exactly with mains zero crossing.

    In the code, change:
    attachInterrupt(0, zero_crosss_int, RISING);
    to:
    attachInterrupt(0, zero_crosss_int, CHANGE);

    Now “void zero_crosss_int()” is called each zero crossing as before.

    I used a 4n33 instead of a 4n25. You may need lower than 150K if you are using a 4n25. Also I found that I needed a 2.2K pull up resistor on the opto collector (10k is far to high) to get nice sharp rises and falls. Having nice sharp rises and falls on zero crossings is key to avoiding “flicker” or miss-firing.

    I adapted the code to run on interrupt using timer 1, rather than putting in a delay in the zero_crosss_int service code. Here is my arduino leonado test code:

    char inByte;// character for serial receive
    volatile int vary = 19980; //..this is OFF value..200 = 100 uS with an 8 prescale, 100*200 = 10ms… but int response takes 10us so use 19980
    int AC_LOAD = 3; // Output to Opto Triac pin
    int dimming = 10; // Dimming level (0-100) 0 = off, 100 = on
    void setup()
    {
    pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
    attachInterrupt(1, zero_crosss_int, CHANGE);
    // Chooses change as interrupt for the zero-crossing
    Serial.begin(115200);
    }
    // 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 setting
    // initialize Timer1
    TCCR1A = 0; // set entire TCCR1A register to 0
    TCCR1B = 0; // same for TCCR1B
    // set compare match register to desired timer count:
    OCR1A = vary;
    // turn on CTC mode:
    TCCR1B |= (1 << WGM12);
    // Set CS11 bit for 8 prescaler:
    TCCR1B |= (1 << CS11);
    // enable timer compare interrupt:
    TIMSK1 |= (1 < 0) {
    // get incoming byte:
    inByte = Serial.read();
    switch (inByte) {
    case ‘h’:
    dimming = dimming+5;
    if (dimming > 95) {
    dimming = 95;
    }
    Serial.print(“level is “);
    Serial.println(dimming);
    break;
    case ‘l’:
    dimming = dimming-5;
    if (dimming<10) {
    dimming =10;
    }
    Serial.print("level is ");
    Serial.println(dimming);
    break;
    case 'p':
    Serial.print("vary is");
    Serial.println(vary);
    break;
    case '3':
    dimming = 30;
    break;
    case '6':
    dimming = 60;
    }
    }
    vary = 200*(100-dimming)-20;
    }

    • Arduino says:

      Thanks for yr suggestion. I have not had the problem you describe, yet I will keep it in mind and perhaps it will be of use in the future. If you do not use a bridge obviously the frequency of the signal gets halved

  8. Jeff says:

    some of the code did not get posted right. a chunk was missing in the middle. Here is the code again:
    char inByte;// character for serial receive
    volatile int vary = 19980; //200 = 100 us with an 8 prescale, 100*200 = 10ms interrupt = off… but int response =10us so 19980
    int AC_LOAD = 3; // Output to Opto Triac pin
    int dimming = 10; // Dimming level (0-100) 0 = off, 100 = on
    void setup()
    {
    pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
    attachInterrupt(1, zero_crosss_int, CHANGE);
    // Chooses ’1′ as interrupt for the zero-crossing
    Serial.begin(115200);
    }
    // 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 setting
    // initialize Timer1
    TCCR1A = 0; // set entire TCCR1A register to 0
    TCCR1B = 0; // same for TCCR1B
    // set compare match register to desired timer count:
    OCR1A = vary;
    // turn on CTC mode:
    TCCR1B |= (1 << WGM12);
    // Set CS11 bit for 8 prescaler:
    TCCR1B |= (1 << CS11);
    // enable timer compare interrupt:
    TIMSK1 |= (1 < 0) {
    // get incoming byte:
    inByte = Serial.read();
    switch (inByte) {
    case ‘h’:
    dimming = dimming+5;
    if (dimming > 95) {
    dimming = 95;
    }
    Serial.print(“level is “);
    Serial.println(dimming);
    break;
    case ‘l’:
    dimming = dimming-5;
    if (dimming<10) {
    dimming =10;
    }
    Serial.print("level is ");
    Serial.println(dimming);
    break;
    case 'p':
    Serial.print("vary is");
    Serial.println(vary);
    break;
    case '3':
    dimming = 30;
    break;
    case '6':
    dimming = 60;
    }
    }
    vary = 200*(100-dimming)-20;
    }

  9. Jeff says:

    second attempt at pasting code also seems to have failed. this bit is missing:

    }
    ISR(TIMER1_COMPA_vect)
    {
    digitalWrite(AC_LOAD, HIGH); // triac firing
    delayMicroseconds(10); // triac On propogation delay
    digitalWrite(AC_LOAD, LOW); // triac Off
    TCCR1A = 0; // set entire TCCR1A register to 0
    TCCR1B = 0; // same for TCCR1B
    }

    void loop() {
    if (Serial.available() > 0)

    insert above exact after text TIMSK1 |= (1 < 0)

  10. Jeff says:

    message to the moderator…

    I see other bits of code removed from the paste, so even my correction of missing code also has some missing code. I don’t think this posting blog is good for code. There is text in the upload being filtered out and removed by the web app for some reason. Send me an email if you think others would be interested in the timer code.
    Jeff

  11. Nikoas says:

    Trying to use a timer instead of the delayMicroseconds but it keeps blinking.. Code is like this:

    int AC_LOAD = 3;
    volatile int dimming = 128;

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

    void loop()
    {
    }

    void zero_cross_int()
    {
    setTimer(65*dimming);
    }

    ISR(TIMER1_COMPA_vect)
    {
    digitalWrite(AC_LOAD, HIGH);
    delayMicroseconds(8.33);
    digitalWrite(AC_LOAD, LOW);
    }

    void setTimer(int microseconds)
    {
    TCCR1A = 0; // set entire TCCR1A register to 0
    TCCR1B = 0; // same for TCCR1B

    TCCR1B |= (1 << WGM12);

    TCCR1B |= (1 << CS11);
    TCCR1B &= ~(1 << CS10);
    TCCR1B &= ~(1 << CS12);

    OCR1A = microseconds*2 -1;

    TIMSK1 |= (1 << OCIE1A);
    }

    Anyone has any ideia?

    Thank you!

    • Arduino says:

      I can’t immediately see a problem with the code. Maybe someone else will

    • Arduino says:

      blinking may also be causef if the LED on the entrance takes away too much of a voltage drop. Replace the LED by a wire bridge and increase the value of the 220 oghm resistor to 330 or 470 ohm

  12. chethan says:

    Hi , I want to buy this module , is it available in india ?

    • Arduino says:

      I am not selling any module che than. The one I linked to is mailorder

      • chethan says:

        Hi, if it is not available then I will try to build my own . Could you pls share the complete circuit schematic … ? .. I need to build in the india so my AC supply will be 230v 50Hz …

      • Arduino says:

        Che than, the complete circuit is in this article. In case it wasn’t clear, you need the circuit that u will see immediately above the program listing that has the 4n25, the moc3021, the bridge rectifier and the triac. Ad you can see a rally simple circuit. You will find the print design below the program listing and a picture of the components on the PCB directly below that. The values given are for 230 volts. Don’t hesitate to ask if you need to know more

      • Arduino says:

        not sure what you mean Chethan. what part of the circuit are you missing?

  13. Indra says:

    Hi, I have built this circuite my own , and now I want to program my atmel 8051 controller to receive drive the Zero Crossing signal , Dimmer SIgnal in .
    What I understood from the above program is , Connect these points to the micro controller pins , and use the above program . Zero Crossing signal o/p work as a interrupt to the controller and based on this it drives the Dimmer Signal out put ..
    Can I use above program directly with only giving proper pin detail in the program ..

    • Arduino says:

      Indra, yes you are understood wel. You need to connect the zero crossing to an interrupt of the microcontroller annd then have an output pin of the microcontroler switch the optoisolator/triac

      However, the program in itself will probably not work immediately as it is not pure C, but if you have a C compiler for yr 8051 an dyou use this program, you will get pretty far, by adapting the pins and making the language a bit more pure C.

      If you get it to work, I would be very interested for you to share it :-)

      Thank you for yr comment

    • Arduino says:

      you may want to check here: http://www.linuxforturkey.com/lamp_dimmer/lamp_dimmer.php for some code.
      I know that many years ago i wrote some code to do this for an 8051, even in assembler, but after about 20 years I have lost that code and I am not working with 8051′s anymore

  14. indra says:

    Thanks for the info , below is the code which I have written , let me test and post the result
    #include

    /*=============================================================================
    =============================================================================*/
    int dimming = 0;

    void delayMicroseconds(unsigned int i)
    {
    unsigned int j,k;
    for(j=0;j<=i;j++)
    {

    for(k=0;k<256;k++);
    }

    }

    void delay(unsigned int i)
    {
    unsigned int j,k;
    for(j=0;j<=i;j++)
    {
    for(k=0;k65
    delayMicroseconds(dimtime); // Off cycle
    P1 =0×01; // triac firing
    delayMicroseconds(10); // triac On propogation delay
    //(for 60Hz use 8.33)
    P1 =0×00; // triac Off
    }

    void ex0_isr (void) interrupt 0
    {
    Drive_Trac(); // Increment the count
    }

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

    /*———————————————–
    Zero Crossing Interrupt
    ———————————————–*/
    IT0 = 1; // Configure Zero Configure interrupt 0 for falling edge on /INT0 (P3.2)
    EX0 = 1; // Enable EX0 Interrupt
    EA = 1; // Enable Global Interrupt Flag
    /*———————————————–
    for Triac drive P1.0
    ———————————————–*/
    P1 = 0×00;
    /*———————————————–
    Wait forever.
    ———————————————–*/
    int i;
    for (i=5; i <= 128; i++)
    {
    dimming=i;
    delay(10);
    }
    while (1)
    {
    }
    }

    /*=============================================================================
    =============================================================================*/

  15. Indra says:

    Hi, I tried my board with the code which I have written for 89V51RD2 .
    I receive the interrupt from Zerocrossing output pin …

    But load(bulb) which I am connected is not varying, its always ON .. if I remove the triac input signal also my load is ON”.. Is TRIAC is fine ?

    Since I did not get 30k(1.2 watt resistor) , I connected 33k(1/2watt) all other or normal resistor ..

    here is my delay and ISR code

    void delayMicroseconds(unsigned int i)
    {

    for(j=0;j<=i;j++)
    {

    for(k=0;k<256;k++);
    }

    }

    void ex0_isr (void) interrupt 0
    {
    P0 =0×01; // triac firing
    delayMicroseconds(10); // triac On propogation delay

    P0 =0X00;// triac Off
    }

    • Arduino says:

      Indra, if you disconnect the Input to the optocoupler and yr triac is still on then obviously either yr triac has had it or yr optoisolator has a short. If you have used an ic foot for yr optoisolator I suggest you take out the chip and try again by just applying mains voltage again. If yr triac is off, your optoisolator has a short. If it is still on I expect a faulty triac

  16. indra says:

    Hi, Since I did not put any ic foot ,, I will try to replace the IC and check …

    I have some small question :
    I need to support four dimming Level for my load(bulb) .

    will be changing the Delay between triac ON and OFF work well ?

    Like below .

    //for Level: 0
    P0 =0×01; // triac firing
    delayMicroseconds(8); // triac On propogation delay for Level: 0
    P0 =0X00;// triac Off

    //for Level: 1
    P0 =0×01; // triac firing
    delayMicroseconds(10); // triac On propogation delay for Level: 1
    P0 =0X00;// triac Off

    //for Level: 3
    P0 =0×01; // triac firing
    delayMicroseconds(12); // triac On propogation delay for Level: 2
    P0 =0X00;// triac Off

    • Arduino says:

      Better to first desolder one pin of the resistor.
      With regard to the 4levels you have to set those by setting the delay from the zerocrossing

  17. indra says:

    Hi, the problem was with optoisolator , I desolder 1k resistor .. now its not ON .. So as you suggested I will try replace with new …

    With regard 4levls , I did not understand “delay from the zerocrossing” .. Is it adding some delay in the interrupt routine which I get for the zero crossing output ..

    as per my code below , whenever I get the interrupt , in the interrupt routine I do the traic firing and OFF ..
    So where to add the dealy in order to have diffrent dim levels
    void ex0_isr (void) interrupt 0
    {
    P0 =0×01; // triac firing
    delayMicroseconds(10); // triac On propogation delay

    P0 =0X00;// triac Off
    }

  18. Arduino says:

    Hi Indra, good that you pinpointed the problem. Still, make sure that there werent any accidental shorts between the tracks from the optoisolator.

    With delay from the zeorcrossing I mean that the lightlevel of the lamp depends on where in the 50Hz (or 60Hz) cycle you send a pulse to the TRIAC.
    In a 50Hz cycle the time between two zero crossings is 10ms (8.33 in a 60Hz).
    So if you want to have yr lamp at half power, you need to light the TRIAC halfway through that cycle, which is 5 ms after the zerocrossing.
    If you want yr lamp at 25% you need to wait for 7.5ms after the zerocrossing before you trigger the TRIAC and if you want yr lamp at 75% strength you need to trigger the TRIAC after 2.5ms.
    (technically for the 25% and 75% it is an approximation as the area under the curve is not liniair, but it is close enough for illustration of the proces).
    You have to add that delay in your program before you fire the TRIAC. Where exactly is up to you, but what I have done in my Arduino code is that in my interrup routine, I multiply a stepvariable with a steptime. Subsequently I set that variable in my main loop.
    Since you only want 4 levels, you could set a bigger steptime e.g. 2.4ms and multiply that with a variable.
    Subsequently in your main loop you set that variable to say 1, 2, 3 or 4

    You could also set the total dimtime directly in your mainloop as follows:

    interrupt {
    delayMicroseconds(dimtime);
    P0=0×01;
    delayMicroseconds(10); //propogationdelay
    P0=0×00;
    }

    loop {
    IF condition dimtime=9000;
    ELSE IF condition dimtime = 7000;
    ELSE IF condition dimtime= 5000;
    ELSE dimtime=2000;
    }

    I have chosen 9000 rather than (10000-10) because the 4N25 that gives the zerocrossing is not ideal in a sense that it does not give a very narrow pulse. For normal dimming purposes that is not a problem, but it could give some timing issues when you regulate close to the edges of your cycle

    Hope that helps, good luck. dont hesitate to ask if you need further help

  19. Indra says:

    Hi,
    Thanks for the detailed information . I tried as you said above .

    instead of the dimming at constant level .. My load(bulb) blinks at the rate which I added as dimtime …

    this is my delay code .
    void delayMicroseconds(unsigned int i)
    {

    for(j=0;j<=i;j++)
    {

    for(k=0;k<256;k++);
    }

    }

    Isr(){
    delayMicroseconds(2000);
    P0=0×01;
    delayMicroseconds(10); //propogationdelay
    P0=0×00;
    }

    Pls help if I have made any mistake in the setting proper delay ..

    • Arduino says:

      Indra I am currently travelling. I all get back to you

    • Arduino says:

      As I am on mobile I can only give a short reply but frankly I do not understand your code. If ‘i’ is yr dim time then what is the function of the 2000 and what is the function of ‘k’?
      I am not sure how yr delay is called by what yr function seems to do is to just repeat the 2000microsecond delay a number of times. If it is the zero crossing that calls this then maybe the first time us OK but after that there is no proper relationship with the zero crossing anymore and you even pass into the next phase of the cycle. Seems to me that j and k serve no function at all but that you need e.g. i * 2000 in which i is between 0 and 4.

      Just look at the example i gave in my reply of Oct 11, 2013 @ 09:24:11 That shows the structure you have to follow. Your code -sorry to say- is completely wrong, it will make yr TRIAC go haywire

  20. Indra says:

    Hi , Thanks for your help .. I am able to get four DIM level ..
    But suddenly load flickers .. as you had suggested I replaced 220ohm with 440ohm and 1kohm , but still I get the flicker during normal operation ..
    Pls suggest how to overcome this flicker ..

    Since my 8051 out put pin was not able to drive the MOC3021 , I used a tip122 to drive .. as below
    https://lh3.googleusercontent.com/-OHBImWUiKVM/UlwtYFIGwgI/AAAAAAAAABo/_o4aIjLk8ts/w776-h458-no/test.png

    And below is my complete code

    /* Dimmer.C – Keil MCBx51 Evaluation Board with 80C51 device*/

    #include
    #include

    int dimming = 0;
    unsigned int j,k;

    void delayMicro(unsigned int us)
    {
    for( ; us>0 ; us–)
    {
    _nop_(); // if crystal is 11Mhz crystal then delay is ~1 microsecond

    }
    }

    void delay(unsigned int i)
    {

    for(j=0;j<=i;j++)
    {
    for(j=0;j<=256;j++)
    {
    for(j=0;j<=256;j++)
    {
    }
    }
    }
    }
    void Drive_Trac(void)
    {

    delayMicro(dimming);
    //delayMicro(550);
    P0 =0xFF; // triac firing
    delayMicro(10);
    //(for 60Hz use 8.33)
    P0 =0×00;// triac Off
    }

    void ex0_isr (void) interrupt 0
    {
    //P1 = ~P1;
    Drive_Trac(); // Increment the count
    }
    /***********************************************************?
    void main (void)
    {
    //P1 =0×00; // triac firing
    P0 = 0×00;

    /*———————————————–
    Zero Crossing Interrupt
    ———————————————–*/
    IT0 = 1; // Configure Zero Configure interrupt 0 for falling edge on /INT0 (P3.2)
    EX0 = 1; // Enable EX0 Interrupt
    EA = 1; // Enable Global Interrupt Flag
    /*———————————————–
    for Triac drive P1.0
    ———————————————–*/

    /*———————————————–
    Wait forever.
    ———————————————–*/

    while (1)
    {
    dimming=380 ; //Level 1
    delay(9999);
    dimming=450 ; //Level 2
    delay(9999);
    dimming=500 ; //Level 3
    delay(9999);
    dimming=550 ; //Level 4
    delay(9999);

    }
    }

  21. Arduino says:

    Hi Indra, thanks for your code. But to be frank, it is hard to say. I keep giving an example that as far as I can see is just simple and should work
    Your routine Drive_Trac seems completely unnecessary as you can set that in your interrupt routne. Now you just have yr interrupt routine call another routine. Your delay function seems a bit too complicated and can be simplified. P0=0×FF ofcourse switches on the entire port but as I do not know on which pin yr TRIAC is, I left it as such, but I think you could write e.g. P0_1=1.
    I am not a C programmer but why dont you try something like this and see what happens:

    /*===================================================*/
    void ex0_isr (void) interrupt 0
    {
    int dimtime=(75*dimming);
    delayMicroseconds(dimtime);
    P0=0×FF;
    delayMicroseconds(10); //propogationdelay
    P0=0×00;
    }

    void msdelay(unsigned int value){
    unsigned int x,y;
    for(x=0;x<value;x++)
    for(y=0;y<1275;y++);
    }

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

    /*———————————————–
    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 = 1; // Configure interrupt 0 for falling edge on /INT0 (P3.2)
    EX0 = 1; // Enable EX0 Interrupt
    EA = 1; // Enable Global Interrupt Flag
    P0 = 0×00; //all pin of PORT0 declared as output
    /*———————————————–
    Wait forever.
    ———————————————–*/
    while (1)
    {
    for(i=5;i<128;i++){
    dimming=i;
    msdelay(10);
    }
    }

    /*===================================================*/

    In C programs you cannot be sure of delay, cause it depends on compiler how it optimize the loops as soon as you make changes in the options the delay changes.

    you will have to use Timers for making exact delays….. it does not matters whether u need delays of ms , us or even seconds…

    below is a function of 1 second using timers…..

    // the idea is to make a 50ms delay and run it 20 times as 20x50ms= 1000ms= 1sec

    delay_1s() // timer of 1 sec
    {
    int d;
    for(d=0;d<=20;d++)
    {
    TMOD=0×01;
    TL0=0xFD;
    TH0=0x04B;
    TR0=1; // start timer.
    while(TF0==0); // run until TF turns to 1
    TR0=0; // stop timer
    TF0=0; // reset the flag
    }
    }

  22. indra says:

    Hi , Thanks your patience and nice reply … I tried with oscilloscope to cross check the proper delay .. seems like I have set the proper delays

    Now I made a program , wherein User will send his desired level ( as a UART commands , like SET L1 , SET L2 etc ) .. Its working well .

    But still I have some problem , i.e when the load is at some level , it glows properly until it receives the next UART command from the user .
    During at some level the load suddenly blink ( sudden blink) to high level and come backs to same level .. This is not related to my delay or period , it happens irregularly, and quite often . Is it because of some problem in my circuit ? I tried changing all the resistor values but still this continues ..

    • Arduino says:

      I dont think it is a fault in yr circuit, might be spikes on yr psu. If you share yr code with me I will check.
      Try and run the code that I gave you and see how it behaves

  23. Maha says:

    hello,
    i connected the dimmer circuit but i used MOC3020. does it suitable or I have to use 3021 ??

  24. Mali says:

    Greetings and thanks for sharing. It is not clear to me how do you limit the current going into the Triac’s gate. It’s a 1K resistor (AC to to Moc3021), which would let approx I_G=215mA go through, i.e., -220+V_R+V_{TM}+T_{GT}=0, where R=V_R/I_G. Both the triacs you mentioned have a way lower gate sensitivity than this. Is it probably 10k? Thank you

  25. Arduino says:

    True, sometimes higher values of the resistor are used and I think I even have seen 68 or 100k. However, there isn’t 220 volt over the triac as it is in series with the load. That probably isn’t a very high resistance, depending on the wattage of the load so yr calculation comes close for those moments the triac is off. The 220 volt is however an average. If you want to switch on the triac close to the zero crossing, the numbers are different.
    Rather than to start calculating I have chosen an existing design that I know worked well. I am sure though that a higher resistance would also work. I may try once what the max resistance could be. If you find out I wld be happy to hear.

  26. Tony says:

    What’s the max current load of this? I’m designing a control for a 5500W heating element at 240VAC (~23Amp max) that I want to be able to adjust from 0V (off) to full power (on) at 240VAC. The 240VAC PSU has two hot lines at 120VAC 180deg out of phase. Is this the sort of circuit that should be used for this application? Do I have to use different components with a higher current rating?

    • Arduino says:

      Tony, I am not proficient enough in 2 or 3 phase ac to safely answer this question. In principle this circuit is suitable for any load as long as the right triac is chosen. You say you have 2 power lines 180 degrees out if phase but do I understand you also have a neutral feed thus 3 wires going to yr device? If it is only two lines then the only thing that counts is the fact there is a zero crossing. If you have 3 lines than it is a bit more complicated but yes in principle 2 circuits could be the answer however I do not have experience with that. Maybe someone else here can help

  27. Mali says:

    Thank you for your reply. After some readings I have finally understood the criteria to choose the value of the resistor R_G. When placed in this circuit, it will have two main effects:
    a) It will limit/provide the current going into the gate of the triac (I_{GT})
    b) It will cause the voltage to drop when the triac is on (V_R)

    The lowest value this resistor may have (for 220 V AC) is R=220*sqrt(2)/I_{TMS}, where I_{TMS} is the maximum peak current allowed in the photocoupler’s phototriac. These are surge values, thus they are transient and account for a limit before breakdown. Therefore in your circuit R would be R=220*sqrt(2)/1=311.12 or 330 ohms, since the MOC3021′s I_{TMS}=1A. This is consistent with I_{GM} which is the peak gate current of the TIC206. In your schematic you use 1K which would limit the current to 311mA.

    This “surge” case may take place only when a pulse is received by the phototriac and it is able to conduct I_{GT}, and of course for a line value of 220*sqrt(2). Charge will then accumulate in the triac’s gate until V_{GT} gets build up and the the triac gets activated.

    In quadrant I, ( V_{GT} and A1 are more positive than A2) in order for sufficient charge to build up and V_{GT} in the main triac to bee reached, the voltage across the triac must equal V_R+V_{TM}+V_{GT}
    Of course V_R=I_{GT}*R . Commonly, V_{TM}+V_{GT} will both account for approximately 3V (datasheet). At the same time, the resistor must provide sufficient current to the Triac’s gate, let’s say a minimum of 25 mA (sensitivity of the Triac), thus

    V_{triac}= 330ohms*25mA+1.3V+1.1V=10.65V and
    V_{triac}= 1k-ohms*25mA+1.3V+1.1V=27.4V (the value in your circuit)

    Which is the voltage needed to activate the triac. Therefore, the smallest the resistor the less voltage is required to switch on the main triac. What goes on afterwards is mainly that there is a voltage drop across A1 and A2 and therefore the phototriac voltage and current will drop causing turn-off state (of the phototriac). The main triad will be kept switch on if the holding current I_H is respected. When the load current is below I_H, the main triac is switched off until a pulse from the photodiode is emitted again in order to polarize V_{GT} and build the required charge in the next cycle. Q1 and Q3 are the quadrants for this setup. Cheers.

    • Arduino says:

      Thanks Mali for sorting it out and writing it down clearly. Seems to some extend you may have read the same articles at I did and that made me decide to just use a tried and rested design :-)

  28. franssenrogier says:

    Hi,

    I’m a rookie programmer/arduino user and I’ trying to set up this dimmer to let the light fade in/out. I got the dimmer itself set up properly and it works perfect with the code above.

    Now I’ve been trying some things myself in the code but I keep getting the ‘name lookup of ‘i’ error message when I verify it.

    I only adjusted the loop of the original code like so:

    void loop() {
    int x = 1;
    for (int i=5; i > -1; i = i + x){
    if (i == 128) x = -1;
    }
    {
    dimming=i; // Line of error message
    delay(10);
    }

    }

    I looked up the error code on the web and I found out it has something to do with a ‘i’ too much or something but I figured the ‘i’ for dimming is still the same as the ‘i’ in de for loop.

    • Arduino says:

      This error means that u make multiple declarations of i. Where u do this is not immediately clear to me, but your code looks a bit odd. As it is not immediately clear to me what you are trying to achive it is hard to say what you need to change.
      The problem however is in the ‘;’ after your ‘x=-1′ in your if statement There should not be a semicolon after an if statement. There should be a semicolon after your action which is defined by brackets around it
      If x=-1 is the action following your condition, there should be brackets around it. Where your end bracket should go depends on what you are trying to achieve. However it seems you have just randomly added an if statement without taking the structure of the existing “For” loop into consideration.
      Not sure what you are trying to achieve, but removing the semicolon makes yr error go away, but then ofcourse asks for a semicolon. removing ‘x=-1;’ in total makes the code run error free.
      So, ergo you have structured your if condition wrong. An if condition should look like this:
      If (condition) {action;}
      Whereas you have:
      If (condition)something;
      existing action of FOR loop

    • Jos says:

      Your variable ‘i’ is declared in a for-loop, so it’s local to that loop, i.e. it can’t be used outside of that loop; the remedy is simple: declare it outside of the loop, e.g. where you declared ‘x’ is a fine place.

      kind regards,

      Jos

  29. Mali says:

    On the contrary, thanks to you for sharing. This was my first time posting and it was very helpful. Happy designs.

  30. bigWcharly says:

    Thanks a lot for sharing this! Also the comments and support you give are really helpful!
    @Mali, also thanks to you for your detailed explanation on the value of the resistor between the moc and triac :-) If I understand correctly, the smallest value is better as then the voltage accross the triac is lower and less power will be dissipated? Is there a chance that surge currents will break the R with lower value?

    I’ve seen similar circuits where they also add a resistor between the triac’s gate and T1. Does this sound familiar to anyone? Why would this be needed? I’ve been breaking my head about it, but the only reason I can think of is that it is only needed if the max gate current is lower than the moc’s max terminal current? So typically not needed then … Can anyone confirm?

    Now, I’ve built the circuit with R 330 and also a similar resistor between G and T1. I notice that when I connect the circuit to the mains, the lamp flashes and even my arduino picks up false interrupts (I use an additional interrupt to control the lamp with a switch). Anyone noticed this as well? How can I resolve this? The load is purely resistive (traditional light bulb).

    Looking forward to your response, many thanks again :-)

    • Arduino says:

      Thanks bigWcharley
      Mali’s comment was useful indeed. I basically chose a value that is safe for the MOC and the gate.
      I know the circuit you refer to, I always presumed it was to get a tighter definition of the voltage on the gate coz it makes a voltage divider but I am not sure. Youe explanation could be true as well
      With regard to the flickering, does this only happen when you add that extra resistor?
      The flashing of the lamp maybe caused by your arduino picking up false interrupts, but why it picks up these (i.e. what is the reason) i dont know. Perhaps someone else kmnows

  31. amateur says:

    Hello,
    I do not understand what have I done but it working.

    //—————————————
    int AC_LOAD = 3;
    int dimming=8;

    void setup()
    {
    pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
    attachInterrupt(0, zero_crosss_int, RISING);

    pinMode(4, INPUT);
    digitalWrite(4, HIGH);

    pinMode(5, INPUT);
    digitalWrite(5, HIGH);
    }
    void zero_crosss_int()

    {
    int dimtime = (75*dimming); // For 60Hz =>65
    delayMicroseconds(dimtime); // Off cycle
    digitalWrite(AC_LOAD, HIGH); // triac firing
    delayMicroseconds(10); // triac On propogation delay //(for 60Hz use 8.33)
    digitalWrite(AC_LOAD, LOW); // triac Off

    }
    void loop() {

    if (digitalRead(4)==LOW) dimming++;
    delay(10);
    if (digitalRead(5)==LOW) dimming–;
    delay(10);

    if (dimming>120) dimming–;
    if (dimming<5) dimming++;

    }
    //——————————————————————

    Thanks for this project, kind regards

  32. scott2512 says:

    Will someone be able to give me a list of all the parts i need to build this please?

    • Arduino says:

      Scott, I am a bit surprised as it seemed obvious from the circuit, but maybe i wasnt clear:
      resistor 10k, 1 k, 220R, 30k, 30k
      4n25
      MOC3021
      Bridge rectifier
      TRIAC such as TIC206
      LED red

      You could skip the LED and make the 220R resistor a 470 R

  33. Tom says:

    Hello,

    Great post. I cannot make it work, tho. I believe my problem is with zero crossing detection (when I try to set +5V to triac manually the light lights up correctly, so circuit for this works just fine).

    For bridge rectifier I use DF08, is it proper BR for this? As you mentioned above I ofcourse use 4n25 together with two 30k resistors (230V 60 Hz).

    I tried to monitor serial port (it should display ’1′ every interrupt), and I got result only when plugging 230V cable and unplugging it.

    Sorry for my newbie question but I’m really new to electronics.

    Thank you in advance for your reply,
    Tom

    • Arduino says:

      The dfo8 should be ok but just dou le check the pin layout to see if it is compatible. Can u measure any output on the zero crissing pin?

      • Tom says:

        As I mentioned before when I try to measure output on zero crossing pin I get +5V only when I’m plugging and unplugging 230V, otherwise nothing happens. I checked all the pins bunch of times and all seems to be connected fine. As I can see you are using double phased rectification, DF08 is single phase, does it matter?

        Maybe I should post photo of circut on breadboard if it’s not too much for you?

      • Arduino says:

        Yes go ahead and post that. The rectifier shld be a bridge. I had the impression the df08 is a bridge. Is it inserted the right way? Is the 4n25 inserted the right way?

  34. Tom says:

    Yes, both 4n25 and df08 are inserted the right way. Could you tell me what BR you used in your case?

    Please send me an email, as I cannot put photos here, I will send them back in reply to your email.

  35. Tom says:

    DF02 is also single phased as I can see in datasheet. I just sent you an email

    • Arduino says:

      got that one and looking at it. Is that really a 4n25? I cant really make out the number

      • Tom says:

        Yes, this is 100% 4n25. It has LTV 4N25 written on it, which I believe LTV is code of producer (Lite-On)

    • Arduino says:

      I have a datasheet. Not sure what the single phased would refer to as it is a normal bridge rectifier. Anyway, your setup seems ok.
      Have you used the program exactly as I provided it (with INT 0)?
      What I like you to do is to measure the voltage on the primary side of the optocoupler.
      If your setup is OK, your software is ok, your wires are OK, then I start to think maybe your 4N25 is not OK.
      After you do the measurement can you exchange it for another one?

      • Tom says:

        Ok, I just measured what’s going on right after BR, and it gives no votage. That’s where the magic happens – as I mentioned before only when I plug in and plug out the 230V cable I get some results – when I tried it with multimeter I see that even when showing 0 when I plug in or out the cable multimeter shows -0.00V for a little while.

        In fact I don’t know how is it possible because I already changed DF08 two times. I changed it again and… It works. First one I just know I broken, second one seemed fine!

        I will finish the circuit for dimming and will let you know if everything works ok.

      • Arduino says:

        ok seems you got the problem there. Odd, but I have had components come right from the shop and be faulty too. cant hurt to check

      • Tom says:

        Yes, it works fine now. I have other problem now, and it maybe something in the code. I’m trying different values for dimming:

        When I set int dimming to 25 it seems to have max power, when I set it to 23 it starts blinking badly. When I set dimming to 128 it has about 1/2 power, 149 is value that lights it just a little bit.

        It seems like proper values are between 25 and 149. Why is that?

      • Arduino says:

        Do you mean the values for ‘i’ ??
        If so that would surprise me. The limit values are theoretically 0 and 128 because the software takes 128 steps of 75 microseconds (for 50Hz). That is an approximation as it could theoretically go to 133 (as 133.3*75 is 10000us =100Hz).
        Poland -where you are- has 50 Hz frequency so the 75 us in the software should be right. Are you sure you didnt by accident select 60Hz?? In that case at 128 your timing would be 8320 us and thus the lamp would not be fully off.
        If indeed you would have it at 60 Hz then at 149 your timing would be 9685, which is indeed almost off.

        If indeed you correctly selected 50Hz then a ‘dirty’ psu may cause havoc as that can couse extra spikes that trigger the interrupt.

        So first I would check yr software to see what timing you have selected.

  36. Assaf Laufer says:

    Hi Arduino, you wrote:

    On thing to consider is that if you are building a system in which you are not using a ready made PSU but rather supply your own PSU, built from a transformer and a rectifier, you could consider picking up the 0-crossing from the secundary side of the transformer.

    Is it possible connect to 4n25 and 1k directly to BR1 and thus to eliminate BR2?

    • Arduino says:

      Dear Assaf, My answer is ‘it depends’
      You cannot pick up the signal directly from BR1 because there is a smoothing capacitor over the + and – lines and therefore there is just no zerocrossing signal left anymore.
      What you could do is to take it off BR1 and then use a diode before you feed the voltage to the smoothing capacitor.
      However, as the bridge is a cheap component, I decided to just keep it clean and separate the two signals completely.
      I trust that answers your question :-)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s