Triac, zero cross, AC dimmer via interrupts
Posted: Sat Nov 14, 2020 10:34 am
Hi to all!
Im looking for any tip as im getting crazy.
Im trying to create a stable AC phase control, and to do it I use a interrupt on rising linked with the zero cross detection, and set up a timer, to delay the triac gate activation. Then, change the timer delay to maintain the high pulse for certain minimum time.
It works, but ocassionally it fails, and the light flicker, becasue the triac is triggered earlier that it should be.
Attached an image where I catched the fail. The right timer delay is 6300uS, the delay for the high state of the trigger pin to the triac is 200uS. The same behaviour with different timer loads.
Code is this. It include another hardware timer, to generate a interrupt each second. The problem persist even if I deactivate this "each second" interruption:
Any tip will be welcome.
Thanks in advance.
Kind regards
Im looking for any tip as im getting crazy.
Im trying to create a stable AC phase control, and to do it I use a interrupt on rising linked with the zero cross detection, and set up a timer, to delay the triac gate activation. Then, change the timer delay to maintain the high pulse for certain minimum time.
It works, but ocassionally it fails, and the light flicker, becasue the triac is triggered earlier that it should be.
Attached an image where I catched the fail. The right timer delay is 6300uS, the delay for the high state of the trigger pin to the triac is 200uS. The same behaviour with different timer loads.
Code is this. It include another hardware timer, to generate a interrupt each second. The problem persist even if I deactivate this "each second" interruption:
Code: Select all
//////////////// Pinout ////////////////
static const uint8_t Pin_BACS = 33; // Pin, ZeroCross
static const uint8_t Pin_PWMBACSESP = 12; // Pin, Triac Gate
//////////////// Interrupcion Tiempo SEGUNDOS ////////////////
portMUX_TYPE timer0Mux = portMUX_INITIALIZER_UNLOCKED;
volatile int interruptCounter;
int totalInterruptCounter;
hw_timer_t * timer0 = NULL;
//////////////// Interrupcion Tiempo PASO POR CERO ////////////////
portMUX_TYPE timer1Mux = portMUX_INITIALIZER_UNLOCKED;
hw_timer_t * timer1 = NULL;
//////////////// Paso Por Cero - AC ////////////////
portMUX_TYPE muxBACS = portMUX_INITIALIZER_UNLOCKED;
const uint16_t DelayTriacMin = 1200; // Tiempo min para disparo triac (max potencia)
const uint16_t DelayTriacMax = 6200; // Tiempo max para disparo triac (min potencia)
volatile uint16_t DelayTriac; // Delay disparo triac (cant be float)
volatile bool FlagTriac=false; //
uint8_t segundos=0;
// Interrupcion Zero Cross detection
void IRAM_ATTR int_BACS() {
portENTER_CRITICAL_ISR(&muxBACS);
detachInterrupt(digitalPinToInterrupt(Pin_BACS)); // Desactivamos la interrupción (esta misma) de paso por cero
timerAlarmWrite(timer1, DelayTriac, false); // El delay en el temporizador depende de la potencia que queramos en la bomba
timerRestart(timer1);
timerAlarmEnable(timer1);
portEXIT_CRITICAL_ISR(&muxBACS);
}
// Interrupción TIMER, cada SEGUNDO
void IRAM_ATTR onTimer() {
portENTER_CRITICAL_ISR(&timer0Mux);
interruptCounter++;
portEXIT_CRITICAL_ISR(&timer0Mux);
}
// Interrupción TIMER, para el
void IRAM_ATTR onTimerPASOCERO() {
portENTER_CRITICAL_ISR(&timer1Mux);
if (!FlagTriac){
digitalWrite(Pin_PWMBACSESP, HIGH);
FlagTriac = true;
timerAlarmWrite(timer1, 200, false); // El delay en el temporizador depende de la potencia que queramos en la bomba
timerRestart(timer1);
timerAlarmEnable(timer1);
}else{
digitalWrite(Pin_PWMBACSESP, LOW);
attachInterrupt(digitalPinToInterrupt(Pin_BACS), int_BACS, RISING); // Activamos la interrupción captura paso por cero 220AC
FlagTriac = false;
}
portEXIT_CRITICAL_ISR(&timer1Mux);
}
void setup() {
delay(10);
// Configura Pines, entrada/salida/ADC
pinMode(Pin_BACS, INPUT_PULLUP); // In, Zero Cross detection
pinMode(Pin_PWMBACSESP, OUTPUT); // Out, Triac Gate
//////////// INTERRUPCIONES ////////////
// Configuramos el La interrupción del Timer de los SEGUNDOS
timer0 = timerBegin(0, 80, true); // Prescaler
timerAttachInterrupt(timer0, &onTimer, true); // Función a llamar en la interrupción
timerAlarmWrite(timer0, 1000000, true); // cada 1sg
timerAlarmEnable(timer0); // Activamos la interrupción
// Configuramos el La interrupción del Timer del PASO POR CERO
DelayTriac = DelayTriacMax;
timer1 = timerBegin(1, 80, true); // Prescaler
timerAttachInterrupt(timer1, &onTimerPASOCERO, true); // Función a llamar en la interrupción
timerAlarmWrite(timer1, DelayTriac, false); // El valor inicial del disparo del triac
// Enlazamos las interrupciones a los pines
attachInterrupt(digitalPinToInterrupt(Pin_BACS), int_BACS, RISING); // Interrupción captura paso por cero 220AC
}
void loop() {
if (DelayTriac<1200){
DelayTriac=8200;
}
/////////// Interrupción cada segundo ///////////
if (interruptCounter > 0) { // Solo lo ejecutamos si el timer ha desbordado
DelayTriac=DelayTriac - 100;
timerAlarmWrite(timer1, DelayTriac, false); // El delay en el temporizador depende de la potencia que queramos en la bomba
portENTER_CRITICAL(&timer0Mux);
interruptCounter--;
segundos++;
portEXIT_CRITICAL(&timer0Mux);
if (segundos >= 2){
segundos = 0;
}
}
}
Thanks in advance.
Kind regards