Metodi per temporizzazione eventi

Salve,
devo risolvere un problema di ritardo all'attivazione di un uscita digitale:
utilizzando un zero crossing detector che mi rileva il passaggio dallo zero di una semionda con frequenza 50 hz, devo attivare con un ritardo fisso(che in futuro però dovrà diventare variabile) un pin digitale.
Il tempo di clock è ottenuto tramite interrupt (che legge il zero crossing) settato su "RISING"
Una volta attivato devo disattivarlo con un' altro ritardo.
Ho fatto delle prove con delay() ma come pensavo non funziona come dovuto quindi un ulteriore tentativo l'ho fatto utilizzando la funzione millis() e relative implementazioni però anche qui comportamenti non corretti.
Qualcuno mi può suggerire qualche metodo alternativo per settare questi ritardi ?
Grazie

Ciao,

Mettici in grado di aiutarti :smiley:
Posta lo sketch completo, quello con millis(), e spiega meglio cosa non và come vorresti.

Attilio

Oltre al millis e al delay, potresti usare micros e delayMicroseconds, per avere degli intervalli più precisi.

Probabilmente usi lo zero crossing per pilotare il gate di un TRIAC: dai un occhio a questo articolo.

http://playground.arduino.cc/main/ACPhaseControl

Riporto il codice che mi hai indicato nell’articolo citato e ci sarebbero alcune cose che non capisco e che non so come variare:

#include <avr/io.h>
#include <avr/interrupt.h>

#define DETECT 2  //zero cross detect
#define GATE 9    //triac gate
#define PULSE 4   //trigger pulse width (counts)
int i=483;

void setup(){

  // set up pins
  pinMode(DETECT, INPUT);     //zero cross detect
  digitalWrite(DETECT, HIGH); //enable pull-up resistor
  pinMode(GATE, OUTPUT);      //triac gate control

  // set up Timer1 
  //(see ATMEGA 328 data sheet pg 134 for more details)
  OCR1A = 100;      //initialize the comparator
  TIMSK1 = 0x03;    //enable comparator A and overflow interrupts
  TCCR1A = 0;    //timer control registers set for
  TCCR1B = 0;    //normal operation, timer disabled


  // set up zero crossing interrupt
  attachInterrupt(0,zeroCrossingInterrupt, RISING);    
    //IRQ0 is pin 2. Call zeroCrossingInterrupt 
    //on rising signal

}  

//Interrupt Service Routines

void zeroCrossingInterrupt(){ //zero cross detect   
  TCCR1B=0x04; //start timer with divide by 256 input
  TCNT1 = 0;   //reset timer - count from zero
}

ISR(TIMER1_COMPA_vect){ //comparator match
  digitalWrite(GATE,HIGH);  //set triac gate to high
  TCNT1 = 65536-PULSE;      //trigger pulse width
}

ISR(TIMER1_OVF_vect){ //timer1 overflow
  digitalWrite(GATE,LOW); //turn off triac gate
  TCCR1B = 0x00;          //disable timer stopd unintended triggers
}

void loop(){ // sample code to exercise the circuit

  i--;
  OCR1A = i;     //set the compare register brightness desired.
  if (i<65){
   i=483;
  }                      
  delay(15);                             
}

Questo sketch è pensato per una frequenza di 60 hz: come fare per adattarlo a quella europea?
La teoria di funzionamento spiegata nell’articolo è chiarissima ma
essendo alle prime armi ho capito ben poco del contenuto. Non pretendo che qualcuno mi spieghi come funziona il tutto (non mi piace fare bovinamente un “copiaincolla” senza capire come funziona quello che sto incollando, ma tant’è ) e sarebbe utile capire quali sono i parametri da modificare per variare alcune temporizzazioni.
Caricato lo sketch noto che modificando la variabile i nel loop, ritardo od anticipo il fronte di salita (quello che mi serviva) rispetto allo 0 ma noto anche che il tempo di discesa è eccessivamente basso per attivarmi il triac (64uS); come aumentarlo?
Questa riga:

#define PULSE 4   //trigger pulse width (counts)

si poteva anche sostituire con

int PULSE = 4;

??

Grazie mille delle eventuali dritte

