ATtiny85, Triac e IRremote problemi Zero Crossing

Ho realizzato un telecomando IRremote che comanda una lampada 220V tramite un TRIAC.

Se imposto un tempo manualmente (ho scelto 1000 - 9500uS) funziona, da accesa a spenta,
quind il TRIAC da solo funziona .

Il telecomando senza la schedina con il circuito dello Zero Crossing funziona!
Eseguo i comandi che imposto nella routine IRr_comandi(void) senza problemi.
Riesco a comandare anche il TRIAC ON/OFF.

Se inserisco la schedina dello Zero Crossing non riesco più ad eseguire i comandi impostati,
praticamente non vengono decodificati.

Penso che IRremote impieghi molto tempo per elaborare i comandi ricevuti e non ci sia il
tempo ( tra due zero crossing) suffuciente per eseguirre la decodifica del tasto premuto.
Che pensate?

Questo è il mio codice, in allegato c’è anche lo schema.

#include <IRremote.h>
int RECV_PIN = 3; //Pin dove è collegat IR. Telecomando PHILIPS
#define LED1 1
#define TRIAC 4
byte led_ric=0;
byte int_IRr=100;
int varia=5000;
decode_results results;   //Variabile ricezione.
IRrecv irrecv(RECV_PIN);  //
//---Predisposizione--------------------
void setup(void){
  pinMode(TRIAC,OUTPUT);
  pinMode(LED1,OUTPUT);
  irrecv.enableIRIn();    //Avvio ricevitore infrarossi.
  delay(50);
  attachInterrupt(0,Zero_Cross,RISING);
}
//---Ciclo principale--------------------------------------
void loop(void){
  if(irrecv.decode(&results)) {       //Se un tasto è stato premuto.
    delayMicroseconds(30);
    IRr_comandi();
    results.value=0;
    irrecv.resume();
  }  
}
//Esegue i comandi del telecomando-----------------------
void IRr_comandi(void){
  if(results.value==824){        //Rosso.
    led_ric=1;
    if(varia<9400){varia+=100;}    //
  }else if(results.value==2872){ //Verde. 
    led_ric=1;
    if(varia>1000){varia-=100;}
  }
  if(led_ric){digitalWrite(LED1,HIGH);}
  delay(150);
  digitalWrite(LED1,LOW);
  led_ric=0;
}
//---Routine di Interrupt--------------------------------
void Zero_Cross(void){
  delayMicroseconds(varia);   //Tempo 1000-9500 microsecondi.
  digitalWrite(TRIAC,HIGH);
  delayMicroseconds(50);
  digitalWrite(TRIAC,LOW);
}

Controllo_IRemote.tar.gz (131 KB)

Nella routine di interrupt non puoi usare millis() o delay() poiché queste funzioni sono bloccate.

Nella routine di interrupt non puoi usare millis() o delay() poiché queste funzioni sono bloccate.

Non ho capito il perchè.
Non mi spiego come mai se nel loop() inserisco questo codice.

if(aum_dim==1){
    for(int i=1000; i <= 9500; i+=3){
      varia=i;
      delay(1);
    }
    digitalWrite(LED1,LOW);
    aum_dim=0;
  }else{
    for(int i=9500; i >= 1000; i-=3){
      varia=i;
      delay(1);
    }
    aum_dim=1;  
    digitalWrite(LED1,HIGH);
  }

funziona bene. Avviene una variazione della lumonosità in aumento poi in diminuzione
molto lineare, la lampada si accende bene senza disturbi.
Secondo me la routine di Interrupt non ha problemi.

//---Routine di Interrupt--------------------------------
void Zero_Cross(void){
  delayMicroseconds(varia);   //Tempo 1000-9500 microsecondi.
  digitalWrite(TRIAC,HIGH);
  delayMicroseconds(50);
  digitalWrite(TRIAC,LOW);
}

Il problema è che la routine void IRr_comandi(void){ viene si richiamata ad ogni
zero crossing (verificato) ma non incrocia i codici impostati in tale routine pertanto
non ne esegue i comandi.

Pensavo ad utilizzare 2 ATtiny85 uno per la comunicazione con IRremote e l’altro
per il dimmer.
ATtiny85 IRremote passerebbe le informazioni al dimmer tramite un 1 pin.

Secondo me la variabile Int varia deve essere dichiarata volatile per essere cambiata nella funzione IR

Dal manuale:
http://arduino.cc/en/Reference/Volatile

Ciao
Gio

Non ho capito il perchè...

Le funzioni temporali lavorano tramite interrupt, quindi non funzionano all'interno di una routine invocata da interrupt.

In particolare, è come se nella tua routine tu abbia:

void Zero_Cross(void){
//  delayMicroseconds(varia);   //Tempo 1000-9500 microsecondi.
  digitalWrite(TRIAC,HIGH);
//  delayMicroseconds(50);
  digitalWrite(TRIAC,LOW);
}

delayMicroseconds() non usa gli interrupt quindi non crea problemi.

Inside the attached function, delay() won't work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function. If your sketch uses multiple ISRs, only one can run at a time, other interrupts will be ignored (turned off) until the current one is finished. As delay() and millis() both rely on interrupts, they will not work while an ISR is running.

The delayMicroseconds() function in contrast uses a simple wait loop and disables interrupts before execution (and then restores SREG after execution), so you can use it in interrupt routines. delayMicroseconds(), which does not rely on interrupts, will work as expected.

E la libreria IRemote che usando gli Interrupt va in conflitto con lo Zero-crossing e sbaglia i suoi conteggi degli impulsi IR. http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html

Ciao Gio

The delayMicroseconds() function in contrast uses a simple wait loop and disables interrupts before execution (and then restores SREG after execution), so you can use it in interrupt routines. delayMicroseconds(), which does not rely on interrupts, will work as expected.

Dove hai trovato questa affermazione?

Comunque, come dice espressamente, vengono disabilitati gli interrupt e non capisco come possa essere utilizzato in una routine di interrupt.

Ho preso spunto principalmente da qui: http://arduino.cc/en/Reference/attachInterrupt

Ciao Gio

Hai ragione, pare sia possibile.