AC Light Dimming

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 Andrew Kilpatrick 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 :frowning:

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.

Doug

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...

int dim = 0;

attachInterrupt(0, zero, CHANGE);

void loop()
{
  while(dim<128) {
    dim++;
    delay(10);
 }

void zero() {
  delayMicroseconds(65*dim);
  digitalWrite(dimmer1Pin, HIGH);
  delayMicroseconds(1000);
  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.

Doug

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.

Doug

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.

Doug

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.

Eagle. http://www.cadsoft.de/index.htm

I'm using the freeware version right now.

Also, SparkFun Tutorials - SparkFun Electronics has some good tutorials on Eagle

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

/*
  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!

Hi Ryan fantastic!

Your code is much simpler and cleaner than my buggy suggestion!

Im looking forward to entering the fun when my semester examproject is finished in a week.

What features are you planning?

/Niels

Thanks, I want to try to be able to write it to be able to just set the dim value. I am also still having problems with delays in the main program, then the interrupt won't fire.

It works great stand alone, but I need to do the testing when integrating it into a larger program that is doing other things.

Hi, Here is the current schematic. There is a bit of leway in what triac and opto-triac coupler you can use. Each output is for 10A, so I would not put more than 2-4A on each output maybe 600W, plus remember to keep wire gage in mind!

The "AC_out" should be connected to the "hot" of the load and the neutral of the load connected to ac neutral.

If there is enough interest I might make a PCB and sell a kit with 4 outputs.

Great work - but some questions...

I have been looking around over at http://diylightanimation.com/ thinking about next Christmas and Blinky lights on my house. Being an Arduino guy I wanted see what was possible using it. Your post is a godsend.

The sample code you posted uses a delay and one output - but your schematic shows 4 triacs. Do you use a if/else string to test some current counter to decide if one or the other Triac needs to be turned on? Like setting one of the timer's up to decrement a variable and test it in a series of if/else in the main loop?

In any event your example is quite a great start at what I want to do - which is something like the SSR4 @ Equipment - DiyLightAnimation

If I could your code to play nice with Lady Ada's WAV shield (doubt it) it would be a kewl project.

right now I only have dimming hooked up on one channel. Fir what I am working on I only need one channel to dim and 3 just on off so this will work great. My thought to do all 4 would be to do the math for the dim time in the main program. You would need to figure out which channel to dim first and do the additional delays after that. It would take some playing around with.

I did some more debugging on the code yesterday and will post the changes. The only problem I am still havving is speed. It seems that the delays are consuming all my program time and I cannot get the dimming process to run in the "background"

Thanks for the support!