[Solved]Problemi con circuito di Zero Crossing

Salve ragazzi sono di nuovo io. Questa volta sono alle prese con un progetto che si dovrebbe occupare di far variare la luminosità di una lampada 220V attraverso in circuito di zero crossing.
Prima di procedere a creare il progetto ho girovagato per molti siti e in particolare ho fatto riferimento alla discussione trattata in precedenza qui:
http://arduino.cc/forum/index.php/topic,89415.45.html

dopo aver seguito i consigli dati in quella discussione ho deciso di cimentarmi anche io in questa esperienza. Grazie all'aiuto dato da maxvetro in quella discussione sono arrivato a creare il mio piccolo circuitino montato su piastra mille fori. Il circuito è il seguente:

se vedete bene il circuito è riprodotto proprio sulle false righe del circuito proposto da maxvetro.

Il mio problema è che non funziona. La lampada si accende per qualche frazione di secondo e poi si spegne senza fare il dimmer.
Ho provato diversi codici tra i quali:

int var = 1000 ;
void setup()
{
attachInterrupt(0, zero_cross_detect, RISING);
pinMode(10, OUTPUT);
Serial.begin(9600);

pinMode ( 3 , INPUT );

}

void zero_cross_detect() {

delayMicroseconds(var);
digitalWrite(10, HIGH);
delayMicroseconds(1000);
digitalWrite(10, LOW);

}

void loop()
{

if ( digitalRead(3) == LOW ) {

var = var + 50 ;
delay ( 10 ) ;
if ( var == 9000 ) {
var = 1000;

}

}

}

e anche

int AC_LOAD = 3; // Output to Opto Triac pin
int dimming = 128; // Dimming level (0-128) 0 = ON, 128 = OFF
/* Due to timing problems, the use of ‘0’ can sometimes make the circuit
flicker. It is safer to use a value slightly higher than ‘0’
*/
void setup()
{
pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
attachInterrupt(0, zero_crosss_int, RISING);
// Chooses '0' as interrupt for the zero-crossing
}
// 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

// 10ms=10000us
// (10000us - 10us) / 128 = 75 (Approx) For 60Hz =>65
int dimtime = (75*dimming); // For 60Hz =>65
delayMicroseconds(dimtime); // Off cycle
digitalWrite(AC_LOAD, HIGH); // triac firing
delayMicroseconds(10); // triac On propogation delay
//(for 60Hz use 8.33)
digitalWrite(AC_LOAD, LOW); // triac Off
}
void loop() {
for (int i=5; i <= 128; i++)
{
dimming=i;
delay(10);
}
}

Adesso mi chiedo potrebbero essere i CNY17-3 che non sono adatti a questo scopo? Se avete qualche consiglio da suggerirmi sarò più che felice di seguirvi nel limite del possibile :slight_smile:
Un grazie in anticipo a tutto il forum!Siete davvero grandi!

PS: utilizzo un Arduino 2009

Non so se funzionano i delayMicroseconds nella poutine di interrupt. Ma se funziona:

se var é 8950 la seguente funzione

void zero_cross_detect() {  
  delayMicroseconds(var);
  digitalWrite(10, HIGH);
  delayMicroseconds(1000);
  digitalWrite(10, LOW); 
}

avrá un tempo di esecuzione maggiore di 10mS. Arriveranno dei interrupt (arrivano precisamente ogni 10µS) prima che la funzione sia terminata e percui entro breve si riempie lo stack e Arduino va in tilt.

Consiglio di:

  1. Fare il ritardo con un timer
  2. Non andare su tempi di ritardo pilotaggio troppo lunghi che si acvviciano troppo a 10mS In quel caso per esempio a 9,5mS spegnere l'utenza del tutto non pilotando il triac.

Secondo quel poco che so dei Triac hai collegato il carico sul lato sbagliato del triac. nel disegno postato deve essere messa l' utenza sopra prima del triac e non sotto, dopo.

Ciao Uwe

Mmmm...non penso sia un problema legato a dove si trova il carico rispetto al triac perchè ho effettuato diverse prove cambiando la posizione del carico e non fa nulla.quindi a questo punto mi rimane da cambiare il codice maaa...come si fa un ritardo con un timer??non l'ho mai fatto :astonished:
Centra qualcosa questo sketch?Arduino Playground - ACPhaseControl

Quello che mi sembra strano è che hanno messo la discussione come Risolta....booooh :astonished:

Ciao ragazzi...sono arrivato purtroppo alla frutta.
Sto provando a realizzare questo maledetto circuito da ieri sera e non ci sto riuscendo. Purtroppo non riesco a far variare la luminosità della mia lampada 220V. Quello che fa adesso è semplicemente due step di luminosità

  1. massima luminosità
  2. luminosità media
    e basta. Il circuito non dimmera e non fa neanche spegnere la luce. Ho seguito questo schema e questo codice. Spero veramente riusciate a darmi qualche dritta altrimenti devo dichiarare chiuso questo tema...

