Solid state relay, PWM sync with zero crossing detection

Hello. I have a project, where I need to use solid state relays(SSR) as light dimmer. I have 8 SSRs of them and I need to drive them with PWM signal. Mains voltage 230V, 50Hz. I know that I need to know zero crossing and sync my PWM output with it. I already have schematic for ZC detection and tomorrow I am going to buy parts I need. Arduino is Mega1280. What would be the easiest code for that? I have been looking for different code examples, but they look complicated. Do I need to sync internal timers, or can I use some easier way?

have 8 SSRs of them and I need to drive them with PWM signal.

No you don't. It will do you no good if you do.

Once a SSR is turned on you can't turn it off until the end of the cycle, so a PWM signal is of no use to you.

All you need to do is to give a pulse on the gate after a delay once the zero point is reached. The length of that delay determines for how much of the cycle the SSR conducts and hence the power in your load.

When I get my zero crossing signal, how should I send a pulse? And how long delay should be? And I can't use delay() function, because it halts all the code. What would be the options?

Ragnar: I have a project, where I need to use solid state relays(SSR) as light dimmer.

First, there are zero crossing type, and non-zero-crossing type SSRs.

If you want to delay for a known amount of time before getting an interrupt, you should use one of the timers (such as timer2 of the atmega328.) You can set the timer to count from 0 to 255 in 0.5/60 seconds (about 8 milliseconds) and then set the timer count target to the delay you want, and set it up to stop and interrupt when it reaches the compare target. Check out the data sheet: http://www.atmel.com/dyn/resources/prod_documents/doc8025.pdf (chapter 18) I don't think there's a direct Arduino-style library to do this, but it's not that hard to set up with the registers directly.

Third, perhaps you should try a pair of MOSFETs instead? They will happily switch on and off no matter where on the waveform you are. You can even run PWM at a rate other than the line rate.

Outgoing stock is 85 cents each: http://search.digikey.com/us/en/products/STP13NK50Z/497-7504-5-ND/1852503 Current models are about 1.37: http://search.digikey.com/us/en/products/AOT10N60/785-1191-5-ND/2353856

Note that you need two coupled head-to-head, because a FET will conduct like a diode in the "non-switched" direction. You need heat sinks to get to the rated amperage -- but typically, that's the same for a SSR.

I already have random-fire SSRs. Can I use 1 timer for 8 output? Which timer on Mega1280? Any code example?

Can I use 1 timer for 8 output?

Only if you want all channels to be at the same power.

Third, perhaps you should try a pair of MOSFETs instead?

On mains AC!!!

Most people use an SSR that contains a phase angle delay circuit, that you can feed with PWM as all it does is alter the brightness of the LED feeding the phase angle delay circuit.

How can I use 8 SSRs on different levels? I need 8 timers? Does Arduino have that many?

What it I convert AC to DC. It should be okay for tungsten lamps. Then, can I feed SSRs with pure PWM signal?

How can I use 8 SSRs on different levels? I need 8 timers? Does Arduino have that many?

You need 8 different delays, one way to get a delay is with a timer. The arduino only has three timers. One way to get a delay is to use a timer to generate an interrupt. The ISR (Interrupt Service Routine) increments a counter and checks which of the 8 delays matches the current count. If one (or more) is equal then that pin is set high, if not it is set low. As you said:-

I have been looking for different code examples, but they look complicated.

Maybe you are beginning to understand why.

What it I convert AC to DC. It should be okay for tungsten lamps. Then, can I feed SSRs with pure PWM signal?

DC at such a high voltage is dangerous because the electric shock it produces paralyses you and you feel it sticks to your hand unable to draw it away. You will also need smoothing capacitors that can handle the voltage and ripple current, these will be very big and very expensive. In short, don't go there.

Why not just use a proportional SSR you can feed PWM directly into and forget trying to do a DIY zero crossing detection.

