Zero_cross... hrmm

So I bought a zero-cross detecting circuit… The code example is:

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 : (50Hz)-> 10ms (1/2 Cycle) For 60Hz (1/2 Cycle) => 8.33ms 
  // 10ms=10000us

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

But it uses delaymicros()… yuck. :stuck_out_tongue:

So I’m using this code: AC dimmer Timer Interupt as a starting point…

It works… Except with LED lightbulbs. The old code DID work with the led lightbulb.

I’m guessing it has to do with the amount of time the triac stays OFF, but I’m not smart enough to grok it.


Can you post the code you actually want reviewed? :wink:
Did you go for the fast digital IO functions suggested in the thread?

BTW, delayMicroseconds() only takes an int value, so 8.33 will just be 8, and are you not missing a closing curly brace in that function?

Not a very enlightening symptom description.

Here is the code from the link:

#include "SparkIntervalTimer.h"

volatile int i = 0;               // Variable to use as a counter volatile as it is in an interrupt
volatile boolean zero_cross = 0;  // Boolean to store a "switch" to tell us if we have crossed zero
int AC_pin = D1;                // Output to Opto Triac
int dim = 0;                    // Dimming level (0-128)  0 = on, 128 = 0ff
int inc = 1;                      // counting up or down, 1=up, -1=down

int freqStep = 75;    // This is the delay-per-brightness step in microseconds.
                      // For 60 Hz it should be 65
// It is calculated based on the frequency of your voltage supply (50Hz or 60Hz)
// and the number of brightness steps you want.

void zero_cross_detect();
volatile int zeroCross = 0;
IntervalTimer timer;

void setup()
  pinMode(AC_pin, OUTPUT);                          // Set the Triac pin as output
  timer.begin(dim_check, freqStep, uSec, TIMER5);
  attachInterrupt(PIN_ZERO_CROSS, zero_cross_detect, RISING);    // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection

void zero_cross_detect() {
  zero_cross = true;               // set the boolean to true to tell our dimming function that a zero cross has occured
  digitalWrite(AC_pin, LOW);       // turn off TRIAC (and AC)

// Turn on the TRIAC at the appropriate time
void dim_check() {
  //Serial.println("DIM CHECK");
  if(zero_cross == true) {
    if(i>=dim) {
      digitalWrite(AC_pin, HIGH); // turn on light
      i=0;  // reset time step counter
      zero_cross = false; //reset zero cross detection
    else {
      i++; // increment time step counter

void loop() {
  if((dim>=128) || (dim<=0))

When I use that code if I’m using a non LED light bulb “it works” as in I can dim the light bulb.

If I use an LED light bulb, however, it does not work. The light bulb does not dim.

If I use the original code it dims with both a non led bulb and an led bulb.

I think your digitalWrite(AC_pin, LOW) after the zero cross comes too late.
Your original code does this differently.
8µs after you fired the Triac via digitalWrite(AC_pin, HIGH) the Triac is “prepared” to switch off on next zero cross but with the “new” code the AC_pin is still HIGH at that time keeping the Triac open.

BTW, try using pinSetFast(AC_pin) and pinResetFast(AC_pin) for extra speed.

Try this

void dim_check() {
  if(zero_cross) {
    if(i >= dim) {
      pinSetFast(AC_pin);   // turn on light
      i = -1;               // prepare next timer call to rearm Triac
    else if (i < 0) {       // first timer call after firing the Triac
      pinResetFast(AC_pin); // rearm Triac to switch off on zero cross
      zero_cross = false;   // reset zero cross detection
      i = 0;
    else {
      i++;                  // increment time step counter

(i is not a good name for a global variable)

I’d also add special treatment for off (dim == 128) and on (dim == 0) states.
In these cases no zero cross detection nor Triac switching is needed and should even be avoided entirely.

1 Like

hrmm... well that seems to have stopped the flickering I was getting... but now it doesn't dim either LED or incandescent.

I think I need to do more studying on exactly how zero_cross and triacs work

I forgot to (explicitly) mention that the digitalWrite(AC_pin, LOW) in your zero_cross_detect() should be removed.

Thanks man, why I need to do more studying! :grin:

Are you using a dimmable LED bulb?

Yeah it is. That’s why it was weird that it works with the one code, and not the other