/*
AC Light Control

Updated by Robert Twomey rtwomey@u.washington.edu

Changed zero-crossing detection to look for RISING edge rather
than falling. (originally it was only chopping the negative half
of the AC wave form).

Also changed the dim_check() to turn on the Triac, leaving it on
until the zero_cross_detect() turn's it off.

Ryan McLaughlin ryanjmclaughlin@gmail.com

The hardware consists of an Triac to act as an A/C switch and
an opto-isolator to give us a zero-crossing reference.
The software uses two interrupts to control dimming of the light.
The first is a hardware interrupt to detect the zero-cross of
the AC sine wave, the second is software based and always running
at 1/128 of the AC wave speed. After the zero-cross is detected
the function check to make sure the proper dimming level has been
reached and the light is turned on mid-wave, only providing
partial current and therefore dimming our AC load.

Thanks to Andrew Kilpatrick
and http://www.hoelscher-hi.de/hendrik/english/dimmer.htm

*/

#include <TimerOne.h> // Avaiable from Arduino Playground - Timer1

volatile int i=0; // Variable to use as a counter
volatile boolean zero_cross=0; // Boolean to store a "switch" to tell us if we have crossed zero
int AC_pin = 11; // Output to Opto Triac
int POT_pin = A0; // Pot for testing the dimming
int LED = 3; // LED for testing
int dim = 0; // Dimming level (0-128) 0 = on, 128 = 0ff

int freqStep = 75; // This is the delay-per-brightness step in microseconds.
// It is calculated based on the frequency of your voltage supply (50Hz or 60Hz)
// and the number of brightness steps you want.
//
// The only tricky part is that the chopper circuit chops the AC wave twice per
// cycle, once on the positive half and once at the negative half. This meeans
// the chopping happens at 120Hz for a 60Hz supply or 100Hz for a 50Hz supply.

// To calculate freqStep you divide the length of one full half-wave of the power
// cycle (in microseconds) by the number of brightness steps.
//
// (1000000 uS / 120 Hz) / 128 brightness steps = 65 uS / brightness step
//
// 1000000 us / 120 Hz = 8333 uS, length of one half-wave.

void setup() { // Begin setup
pinMode(AC_pin, OUTPUT); // Set the Triac pin as output
pinMode(LED, OUTPUT); // Set the LED pin as output
attachInterrupt(0, zero_cross_detect, RISING); // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
Timer1.initialize(freqStep); // Initialize TimerOne library for the freq we need
Timer1.attachInterrupt(dim_check, freqStep);
// Use the TimerOne Library to attach an interrupt
// to the function we use to check to see if it is
// the right time to fire the triac. This function
// will now run every freqStep in microseconds.
}

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 on the TRIAC at the appropriate time
void 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 = analogRead(POT_pin) / 8; // read dimmer value from potentiometer
analogWrite(LED, dim); // write dimmer value to the LED, for debugging
}

ovviamente ho adattato le resistenze per poter lavorare ai 220V

Ciao. Io sono riuscito a dimare una lampadina ad incandescenza (anch'io aiutato dai preziosi consigli di maxvetro che colgo l'occasione per ringraziare) utilizzando i seguenti componenti:

Zero cross detector come in questo schema (forse proprio di maxvetro)

Dimmer 220 optoisolato come in questo mio schema:

Lo codice che ho usato (purtroppo è poco commentato):

// premendo una volta la luce si accende dimata
// premendo un altra volta la luce si spegne dimata
// tenendo premuto la luce aumenta fino al massimo poi diminuisce fino al minimo. Si ferma al rilasciamento

// bisogna modificare:
// 1) lo spegnimento che deve sempre procedere verso il basso senza passare dal massimo (se parte da dimata)
// 2) il dimaggio a pressione mantenuta, che deve iniziare sempre verso il basso


int T0 = 0;
int T1 = 0;
int ST0 = 0;
int ST1 = 0;
int var = 8900; 
//valore in mcsec attesa accensione triac, più è basso più sta acceso
int inc = 50;
int Luce = 0;
int PrintSer = 0;
int accendi = 0;
int spegni = 0;
int my_time = 0;
int my_time2 = 0;
int my_main_time = millis();
int my_main_delay = 10;
int my_var_time = 0;
int my_var_delay = 1000;
int my_timer = 0;
int tmp = 0;

//###################################################################################################
void setup() {
  attachInterrupt(0, zero_cross_detect, CHANGE); // interrupt pin 0, controlla zero cross
  pinMode(10, OUTPUT);                           // output verso opto isolante
  pinMode(3, INPUT);                             // input verso il pulsante in pull up
  Serial.begin(9600);                            // Inizializzazione seriale per debug
}
//###################################################################################################
void loop() {
  my_time = millis();
  my_time2 = my_timer;
 if(my_time>my_main_time+my_main_delay){
   Fn_Pulsante();
 }
}
//###################################################################################################

