Arduino AC Dimmer Triac with ZC Detector

Hello everyone, after searching all day for the solution, and already having burned several resistance wires. I come to ask for help. Because i can’t see the problem / solution :sweat_smile:

What i want to do: I want to control the heat dispatched by a resistance wire. The wire has a resistance of 66 ohm. 2302V / 66ohm = aprox. 800Watt.

I used the following schematic

With:
X1-2 attached to pin 2
X1-3 attached to pin 3 (INT1)
X1-4 attached to 5V

My Powersoure is 230V / 50HZ (the netherlands)

My top code looks like the following.

int AC_LOAD = 2;    // Output to Opto Triac pin
int dimming = 128;  // Dimming level (0-128)  0 = ON, 128 = OFF

void setup()
{
  pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
  attachInterrupt(1, zero_crosss_int, RISING);  // Choose the zero cross interrupt # from the table above
}

To:

  • Set AC_LOAD as an output Attached to Triac
  • Dimming as the variable to control the output
  • The interrupt of the Arduino, calls the function zero_crosss_int

Then i have the following function for the interrupt

//the interrupt function must takes no parameters and returns nothing
void zero_crosss_int()  //function to be fired at the zero crossing to reduce the heat
{
  // Firing angle calculation : 1 full 50Hz wave =1/50=20ms 
  // Every zerocrossing thus: (50Hz)-> 10ms (1/2 Cycle) 
  // For 60Hz => 8.33ms (10.000/120)
  // 10ms=10000us
  // (10000us - 10us) / 128 = 75 (Approx) For 60Hz =>65

  int dimtime = (75*dimming);    // For 60Hz =>65    
  delayMicroseconds(dimtime);    // Wait till firing the TRIAC    
  digitalWrite(AC_LOAD, HIGH);   // Fire the TRIAC
  delayMicroseconds(10);         // triac On propogation delay 
  digitalWrite(AC_LOAD, LOW);    // No longer trigger the TRIAC (the next zero crossing will swith it off) 
}

And then in my loop i do the following:

void loop()  {
    dimming=120;
    delay(10);
}

What i expected to happen:

  • IF i set dimming to 0: The led LED1 will be full bright and the heater will be on max heat.
  • IF i set dimming to 128: The led LED1 will be off and the heater will be off.
  • The burning of the led would be constant.

What happens:

  • At 0 the led is not even close to full brightness and the heater is not on max heat
  • At 128 the led is still slightly on and the heater is not off
  • The led flickers

Hopefully someone could help.

Full code:

int AC_LOAD = 2;    // Output to Opto Triac pin
int dimming = 128;  // Dimming level (0-128)  0 = ON, 128 = OFF

void setup()
{
  pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
  attachInterrupt(1, zero_crosss_int, RISING);  // Choose the zero cross interrupt # from the table above
}

//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 (10.000/120)
  // 10ms=10000us
  // (10000us - 10us) / 128 = 75 (Approx) For 60Hz =>65

  int dimtime = (75*dimming);    // For 60Hz =>65    
  delayMicroseconds(dimtime);    // Wait till firing the TRIAC    
  digitalWrite(AC_LOAD, HIGH);   // Fire the TRIAC
  delayMicroseconds(10);         // triac On propogation delay 
  digitalWrite(AC_LOAD, LOW);    // No longer trigger the TRIAC (the next zero crossing will swith it off) TRIAC
}

void loop()  {
    dimming=128;
    delay(10);
}

The following code, does exactly what i want…

#include  <TimerOne.h>          // Avaiable from http://www.arduino.cc/playground/Code/Timer1
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 = 2;                // Output to Opto Triac
int brightness = 0;           // Dimming level (0-256)  0 = on, 256= 0ff
int freqStep = 75;    // This is the delay-per-brightness step in microseconds.


char auth[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

void setup() {                                    
  pinMode(AC_pin, OUTPUT);                          // Set the Triac pin as output
  attachInterrupt(1, zero_cross_detect, RISING);    // Attach an Interupt to Pin 3 (interupt 0) 
  Timer1.initialize(freqStep);                      // Initialize TimerOne library 
  Timer1.attachInterrupt(dim_check, freqStep);   
  
  Serial.begin(9600);
  delay(10);
                                      
}

void zero_cross_detect() {    
  zero_cross = true;               
  i=0;
  digitalWrite(AC_pin, LOW);       // turn off TRIAC (and AC)
}                                 

// Turn on the TRIAC at the appropriate time
void dim_check() {                   
  if(zero_cross == true) {              
    if(i>=brightness) {                     
      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() {                        
  brightness++;
  if(brightness >= 256) {  
     brightness = 0;
  }
  delay(15);
}

I assume, that i was only detecting a “half-wave” and not a full wave…

I will have to have a proper look one time.