why are you using a PWM signal? how do you synchronize it to the zero crossing?
knowing when there is a zero crossing, why don't you simply generate a short (1 usec) pulse after an appropriate delay to trigger the Triac?
// trigger line power triac with 25% duty cycle
#define ZeroCrPin A1
#define TriacPin 10
#if 1
# define HalfPeriodUsec (1000000/120)
#else // values to test at human speeds with LED
# define PulseWidthMsec 250
# define HalfPeriodUsec 1000000
#endif
#define TriacDutyCycle(x) (HalfPeriodUsec * (100-x)/100)
byte zc;
byte zcLst;
unsigned long zcUsec = 0;
unsigned long triacUsec;
char s [90];
// -----------------------------------------------------------------------------
void loop (void)
{
unsigned long usec = micros();
// capture zero crossing
zc = digitalRead (ZeroCrPin);
if (zcLst != zc) {
zcLst = zc;
if (LOW == zc) {
zcUsec = usec;
}
}
// wait for triac delay
if (zcUsec && (usec - zcUsec) > triacUsec) {
zcUsec = 0;
digitalWrite (TriacPin, HIGH);
#ifdef PulseWidthMsec // no need to ~usec pulse
delay (PulseWidthMsec);
#endif
digitalWrite (TriacPin, LOW);
}
}
// -----------------------------------------------------------------------------
void setup (void)
{
Serial.begin (9600);
digitalWrite (TriacPin, LOW);
pinMode (TriacPin, OUTPUT);
pinMode (ZeroCrPin, INPUT_PULLUP);
zcLst = digitalRead (ZeroCrPin);
triacUsec = TriacDutyCycle(25);
sprintf (s, "%s: HalfPeriodUsec %ld, triacUsec %ld",
__func__, HalfPeriodUsec, triacUsec);
Serial.println (s);
}