//---------------------------------------------------------------------------------------------------
void zero_cross_detect() {
  if(var <= 8900 && var >= 1100){
  delayMicroseconds(var/2);                        // attende mcsec var (che può essere da 1000 a 9000)
      tone(10, 500, 1);
  }
    my_timer = my_timer + 1; // incremento questo timer perchè millis() non è regolare negli interrupts
    if(my_timer > 10000){
      my_timer = 0;
    }
}
//---------------------------------------------------------------------------------------------------
  void Fn_Accendi(){
  accendi = 1;
  var = var - inc;
  if(var < 1100){
    var = 1100;
    Luce = 1;
    accendi = 0;
    T1 = 0;
    T0 = 0;
  }
  }
//---------------------------------------------------------------------------------------------------
  void Fn_Spegni(){
    spegni = 1;
  var = var + inc;
  if(var > 8900){
    var = 8900;
    Luce = 0;
    spegni = 0;
    T1 = 0;
    T0 = 0;
  }
  }
  //---------------------------------------------------------------------------------------------------
  void Fn_Pulsante(){
  if(digitalRead(3) == LOW){                     // se viene premuto il pulsante...
    if(ST0==0){
      T0 = my_timer;
      ST0 = 1;
      ST1 = 0;
    }
      var = var - inc;                              // aumenta il valore var

    PrintSer = 1;
    }
  if(digitalRead(3) == HIGH){
    if(ST1==0){
    T1 = my_timer;
    ST1 = 1;
    ST0 = 0;
    }
    if(PrintSer==1){
    Serial.print("var = ");
    Serial.print(var);
    Serial.print("     T0 = ");
    Serial.print(T0);
    Serial.print("     T1 = ");
    Serial.print(T1);
    Serial.print("     T1 - T0 = ");
    Serial.println(T1 - T0);
    PrintSer = 0;
    }
    if((T1 - T0 > 5 && T1 - T0 < 200) || (10000 - (T0 + T1) > 5 && 10000 - (T0 + T1) < 200) || accendi == 1 || spegni == 1){
      if(Luce == 0){
        Fn_Accendi();
      }else if(Luce == 1){
        Fn_Spegni();
      }
    }
  }

    
    if(var > 8900){                             // se var = 9000 mcsec... (luminosità minima)
      var = 8900;                                // reimposta var a 1000 mcsec (luminosità massima)
      inc = -inc;
    }
    if(var < 1100){                             // se var = 9000 mcsec... (luminosità minima)
      var = 1100;                              // reimposta var a 1000 mcsec (luminosità massima)
      inc = -inc;
    }
    my_main_time = millis();
  }

Ciao. Carlo.

Ah, vedo che non ho segnato il triac che è un BTA16 600B, il condensatore è 33 nano 630v poliestere
L'arduino si collega in alto.

ATTENZIONE!!!
IL CIRCUITO SOPRARIPORTATO SI COLLEGA ALLA 220 VOLT
E C'E' RISCHIO DI MORTE SE USATO INCAUTAMENTE.
Si declina ogni responsabilità.

(messaggio dovuto...)

E per la cronaca il MOC3020 non é un zero crossing ma random.
Ciao Uwe

Infatti, se fosse zero crossing non funzionerebbe il dimmer XD

Allora ragazzi, siamo a un piccolo punto di svolta.
Ho seguito lo schema che mi ha suggerito valisi, e per questo lo ringrazio molto dell'aiuto!
Lo schema che mi ha dato è più o meno simile a tutti quelli che ho seguito finora l'unica cosa aggiuntiva è la presenza del led prima del MOC3020.
La cosa bella è che il led viene dimmerato!!!!, quindi vuol dire che il circuito di zero crossing funziona, è quello dopo il MOC che non funziona, o meglio funziona solo quando il led raggiunge il massimo della luminosità facendo accedere la lampadina per qualche millisecondo e poi si spegne in modo brusco senza far dimmerare nulla, è come se il triac non venisse fatto partire...avete qualche idea?

boh ragazzi...mi arrendo! =(

Ripeto, se stai usando un optoisolato zero crossing, il dimmer non funziona.
Se invece stai usando il mio schema, prova a ridurre la resistenza a monte del MOC

Ho sostituito il MOC3020 con un MOC3021 ed è partitoooooooo :smiley:

La differenza tra i 2 Optocopler (MOC3020 e MOC3021) é la corrente di pilotaggio del entrata (LED) necessaria per far condurre il triac di uscita.
Il MOC3020 necessita di 30mA e il MOC3021 di 15mA. I modelli MOC3022 e MOC3023 necessitano ancora di meno.

Ciao Uwe

La differenza tra i 2 Optocopler (MOC3020 e MOC3021) é la corrente di pilotaggio del entrata (LED) necessaria per far condurre il triac di uscita.
Il MOC3020 necessita di 30mA e il MOC3021 di 15mA. I modelli MOC3022 e MOC3023 necessitano ancora di meno.

Grazie mille uwefed, la prossima volta lo dovrò tenere a mente!