Hi folks,
I am looking for help to improve this zero-cross detecting / triac triggering code that I've implemented on an ATtiny85. It is working without problems on a 220V / 50Hz mains, but I would like to get rid, if possible (I suspect it is, but I can not make it work), of the two timer ISRs I'm using at the moment.
Now it works this way: the ZCD pulses present in PCINT3 activate the pin change ISR (I can not use INT0 because I am using I2C). This ISR resets the Timer1 counter, configured in CTC mode, and puts it to count. Upon reaching the selected OCR1C value, the compare match ISR is activated, where PB1, which controls the triac gate, is put on high. This same ISR sets the Timer1 counter to overflow 3 or 4 ticks later, managing the duration of the triac start pulse.
Finally, the Timer1 overflow ISR puts in low PB1 and turns off the triac.
Would it be possible to achieve the same operation by making timer1 activate/deactivate OC1A? Thus discarding the Timer interrupts that I am using?
Thank you very much in advance!
// Includes ... // Defines #define PWR_CTRL_PIN PB1 #define PWR_CTRL_DDR DDRB #define PWR_CTRL_PORT PORTB #define ZCD_PIN PB3 #define ZCD_DDR DDRB #define ZCD_PORT PORTB #define ZCD_INP PINB #define CHANGETIME 0xFFFF #define MINGATEDELAY 7 /* OK @50Hz 7 tics after ZCD */ #define MAXGATEDELAY 147 /* OK @50Hz 147 tics are the maximum safe triac switching resolution */ #define PULSELENGTH 3 /* OK @50Hz 3 tics are enough to fire the triac */ // Global variables volatile uint16_t ocrChangeDelay = 0; volatile uint8_t newValueFromI2C = UsiTwiReceiveByte(); // Function prototypes ... // Main int main(void) { // Setup Setup(); // Loop Loop(); return 0; } // Pin Change ISR (Zero Cross Detection) ISR(PCINT0_vect) { if(ZCD_INP & (1 << ZCD_PIN)) { /* If it was triggered by a rising edge, run ISR code */ TCNT1 = 0; /* Reset Timer1 counter */ TCCR1 |= ((1 << CS13) | (1 << CS11)); /* Start Timer1 with prescaler 512 (I/O clock / 512) */ } } // Timer1 Compare Match ISR (Triac switch on after counter compare match *fire delay*) ISR(TIMER1_COMPA_vect) { PWR_CTRL_PORT |= (1 << PWR_CTRL_PIN); /* Turn Triac On */ TCNT1 = (255 - PULSELENGTH); /* Set Timer1 counter for overflow interrupt */ } // Timer1 Overflow ISR (Triac switch off after counter overflow *pulse length*) ISR(TIMER1_OVF_vect) { PWR_CTRL_PORT &= ~(1 << PWR_CTRL_PIN); /* Turn Triac Off */ TCCR1 &= ~((1 << CS13) | (1 << CS12) | (1 << CS11) | (1 << CS10)); /* Set Timer1 off - Prescaler 0 */ } // Setup void Setup(void) { clock_prescale_set(8); /* Set CPU @1 MHz (System clock / 8) */ PWR_CTRL_DDR |= (1 << PWR_CTRL_PIN); /* Set led pin Data Direction Register for output */ PWR_CTRL_PORT &= ~(1 << PWR_CTRL_PIN); /* Turn Triac Off */ _delay_ms(500); /* Delay to allow ISP programming at 1 MHz after power on */ clock_prescale_set(1); /* Set CPU @8 MHz (System clock / 1) for safe I2C slave operation */ cli(); /* Disable interrupts */ SetPinChangeInterrupt(); /* Enable pin change interrupt for zero cross detection */ SetTimer1Interrupt(); /* Enable timer1 interrupts for modulating phase angle */ sei(); /* Enable interrupts */ } // Main Loop void Loop (void) { for(;;) { OCR1C = newValueFromI2C; } } // Function SetPinChangeInterrupt void SetPinChangeInterrupt(void) { ZCD_DDR &= ~(1 << ZCD_PIN); /* Set PB3 for input to detect the Zero Cross pulse */ ZCD_PORT &= ~(1 << ZCD_PIN); /* Disable PB3 pull-up resistor (high-impedance state) */ GIMSK |= (1 << PCIE); /* Enable Pin Change Interrupt */ PCMSK |= (1 << PCINT3); /* Set Pin Change Mask Register to allow ZCD on PB3 */ } // Function SetTimer1Interrupt void SetTimer1Interrupt(void) { TCCR1 |= (1 << CTC1); /* Set Timer1 CTC mode */ TIMSK |= ((1 << OCIE1A) | (1 << TOIE1)); /* Enable Timer1 compare match and overflow interrupts */ OCR1C = MINGATEDELAY; /* Set Timer1 comparator to "MINGATEDELAY" */ }