Grumpy_Mike:
Why not just use a proportional SSR you can feed PWM directly into and forget trying to do a DIY zero crossing detection.

I already have Crydom cxe480d5r SSRs. But maybe there is some little schematic that can be used? Maybe You can find something. I don’t know what to look for. It would be much easier, sure.

I already have Crydom cxe480d5r SSRs.

Then you will have to go with what I said.

maybe there is some little schematic that can be used?

Anything you can implement in software you can implement in hardware, but you will end up spending more that if you just got the right component in the first place.

See this for what you are trying to do:- http://en.wikipedia.org/wiki/Phase_fired_controllers

Grumpy_Mike: See this for what you are trying to do:- http://en.wikipedia.org/wiki/Phase_fired_controllers

That's not easy thing to do as I see. There are no example schematics. It's probably easier to measure zero crossing with Arduino and find some code to do the dimming. I think I can't write it all by myself. I bought optocouplers today, so I can send AC waveform to Arduino and start using is as interrupt. But what comes next... I don't know...

Ragnar: I bought optocouplers today, so I can send AC waveform to Arduino and start using is as interrupt. But what comes next... I don't know...

Can I suggest that you figure out how it's going to work before you spend money on components? That way you won't find yourself with the wrong components and unwilling / unable to spend more money on the [u]right[/u] components.

But what comes next

Use the zero crossing signal to trigger an interrupt.
Make that ISR reset a counter - that is all.

Use timer 3 to trigger an interrupt as fast as you need it. For example if you want 256 steps of control and you are in a 50 Hz area for mains then you need an interrupt every 1 / (256 * 100) seconds. It is 100 and not 50 because you do this every half cycle.

In this ISR you increment your counter. Then compare the value of the counter with your power request value (from 0 to 255). If it is equal you set your SSR driving pin, otherwise you clear it.

The smaller your power request value is, the sooner the mains cycle turns on and the more power you have. So all you main sketch has to do is to set this value and the phase angle will be adjusted to match.

Make sure the counter and the power request value variable are declared as volatile and as global variables.

PeterH: Can I suggest that you figure out how it's going to work before you spend money on components? That way you won't find yourself with the wrong components and unwilling / unable to spend more money on the [u]right[/u] components.

But how should we learn if not from own experience? :) It's not that big money and I'm doing it for own fun not offering anybody service.

Grumpy_Mike, many thanks! I try to write code for your description later tomorrow. If I do not succeed, I come back here. :)

Grumpy_Mike:

Third, perhaps you should try a pair of MOSFETs instead?

On mains AC!!!

Yes, why not? The power controller ones do voltage and current (both forward and reverse) just fine. From what I understand, the main issue is to design the gate->source voltage correctly when the source is shared with mains. If you have other concerns, I'd love to learn!

Most people use an SSR that contains a phase angle delay circuit, that you can feed with PWM

