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
}
#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();
int PIN_ZERO_CROSS = D2;
volatile int zeroCross = 0;
IntervalTimer timer;
void setup()
{
Serial.begin(9600);
pinMode(PIN_ZERO_CROSS, INPUT);
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
i=0;
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() {
dim+=inc;
if((dim>=128) || (dim<=0))
inc*=-1;
delay(18);
}
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.