IR Sterung Mit Interrupts

Hey Leute!
Ich würde gern meinen Mega so programmieren, dass er mithilfe einer Fernbedienung und eines IR Receivers jeweils unterschiedliche “Funktionen” ausführt.
Und zwar sozusagen jeweils in einer Schleife, bis eine andere Taste / Funkion gewählt wird.
Ich bin bereits darauf gestoßen, dass das mit einem Timer bzw. Interrupts funktionieren soll…

Hier mal mein aktueller Code… leider ohne Funktion… es wird kein IR Code mehr empfangen…Vielleicht kann mir einer Helfen… :wink:

Lieben dank schonmal!!

#include <TimerOne.h>
#include <IRremote.h>


int RECV_PIN = 11;  // IR-Receiver PIN
int led = 12;       // Satus-LED PIN
int modus;          // Modus für Interrupt-Abfrage
int ledr = 6;       // RGB LED rot PIN
int ledg = 7;       // RGB LED grün PIN                       
int ledb = 8;       // RGB LED blau PIN
int SerialBuffer = 0; 
int RedSum = 0;     // Farbsumme von VLC über serial ROT
int GreenSum = 0;   // Farbsumme von VLC über serial grün
int BlueSum = 0;    // Farbsumme von VLC über serial Blau
int RedVal=1;       // Variablen für Fader
int BlueVal=1;      //  "
int GreenVal=1;     //  "
int i=1;            // Zählervariable für Fader
int timerwert = 50;   // Timer Zeit für Interrupt in ms
int fadespeed = 10;   // Speed für Fade --> 1: extrem schnell
                      //                --> 10: normal
                      //                --> 100: extrem langsam
  
String readString;
/////////////////////////////////////////////////////////////////////////////////////

IRrecv irrecv(RECV_PIN);
decode_results results;

void setup()
{
  pinMode(ledr, OUTPUT); // Setzen der RGB LED Pins als Output
  pinMode(ledg, OUTPUT); // Setzen der RGB LED Pins als Output
  pinMode(ledb, OUTPUT); // Setzen der RGB LED Pins als Output
  
  pinMode(led, OUTPUT); // Status-LED als Output setzen
  
  Serial.begin(38400); // Serial Verbindung zu VLC
 // Serial.begin(9600);
 
  irrecv.enableIRIn(); // Start vom IR-Empfang
  
//   Ethernet.begin(mac, ip, gateway, subnet); // Server Starteb
//   server.begin();
   
  Timer1.initialize(timerwert); // Initialisieren des Timer-Interrupts
  Timer1.attachInterrupt(leseIR); // IR-Einlesen von Interr. ausführen lassen
}

void leseIR(){
// Ständige Abfrage ob Wert von IR Empfangen, trotz LOOP
  if (irrecv.decode(&results)){
    switch (results.value)  {
     
      case 0xFF10EF: // Modus Fade (DIY 4)
        modus = 1;  
      break;
      
      case 0xFF906F: // Modus pcambi (DIY 5)
        modus = 2;  
      break;
      
     
      
      // DIY 1 FF30CF
      // DIY 2 FBB04F
      // DIY 3 FF708F
      // DIY 4 FF10EF
      // DIY 5 FF906F
      // DIY 6 FF50AF 
      
      case 0xFF02FD:  //Power
       modus = 0;
       digitalWrite(led, HIGH);   // Status LED EIN      
       delay(500);                // Pause 0,5s
       digitalWrite(led, LOW);    // Status LED AUS
       setColor(0, 0, 0);         // RGB LEDs ausschalten
      break;
       
       /////////////////////
       //Standart RGB Remote
       /////////////////////
       
      case 0xFFA25D:  //Blau 0,0,255
        modus = 0;
        setColor(0, 0, 255);
      break;
      
      case 0xFF1AE5: //Rot
        modus = 0;
        setColor(255, 0, 0); 
      break;
      
      case 0xFF9A65://Grün
        modus = 0;
        setColor(0, 255, 0); 
      break;  
      
      case 0xFF22DD: //Weiss
        modus = 0;
        setColor(255, 255, 255);
      break;
      
      case 0xFF2AD5: //orange
        modus = 0;
        setColor(255, 165, 0); 
      break;
      
      case 0xFFAA55://Grün mitrtel
        modus = 0;
        setColor(124, 252, 0); 
      break;  
      
      case 0xFF926D: //blau mittel
        modus = 0;
        setColor(92, 172, 238);
      break; 
      
      case 0xFF12ED: //rosa
        modus = 0;
        setColor(255, 228, 196);
      break;      
     
     
     }             // Switch ENDE
  }                // Empfange IR ENDE
 irrecv.resume();  // Receive the next value
}                  // Lese IR ENDE