Can you recommend one of these (rated for up to ~10A) for use with the arduino in a test lab? I found one that is $60 (model SE-1015V @ http://www.temp-inc.com/solid_state_relays.htm), but I'm hoping to spend less than half that.

Grumpy_Mike:
For example if you want 256 steps of control and you are in a 50 Hz area for mains then you need an interrupt every 1 / (256 * 100) seconds. It is 100 and not 50 because you do this every half cycle.

Now I’m stuck. Where should I say that 1/25000 seonds? I’ve never used timers before…
Am I going right direction so far?
I don’t have that zero crossing detection part yet. But I try to write some code and work it in my mind.

volatile int counterValue = 0;
volatile int requestValue = 25;

setup(){
  pinMode(10, OUTPUT);
  attachInterrupt(0, resetTimer, RISING);   //PIN 2 interrupt on timer3?
}

loop(){
  for(counterValue=0; counterValue<255; counterValue++) {
    if (counterValue==requestValue) {
      digitalWrite(10, HIGH);
    }
  }
}

resetTimer() {
  counterValue=0;
}

Now I'm stuck. Where should I say that 1/25000 seonds?

You need to set up timer 3 to give you an interrupt every 40uS, that is a frequency of 25KHz. There should be nothing to do with timing in the loop() function.

This code will give you a clue, it is designed to turn on an off a pin while at the same time modulating it at frequencies in the 30 - 40 KHz region, for IR control.

/* Code to pulse pin 3 with a modulated signal
* Can be used to drive an IR LED to keep a TSOP IR receiver happy
* This allows you to use a modulated receiver and a continuous beam detector
* By Mike Cook Nov 2011 - Released under the Open Source license
*/
 volatile byte pulse = 0;

ISR(TIMER2_COMPB_vect){  // Interrupt service routine to pulse the modulated pin 3
    pulse++;
  if(pulse >= 8) { // change number for number of modulation cycles in a pulse
    pulse =0;
    TCCR2A ^= _BV(COM2B1); // toggle pin 3 enable, turning the pin on and off
  }
}

void setIrModOutput(){  // sets pin 3 going at the IR modulation rate
  pinMode(3, OUTPUT);
  TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); // Just enable output on Pin 3 and disable it on Pin 11
  TCCR2B = _BV(WGM22) | _BV(CS22);
  OCR2A = 51; // defines the frequency 51 = 38.4 KHz, 54 = 36.2 KHz, 58 = 34 KHz, 62 = 32 KHz
  OCR2B = 26;  // deines the duty cycle - Half the OCR2A value for 50%
  TCCR2B = TCCR2B & 0b00111000 | 0x2; // select a prescale value of 8:1 of the system clock
}

void setup(){
  setIrModOutput();
  TIMSK2 = _BV(OCIE2B); // Output Compare Match B Interrupt Enable
}

void loop(){
// do something here
}

It uses direct port access to pulse a pin as this is very much faster than the digitalWrite() function. http://www.arduino.cc/en/Reference/PortManipulation

Grumpy_Mike: You need to set up timer 3 to give you an interrupt every 40uS, that is a frequency of 25KHz. There should be nothing to do with timing in the loop() function.

This code will give you a clue, it is designed to turn on an off a pin while at the same time modulating it at frequencies in the 30 - 40 KHz region, for IR control.

/* Code to pulse pin 3 with a modulated signal
* Can be used to drive an IR LED to keep a TSOP IR receiver happy
* This allows you to use a modulated receiver and a continuous beam detector
* By Mike Cook Nov 2011 - Released under the Open Source license
*/
 volatile byte pulse = 0;

ISR(TIMER2_COMPB_vect){  // Interrupt service routine to pulse the modulated pin 3     pulse++;   if(pulse >= 8) { // change number for number of modulation cycles in a pulse     pulse =0;     TCCR2A ^= _BV(COM2B1); // toggle pin 3 enable, turning the pin on and off   } }

void setIrModOutput(){  // sets pin 3 going at the IR modulation rate   pinMode(3, OUTPUT);   TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); // Just enable output on Pin 3 and disable it on Pin 11   TCCR2B = _BV(WGM22) | _BV(CS22);   OCR2A = 51; // defines the frequency 51 = 38.4 KHz, 54 = 36.2 KHz, 58 = 34 KHz, 62 = 32 KHz   OCR2B = 26;  // deines the duty cycle - Half the OCR2A value for 50%   TCCR2B = TCCR2B & 0b00111000 | 0x2; // select a prescale value of 8:1 of the system clock }

void setup(){   setIrModOutput();   TIMSK2 = _BV(OCIE2B); // Output Compare Match B Interrupt Enable }

void loop(){ // do something here }



It uses direct port access to pulse a pin as this is very much faster than the digitalWrite() function.
http://www.arduino.cc/en/Reference/PortManipulation

It's getting too complicated and I don't understand anything now. :(

DDRD = DDRD | B00001000; //SET PIN 3 OUTPUT?