Go Down

Topic: AC Light Dimming (Read 20678 times) previous topic - next topic


I am working on trying to get this whole dimmer thing going...  I got a Triac hooked up to control a light on one of the Digital IO pins. (and only killed one ATMEGA in the process!)

The problem I am having now is getting the Zero Cross detection working to be able to fire the Triac at the right time.  I have been looking at http://www.andrewkilpatrick.org/blog/?page_id=445 and http://www.hoelscher-hi.de/hendrik/english/dimmer.htm  which have been a great help.  Thanks Guys!

I have some H11AA1 and 4N25 optocouplers.  What was thinking was to have the HOT 120 V AC go through 25ohm 1 W resistor (right now 4 100ohm 1/8w in parallel to test it out) to pin 1 of the H11AA1 and Pin 2 to AC neutral.  Then pin 4 to GND and Pin 5 as an input with a 10K pullup to 5V.

But...  its not working, and I think I might of fried the coupler.  Any ideas?  unfortunately I do not have a oscilloscope handy   :(

Thanks for any help you can give, I love learning this stuff.


I think you missed the "K" in the resistance stated in Andrew Kilpatrick's circuit. He has two 47K ohm resistors in parallel( 23.5Kohm equiv ) and not 25 ohm.  Try 4 100K ohm resistors in parallel.



Stupid me!  I just want to CrapShack and got some 1/2W 47K and it seems to be working now...  I will post the code when I am done to show how it is working.


Ok, so I was able to get the zero cross detection working.  Now I am trying to do the light dimming and I am stuck.  I know i need to fire the triac at a certain time past the zero cross.  There are 120 zero crosses per second (for 60Hz power) that gives 8333 micros between crosses. If I use 128 steps that is 65 micros per step.  So if I want 50% power I would need to fire the Triac at 65*64 micros after the zero cross??

That being said...  I would think this would work, but with no luck...

Code: [Select]

int dim = 0;

attachInterrupt(0, zero, CHANGE);

void loop()
 while(dim<128) {

void zero() {
 digitalWrite(dimmer1Pin, HIGH);
 digitalWrite(dimmer1Pin, LOW);


don't count on the freq being 60Hz and instead, keep track of the 0-xing period yourself either every 0-xing or for some reasonable period(every couple of minutes maybe ).  This way you're sure what your period is and then do the math to set what a percentage point is for that period.

I didn't look at the code but it seems your stated logic is right. For a 60Hz freq 1/60 is the full cycle period, so 1/2 that is the half cycle 0-xing period and it should be in the 8mS range. You divided your 0-xing period by the resolution(128) to get what part of the 0-xing period a 'tick' is. For a 50% cycle you'd want x number of ticks which when multiplied by the 'tick' period is closest to 50% of your 0-xing period.

Cool you got things close and closer to fully working.



I got some partial dimming going, but it seems to "lock up" after around the 20th step...  then no more light.  I was watching the serial out of what step it was on and then it just froze!  

Here is what I am currently working with


Once 'dim' is 128, your 'while' loop just spins because you never re-initialize the 'dim' value.



yes, I did fix that last night and still had no luck...  the light won't even get to the 128th step....  it locks after about the 20th.

Also, here is an updated schematic, I changed some resistor values, and am going to go try them now.  (I only have one of the AC Triacs hooked up).

I'll post some updated code soon.


maybe eliminate the interrupt and just use the standard loop() since the Arduino is running at 16MHz and you're dealing with 60Hz timing.

To debug, skip firing the triac for ever other period and append a string with data in critical sections. Print the string every few seconds during the unused period to be sure serial IO isn't causing you to miss anything. Hopefully you can print debug statements in less than 8ms.

You can also eliminate the triacs, pop in a red LED for the driver LED of the MOC part, and move driving the LED low to the beginning of the zero crossing detection. You'll have a PWM driven LED and you should see it dim or brighten depending on what your code is doing.



Hay Dougl, thanks for the help and support

So,  I managed to snag an old scope from work to verify a few things, and indeed the freq is 8.3 ish uS  AND the interrupt pin is outputting what I want it to...  However, there is one difference than the schematic.  I am using a H11AA1 instead of a 4N25.

Here are the picures if you are interested of the different scope output http://picasaweb.google.com/ryanjmclaughlin/NerdyStuff?authkey=3HlunapsF6k#

I am going to work on adjusting the code tomorrow.  I think I was firing the triac too late to dim...  will look into it tomorrow and report back.

I was trying to print some debugging to serial, but that is where I was having it "lock up" on me.


maybe try no serial output and see what happens. And throw in 4 LEDs you turn on at intervals of 128/4 to see how far the counter really gets.

the pulse on the scope looks good.


It's working!!!!!!!!  Woo hoo.   I will post code tomorrow but turns out the problem was a delay in another part of the program messing with the interrupt.


Ryan, what software are you using to draw your schematic?  Just out of interest.


Dec 31, 2008, 01:19 pm Last Edit: Dec 31, 2008, 01:20 pm by ryanjmclaughlin Reason: 1
Eagle.  http://www.cadsoft.de/index.htm

I'm using the freeware version right now.

Also, SparkFun http://www.sparkfun.com/commerce/tutorials.php has some good tutorials on Eagle


Here is the current code that got it all working...

Code: [Select]
 AC Light Control
 Ryan McLaughlin <ryanjmclaughlin@gmail.com>
 Thanks to http://www.andrewkilpatrick.org/blog/?page_id=445
   and http://www.hoelscher-hi.de/hendrik/english/dimmer.htm

int AC_pin = 10;  // Output to Opto Triac
int led = 3;      // LED for testing
int dim = 128;    // Dimming level (0-128)  0 = on, 128 = 0ff

void setup()                    // run once, when the sketch starts
 pinMode(AC_pin, OUTPUT);      // Set the light control pin as output
 pinMode(led, OUTPUT);         // sets the LED as output
 attachInterrupt(0, light, RISING);  // Attach an Interupt to pin2 (interupt 0) for Zero Cross Detection

void light()  // function to be fired at the zero crossing to dim the light
 int dimtime = (65*dim);  // eval the proper pause to fire the triac
 delayMicroseconds(dimtime);  // delay the dim time
 digitalWrite(AC_pin, HIGH);  // fire the Triac
 delayMicroseconds(10);       // pause briefly to ensure the triac turned on
 digitalWrite(AC_pin, LOW);   // turn off the Triac gate (triac will not turn off until next zero cross)

void loop()
 if(dim > 0) { dim--; } else { dim=128; }  // Simple fade out from full brightness

I am going to try to add some more features soon, and test it with an inductive load and see what happens.  Thanks for all your help.  I will try to post a video of the output of the phase control, its really cool looking!

Go Up

Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

via Egeo 16
Torino, 10131