void setColor (int red, int green, int blue) {
 // RGB LED: write inverted value for each color
  analogWrite(ledr, 255 - red);
  analogWrite(ledg, 255 - green);
  analogWrite(ledb, 255 - blue);

  delay(1000);
}

   
   
   ///////////////////
   /// Fade //////////
   ///////////////////
   
 void fade(int Speed){
  analogWrite(ledr,255-RedVal);
  analogWrite(ledb,255-BlueVal);
  analogWrite(ledg,255-GreenVal);
  
  RedVal =((i<255)*i)+((i>=255)*255)+((i>511)*(512-i))+((i>766)*(i-766))+((i>=1276)*(i-1276))+((i>1530)*(1530-i))+((i>1786)*(1786-i));
  GreenVal =(i<256)*(1)+(i>255)*(i-255)+(i>510)*(510-i)+(i>1020)*(1020-i)+(i>1274)*(i-1274)+(i>1530)*(i-1531)+(i>1785)*(3571-(2*i));
  BlueVal =(i<764)*(1)+(i>765)*(i-765)+(i>1020)*(1020-i)+(i>1786)*(1786-i);

  if(i>2040){
   i = 1;
  }
  
  i++;
  delay(Speed);
 } // Fade ENDE
 
   
void pcambi(){
  ////////////////
 
  ////////////////
  
  digitalWrite(led, HIGH);       // Status LED EIN    
       delay(50);                // Pause 0,5s
      digitalWrite(led, LOW);    // Status LED AUS
         delay(50);
      digitalWrite(led, HIGH);   // Status LED EIN     
       delay(50);                // Pause 0,5s
      digitalWrite(led, LOW);    // Status LED AUS
         delay(50);
      digitalWrite(led, HIGH);   // Status LED EIN      
       delay(50);                // Pause 0,5s
      digitalWrite(led, LOW);    // Status LED AUS
    
    


void loop() {
if(modus==1){    // Abfrage pb Modus:1 in Interrupt gesetzt
fade(fadespeed); // Starte Fade
}

if(modus==2){    // Abfrage pb Modus:2 in Interrupt gesetzt
pcambi();        // pcaMBI
}

if(modus==3){    // Abfrage pb Modus:3 in Interrupt gesetzt
//starteServer();
}
   
   
   
  } // LOOP  Ende

Du musst alle delays aus dem Pogramm entfernen wie soll der Ardu was auswärten wenn er immer wieder irgendwo warten muss. Die Delay rasuschmeissen und mit millis() vergleichen arbeiten wie in dem Beispiel Blinkwithout delay. Gruß Der Dani

Ich glaube nicht daß, Du das mit einem Interrupt realisieren mußt. Ich würde sagen ein Interrupt stört in diesem Sketch nur. Ein delay in der unterrupfunktion ist tödlich für die correkte funktion des sketches. Vergiß den Interrupt und mache alles im loop() ohne delay, nur mit millis().

Grüße Uwe

Sagt mal… könnte man die delay() Funktion nicht z.B. durch diese Funktion ersetzen? oder meint ihr das wäre nicht sonderlich effektiv?

void wait_mseconds(long msek){
    unsigned long currentMillis = millis();
    long previousMillis = millis();
    
      while(currentMillis - previousMillis < msek){
        currentMillis = millis();
      }

Diese Funktion bremst den Programmablauf ebenso wie delay. Wozu sollte das gut bzw. besser sein?

Naja.. wenn in einem sketch mehre delays verwendet werden... ist es doch ziemlich aufwendig, jedes Mal diese "blinkwithout delay Methode" zu nutzen... Oder sehe ich das irgendwie falsch?

Vielleicht liege ich ja komplett falsch.. Aber das Ziel vom Threadersteller hat mich auch schon beschäftigt... vll kann ja mal jemand mit Ahnung den Code von oben "reparieren".. :roll_eyes:

t-lie: Naja.. wenn in einem sketch mehre delays verwendet werden... ist es doch ziemlich aufwendig, jedes Mal diese "blinkwithout delay Methode" zu nutzen... Oder sehe ich das irgendwie falsch?

Ist es nicht, denn der Aufwand ist immer gleich. Am Anfang der loop() wird das aktuelle millis() Wert gespeichert und an jeder delay() Stelle schaut man ob die gewünschte Wartezeit schon rum ist, wenn nicht, macht man nix, ansonsten merkt man sich den aktuellen millis() Wert für den nächsten Durchlauf und führt die gewünschte Aktion aus.

Also sind wir mal ehrlich... wenn man die delays im oberen Code durch diese Methode ersetzen würde... das würde doch eine riesen Verschachtelung werden?!

Kannst mich gern vom Gegenteil überzeugen..

Hast Du Dir das Beispiel http://arduino.cc/en/Tutorial/BlinkWithoutDelay eigentlich mal angesehen? Wenn man den Code in entsprechende funktionale Blöcke teilt, die jeweils einen Status haben, ob sie aktiv sind und jeweils ihren eigenen "delay ohne delay" millis-Wert verwalten, wird es vermutlich sogar übersichtlicher. Natürlich kann man nicht einfach dealy(xxx) durch einen BlinkWithoutDelay Vergleich ersetzen, der Code muss dafür schon umstrukturiert werden. Aber es geht ja am Ende darum, das nicht ein Block durch das delay alle anderen blockiert.

Würde dieser Code funktionieren:

void wait(int interval,int led) {
long previousMillis = 0;  
bool once = false;
if (once == false) {
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
digitalWrite(led, HIGH); // Hier Code einfügen
once = true;
  }
 } 
}

Addi

Sicher nicht! Bei jedem Funktionsaufruf wird

long previousMillis = 0;  
bool once = false;

gesetzt und erreicht somit nie die Endzeit.

Grüße Uwe

Ich hab mal fix eine Library gebaut, die den BlinkWithoutDelay Code kapselt. ZIP-File ist angehängt. Ausgepackt kommt der Ordner WaitWithoutDelay in den libraries Ordner.
Nach dem Neustart gibt es unter “Datei → Beispiele → WaitWithoutDelay” ein Example “BlinkWaitWithoutDelay”, das im wesentlichen dem BlinkWithoutDelay entspricht, nur ohne das rumrechnen mit den millis. Das macht die Klasse selbst.
Wenn man mehrere “delays” braucht, erzeugt man einfach mehrer Objekte der Klasse.
Evtl. hilft das ja dem Einen oder Anderen.

Mario.

WaitWithoutDelay.zip (2.23 KB)

if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

Hallo Mario das oben ist ein Auszug aus dem Beispiel der WaitWithoutDelay Bibliothek. Mir entzieht sich der Sinn dieses ELSE-Teils.

Außerdem gibt mir das Beispiel beim kompilieren mit IDE0022 folgende Fehlermeldung:

sketch_oct17a.cpp.o: In function setup': C:\DOKUME~1\alfa\LOKALE~1\Temp\build8797646699440134618.tmp/sketch_oct17a.cpp:16: undefined reference tooperator new(unsigned int)'

Grüße Uwe

Mir entzieht sich der Sinn dieses ELSE-Teils.

Soll wohl

ledState = ! ledState;

machen...

Die Lib mag ja für "die einfache LED" ganz nett und hilfreich sein... Doch wie würde man das, jetzt mal anhand des Beispiel im Startthread, bei diesem Abschnitt machen?

void setColor (int red, int green, int blue) {
 // RGB LED: write inverted value for each color
  analogWrite(ledr, 255 - red);
  analogWrite(ledg, 255 - green);
  analogWrite(ledb, 255 - blue);

  delay(1000);
}

@Uwe: Ich habe für das Beispiel den Code des originalen BlinkWithoutDelay verwendet, damit es leichter vergleichbar ist. Ansonsten hätte ich den Zustandwechsel auch mit einem state = ! state abgekürzt.

Zum Fehler in der IDE0022, hier kann man das new vermutlich durch folgenden Aufruf ersetzen: WaitWithoutDelay mywait = WaitWithoutDelay(1000);. Dann müssen Methoden des Objekts aber mit "." statt mit "->" referenziert werden.

@t-lie: z.B. so:

void setColor (int red, int green, int blue) {
 static  WaitWithoutDelay localwait = WaitWithoutDelay(1000);

 if(localwait.wait()) {
    Serial.println("setColor called");
    // RGB LED: write inverted value for each color
    analogWrite(ledr, 255 - red);
    analogWrite(ledg, 255 - green);
    analogWrite(ledb, 255 - blue);
  }
}

Damit kann man die Funktion sooft aufrufen wie man will, sie wird nur nach Ablauf einer Sekunde die Farbe der LED ändern. Ich persönlich würde das "Hilfs delay" aber nicht in die Funktion selbst packen, sondern den Aufruf der Funktion in das Wait kapseln. Das hat den Vorteil, das die Funktion setColor() an verschiedenen Stellen im Programm verwendbar ist, wobei es durchaus vorkommen kann, das man gar kein oder ein anderes delay haben möchte als die fixen 1000ms. Das geht natürlich nur, wenn sich die Funktion selbst nicht um das delay kümmert. Die Funktion setColor() hat die Aufgabe die Farbe eine LED per PWM zu setzen, daher sollte sie auch nicht mehr machen.

mkl0815: @Uwe: Ich habe für das Beispiel den Code des originalen BlinkWithoutDelay verwendet, damit es leichter vergleichbar ist. Ansonsten hätte ich den Zustandwechsel auch mit einem state = ! state abgekürzt. ...

Das gestern war nicht mein bester Tag. Du hast Recht. Grüße Uwe

Also das ist jetzt der Abgeänderte Code geht aber immernoch nich noch jemand Ideen ?

#include <TimerOne.h>
#include <IRremote.h>
#include <WaitWithoutDelay.h>


int RECV_PIN = 11;  // IR-Receiver PIN
int led = 12;       // Satus-LED PIN
int ledState = 0;   // Zustand Status LED
int modus;          // Modus für Interrupt-Abfrage
int ledr = 6;       // RGB LED rot PIN
int ledg = 7;       // RGB LED grün PIN                       
int ledb = 8;       // RGB LED blau PIN
int SerialBuffer = 0; 
int RedSum = 0;     // Farbsumme von VLC über serial ROT
int GreenSum = 0;   // Farbsumme von VLC über serial grün
int BlueSum = 0;    // Farbsumme von VLC über serial Blau
int RedVal=1;       // Variablen für Fader
int BlueVal=1;      //  "
int GreenVal=1;     //  "
int i=1;            // Zählervariable für Fader
int fadespeed = 10;   // Speed für Fade --> 1: extrem schnell
                      //                --> 10: normal
                      //                --> 100: extrem langsam
  
/////////////////////////////////////////////////////////////////////////////////////

IRrecv irrecv(RECV_PIN);
decode_results results;

void setup()
{
  pinMode(ledr, OUTPUT); // Setzen der RGB LED Pins als Output
  pinMode(ledg, OUTPUT); // Setzen der RGB LED Pins als Output
  pinMode(ledb, OUTPUT); // Setzen der RGB LED Pins als Output
  
  pinMode(led, OUTPUT); // Status-LED als Output setzen
  
  Serial.begin(38400); // Serial Verbindung zu VLC
 // Serial.begin(9600);
 
  irrecv.enableIRIn(); // Start vom IR-Empfang
}

void leseIR(){
// Ständige Abfrage ob Wert von IR Empfangen, trotz LOOP
  if (irrecv.decode(&results)){
    switch (results.value)  {
     
      case 0xFF10EF: // Modus Fade (DIY 4)
        modus = 1;  
      break;
      
      case 0xFF906F: // Modus pcambi (DIY 5)
        modus = 2;  
      break;
      
     
      
      // DIY 1 FF30CF
      // DIY 2 FBB04F
      // DIY 3 FF708F
      // DIY 4 FF10EF
      // DIY 5 FF906F
      // DIY 6 FF50AF 
      
      case 0xFF02FD:  //Power
       modus = 0;
       setColor(0, 0, 0);         // RGB LEDs ausschalten
      break;
       
       /////////////////////
       //Standart RGB Remote
       /////////////////////
       
      case 0xFFA25D:  //Blau 0,0,255
        modus = 0;
        setColor(0, 0, 255);
      break;
      
      case 0xFF1AE5: //Rot
        modus = 0;
        setColor(255, 0, 0); 
      break;
      
      case 0xFF9A65://Grün
        modus = 0;
        setColor(0, 255, 0); 
      break;  
      
      case 0xFF22DD: //Weiss
        modus = 0;
        setColor(255, 255, 255);
      break;
      
      case 0xFF2AD5: //orange
        modus = 0;
        setColor(255, 165, 0); 
      break;
      
      case 0xFFAA55://Grün mitrtel
        modus = 0;
        setColor(124, 252, 0); 
      break;  
      
      case 0xFF926D: //blau mittel
        modus = 0;
        setColor(92, 172, 238);
      break; 
      
      case 0xFF12ED: //rosa
        modus = 0;
        setColor(255, 228, 196);
      break;      
     
     
     }             // Switch ENDE
  }                // Empfange IR ENDE
 irrecv.resume();  // Receive the next value
}                  // Lese IR ENDE


void setColor (int red, int green, int blue) {
 static  WaitWithoutDelay localwait = WaitWithoutDelay(1000);
 
 if(localwait.wait()) {
    //Serial.println("setColor called");
    // RGB LED: write inverted value for each color
    analogWrite(ledr, 255 - red);
    analogWrite(ledg, 255 - green);
    analogWrite(ledb, 255 - blue);
  }
}
   
   
   ///////////////////
   /// Fade //////////
   ///////////////////
   
 void fade(int Speed){
    static  WaitWithoutDelay localwait = WaitWithoutDelay(Speed);
 
 if(localwait.wait()) {
   
  analogWrite(ledr,255-RedVal);
  analogWrite(ledb,255-BlueVal);
  analogWrite(ledg,255-GreenVal);
  
  RedVal =((i<255)*i)+((i>=255)*255)+((i>511)*(512-i))+((i>766)*(i-766))+((i>=1276)*(i-1276))+((i>1530)*(1530-i))+((i>1786)*(1786-i));
  GreenVal =(i<256)*(1)+(i>255)*(i-255)+(i>510)*(510-i)+(i>1020)*(1020-i)+(i>1274)*(i-1274)+(i>1530)*(i-1531)+(i>1785)*(3571-(2*i));
  BlueVal =(i<764)*(1)+(i>765)*(i-765)+(i>1020)*(1020-i)+(i>1786)*(1786-i);

  if(i>2040){
   i = 1;
  }
  
  i++;
 }
 } // Fade ENDE
 
   
void pcambi(){
  ////////////////
 
  ////////////////
  static  WaitWithoutDelay localwait = WaitWithoutDelay(500);
 
   if(localwait.wait()) {
     if(ledState==1){
        digitalWrite(led, LOW);    // Status LED AUS 
        ledState = 0;
     }else{
     digitalWrite(led, HIGH);       // Status LED EIN
     ledState = 1;
 }
}
}
void loop() {
  leseIR();
if(modus==1){    // Abfrage pb Modus:1 in Interrupt gesetzt
fade(fadespeed); // Starte Fade
}

if(modus==2){    // Abfrage pb Modus:2 in Interrupt gesetzt
pcambi();        // pcaMBI
}

if(modus==3){    // Abfrage pb Modus:3 in Interrupt gesetzt
}
   
   
   
  } // LOOP  Ende

Wie bereits geschrieben, mußt Du die Struktur Deines Programms ein wenig anpassen. WaitWithoutDealy funktioniert nicht wie ein einfaches dealy, es wird also nicht an der Stelle gewartet. Das Programm merkt sich auch nicht, wo noch etwas zu tun wäre, wenn die Wartezeit abgelaufen ist. Ein Beispiel: In der Funktion leseIR() wird überall setColor() aufgerufen, aber nur wenn ein bestimmter Wert von der Fernbedienung erkannt wurde. So wie das geänderte setColor() jetzt funktioniert, wird es in 99% der Fälle wo es aufgerufen wird nichts tun, weil die Bedingung (localwait->wait()) nicht erfüllt ist. Das ist der Grund warum ich geschrieben habe, das das Warten nicht in die setColor() Funktion gehört. Ich würde sämtliche Aufrufe von setColor() in die loop() verlagern, nur dort wird geschaltet. leseIR() sollte nur die Variable modus setzen und zusätzlich 3 Variablen für den Farbwert von rot, grün und blau. Das WaitWithoutDelay muss aus setColor() raus, wenn Farbe setzen, das sofort ohne Verzögerung. Dort wo Du eine Verzögerung brauchst, kapselst Du den Aufruf von setColor() mit dem WaitWithoutDelay. Das "modus" ist schon ein sehr guter Ansatz, diese Variable definiert ja in welchem Status sich Dein Programm befindet, nur muss der Modus "0" auch in der lopp() wiederfinden.

//delay für RGB-LED
WaitWithoutDealy colorWait = WaitWithoutDealy(1000);

//werte für RGB-LED, werden von leseIR() gesetzt
int r,g,b = 0;

void loop() {
  //IR lesen
  leseIR();
  
  switch(modus) {
   case 0:
      if(colorWait.wait()) {
         setColor(r,g,b)  
      }
      break;

   case 1:
      fade(fadespeed);
      break;
  
   case 2:
      pcambi();
      break;
  
   case 3: 
      break;
    
  }
  
} // LOOP  Ende

Der Trick beim BlinkWithoutDelay ist, das Dein Arduino wie "irre" immer wieder die Funktion loop() durchläuft, mehrere tausend Mal pro Sekunde. Anhand der Variable "modus" weiss das Programm in welchen Case-Block (switch innerhalb von loop()) es jeweils aktiv werden muss. Dort sorgt dann aber das WaitWithoutDelay (in meiner Beispiel-loop() exemplarisch für setColor()) dafür, das z.B. setColor() nicht tausend Mal pro Sekunde aufgerufen wird, sondern immer nur, wenn eine Sekunde vergangen ist. Allerdings blockiert die setColor() Funktion dabei nicht das komplette Programm. Das leseIR() wird nämlich bei jedem loop() Durchlauf aufgerufen.

Allerdings frage ich mich eh schon die ganze Zeit, warum das "delay" für das setColor() überhaupt gebraucht wird. Wenn ich auf der Fernbedienung der Knopf für "Rot" drücke, sollte das doch gleich umschalten, oder? Beim "fade" macht das schon mehr Sinn. Auch bei der Funktion pcambi() sehe ich das ein, weil hier im 500ms Takt geblinkt werden soll.

Nun zu Deinem "geht aber immer noch nicht". Was genau geht denn nicht? Werden überhaupt Befehle von der Fernbedienung erkannt? Hast Du mal Debugausgaben auf die serielle Schnittstelle gemacht, um zu sehen was Dein Programm überhaupt macht? Hast Du einzelne Teile des Programms mal separat getestet?

Mario.