Ho riscritto lo sketch in modo che sia più chiaro, ma non ho avuto modo di provarlo.

Prova a vedere se funziona.

/* AC Control V1.1
 This arduino sketch is for use with the heater 
 control circuit board which includes a zero 
 crossing detect fucntion and an opto-isolated triac.
 
 AC Phase control is accomplished using the internal 
 hardware timer1 in the Arduino.
 
 Timing Sequence
 timer is set up but disabled
 zero crossing detected on pin 2
 timer starts counting from zero
 comparator set to "delay to on" value
 counter reaches comparator value
 comparator ISR turns on triac gate
 counter set to overflow - pulse width
 counter reaches overflow
 overflow ISR truns off triac gate
 triac stops conducting at next zero cross
 
 The hardware clock runs at 16MHz.
 Using a divide by 256 for counter of Timer1, each count is 16 μs.
 1/2 wave of a 50Hz AC signal (10 ms) is 625 counts
 1/2 wave of a 60Hz AC signal (16.66 ms) is about 520 counts.
 */

#define ZeroPin 2                           // zero crossing
#define GatePin 4                           // triac gate
#define SemiWaveTick 625                    // 1/2 wave at 50Hz 625 ticks
#define PulseWidth 4                        // trigger pulse width (4 ticks = 4 * 16 = 64 μs)

unsigned int Power = 0;                     // 0 - 100%

void setup() {

  pinMode(ZeroPin, INPUT_PULLUP);           // zero cross detect
  pinMode(GatePin, OUTPUT);                 // triac gate control

  TCCR1A = 0x00;                            // timer 1 control register set for normal operation, timer disabled
  TCCR1B = 0x00;                            // normal operation, timer disabled
  OCR1A = 100;                              // initialize the output comparare register A timer 1
  TIMSK1 = 0x03;                            // enable comparator A and overflow interrupts

  attachInterrupt(0, ZeroCrossing, RISING); // IRQ0 is pin 2 
}  

void loop() {

  for (Power = 0; Power < 101; Power ++) {
    OCR1A = Power * SemiWaveTick / 100;     // set the output compare register A
    delay(15);                             
  }
}

void ZeroCrossing() {                       // zero cross detect   
  TCCR1B = 0x04;                            // start timer with divide by 256 clock
  TCNT1 = 0;                                // reset timer - count from zero
}

ISR(TIMER1_COMPA_vect) {                    // comparator match
  digitalWrite(GatePin, HIGH);              // turn on triac gate
  TCNT1 = 0x10000 - PulseWidth;             // trigger pulse width
}

ISR(TIMER1_OVF_vect) {                      // timer1 overflow
  digitalWrite(GatePin, LOW);               // turn off triac gate
  TCCR1B = 0x00;                            // stop timer
}

Caspita che lavorone... grazie !
Ho provato a caricare ma non funziona del tutto:

in pratica il tempo di on del segnale di uscita rimane molto breve( 64usec.) e nonostante tu abbia reso in certe parti il listato più chiaro per un neofita, rimangono parecchi dubbi.
Il primo:
quale parametro devo variare per modificare il ritardo di partenza del segnale di on rispetto al zero crossing.
Dilemma 2:
il tempo di on è troppo breve, come allungarlo?
Allego il link del video per chiarire il problema.
Traccia
La traccia gialla è la frequenza di rete mentre quel sottile picco è l'uscita di Arduino.

Grazie ancora per lo sforzo

… peccato, vedo che questo argomento è veramente ostico per tutti. :sob:

... peccato, vedo che questo argomento è veramente ostico per tutti.

?????

quale parametro devo variare per modificare il ritardo di partenza del segnale di on rispetto al zero crossing.

Devi impostare OCR1A al valore di cicli da cui vuoi partire dopo lo zero crossing. Sapendo che un ciclo in questo caso dura 16µS

// The hardware timer runs at 16MHz. Using a divide by 256 on the counter each count is 16 microseconds

quindi se vuoi ad esempio attivare il triac dopo 80µS
OCR1A = 5
il valore massimo ammesso è 625. ( 50hz = 20mS . Una semionda=10mS )
10mS / 16µS = 625

il tempo di on è troppo breve, come allungarlo?

Stesso discorso di prima. Ogni unità corrisponde a 16µS

#define PULSE 4 //trigger pulse width (counts)

ISR(TIMER1_COMPA_vect){ //comparator match
 digitalWrite(GATE,HIGH); //set triac gate to high
 TCNT1 = 65536-PULSE; //trigger pulse width

dove ogni unità di PULSE corrisponde a 16µS
Quindi se vuoi mantenere alto il Gate del Triac per 240µS #define PULSE 15

Grazie Brunello,
le indicazioni che mi hai dato hanno effettivamente variato i parametri che mi interessavano però purtroppo non riesco ancora a fare quello che mi serve…
Utilizzando un SSR (questo http://www.mouser.com/ds/2/93/s_1-21837.pdf) collegato all’uscita dell’Ardu, quest’ultimo mi fa accendere una lampadina per un tempo brevissimo e con luminosità ridotta dovuta ad un visibile intervento dello stesso.
Modificando i parametri di ampiezza di ON non varia nulla, così come quelli di ritardo ON tramite potenziometro e questo codice

void loop(){ // sample code to exercise the circuit
int sensorValue = analogRead(A0);
sensorValue = map(sensorValue, 0, 1023, 0, 625);
  i=sensorValue;
  OCR1A = i;     //set the compare register brightness desired.
  if (i<65){
   i=625;
  }                      
  delay(15);                             
}

Mi viene il dubbio che forse sia l’ SSR a non essere adatto allo scopo.

Mi viene il dubbio che forse sia l' SSR a non essere adatto allo scopo

Hai il modello con Zero crossing interno.
Che và benissimo come interruttore, ma non puoi farci un regolatore.

Se ti serve solo per regolare una lampadina ( o un'altro carico sempre resisitivo ) puoi usare una tecnica diversa, quella di far passare un certo numero di semionde

Brunello:
Se ti serve solo per regolare una lampadina ( o un'altro carico sempre resisitivo ) puoi usare una tecnica diversa, quella di far passare un certo numero di semionde

Quello va bene per un riscaldatore, per una lampadina no perche' te ne accorgi (sfarfalla)

Quello va bene per un riscaldatore, per una lampadina no perche' te ne accorgi (sfarfalla)

vero !

In realtà a me serve per variare la potenza resa da una resistenza. Proverò a sostituire il SSR con un triac (quindi senza circuito fotoaccoppiatore a bordo) seguendo lo schema che mi ha indicato cyberhs in un post iniziale.

Puoi usare un'optotriac della serie MOC (quelli senza lo zero-crossing ovviamente) per pilotarci un normale triac :wink:

Un SSR é un Triac con pilotaggio optoisolato.
Ciao Uwe

Franchelli:
...Proverò a sostituire il SSR con un triac (quindi senza circuito fotoaccoppiatore a bordo) ..

Vuoi fulminare Arduino e il PC a cui li hai collegato e nello stesso momento suicidarti??
Ciao Uwe

uwefed:
Vuoi fulminare Arduino e il PC a cui li hai collegato e nello stesso momento suicidarti??
Ciao Uwe

Chi ha scritto questo articolo si è suicidato?
http://playground.arduino.cc/Main/ACPhaseControl

Ciao,

nell'articolo c'è chiaramente scritto:

The circuit consists of an opto-isolated zero-crossing detector and a opto-isolated trigger circuit for the triac. The opto-isolators are necessary to keep the low voltage signal circuits away from the power circuits and provide an appropriate level of safety. As will all circuits involving mains voltage, make sure you know what you are doing.

se non usi gli optoisolatori avrai una brutta sorpresa.

X chi legge: se Franchelli non risponde potrebbe significare che non ha letto questo messaggio in tempo :o :o :o

Bye, Ste

Ciao Ste,

nello schema nel link che ho inviato ci sono i optoisolatori sia per il rilevamento dello zero crossing (H11AA1) che per il pilotaggio del triac (MOC3051)
Mi sfugge qualcosa?

PS: sono ancora vivo (anche perchè sono elettricista e sono consapevole su cosa si sta lavorando almeno da lato rete :grin: )