Infrarot Empfänger

In meinem Artikel habe ich auf eine sehr günstige Variante aufmerksam gemacht, einen Arduino mittels Fernbedienung zu steuern. Dazu kann man nahe zu jede Fernbedienung nutzen die man zu Hause noch von alten Geräten herum liegen hat.

Passend zu diesem Empfänger habe ich ein kleines Programm geschrieben mit dem man die einzelnen Tasten auf dem Arduino erkennen kann. Das Prinzip ist dabei ziemlich einfach. Die Fernbedienung oben auf dem Bild sendet die Daten immer nach dem gleichen Muster. Ein Datenpaket besteht aus einer Startkennzeichnung 32 Bit Daten und einer Endkennzeichnung. Die Länge vom Start bis zum Ende ist immer die gleiche. Ein kurzer HIGH Pegel Symbolisiert eine Null und ein längerer HIGH Pegel eine Eins.

Hier sieht man, dass die ersten 8 Bit Null sind, die zweiten 8Bit sind alle Eins. Bei jeder Taste sind die ersten 16Bit immer die gleichen. Daher benötigt man nur die zweiten 16 Bit um die einzelnen Tasten zu unterscheiden. Das kann bei anderen Fernbedienungen aber anders sein.

Die Auswertung ist daher ziemlich einfach. Wenn nichts passiert ist der Ausgang des Sensors HIGH. Daher wartet man einfach so lange bis er auf LOW gezogen wird. Anschließend nutzt man die Arduino Funktion micros() um die Zeit zu zählen wie lange das Signal HIGH Pegel hat. Diese Informationen werden in eine 16 Bit Variable gepackt damit man die Tasten einfacher unterscheiden kann. Genauer könnt ihr es direkt im Arduino Code nachlesen.

 

AVR-GCC Code

Zusätzlich gibt es auch noch einen Code in avr-gcc geschrieben. Alles weitere Dazu steht im passenden Artikel.

 

Arduino Code

4 Kommentare zu Infrarot Empfänger

  1. Detlef sagt:

    Hallo Kalle,
    ich habe den Code für die IR-Abfrage ausgelagert, um das Problem zu verdeutlichen. Teste zunächst die auskommentierte Variante (s. u.). Ich bekomme eine Erkennungsquote von ca. 70%, d. h. 3 von 10 Tastendrücke gehen unter. Mit TIMEOUT 5000 war es etwas besser als mit 100000.
    Vergleiche dann mal die Effekte durch Auskommentieren der Interruptinitialisierung bzw. der simulierten Ablenkung.


    #define IRPIN 2

    #define TIMEOUT 5000 // 100000
    #define LOW_TRESH 100
    #define HIGH_TRESH 1000
    #define HIGH_MAX_TRESH 3000

    #define DEBUG

    void setup()
    {
    Serial.begin(9600);
    Serial.println("empfangene IR-Codes:");

    pinMode(IRPIN, INPUT);

    // nächste Zeile auskommentieren, um zu zeigen, wie schnell die Fernbedienung über Interrupt schaltet:
    // attachInterrupt(0, Interruptaufruf, FALLING); // Digitalpin 2

    }

    void loop()
    {
    Fernbedienung();
    // nächste Zeile auskommentieren, um zu zeigen, dass der Arduino die Fernbedienung nicht mehr beachtet:
    // delay(500); // Simulation: Arduino bearbeitet andere Abfragen
    }

    unsigned int startReceive()
    {
    unsigned long l = 0;
    unsigned long h = 0;
    unsigned char counter = 0;
    unsigned char state = 0;
    unsigned char stateArray[50];
    unsigned int ret = 0;

    do
    {
    state = 2;
    h = wait(HIGH);
    l = wait(LOW);

    if (h HIGH_TRESH)
    {
    state = 1;
    }
    else if (h > LOW_TRESH)
    {
    state = 0;
    }
    }
    stateArray[counter] = state;

    counter++;

    if (counter == 50) // 50
    {
    return 0;
    }
    }
    while (l < TIMEOUT && h < TIMEOUT);

    if (counter < 34)
    {
    return 0;
    }

    unsigned char j = 0;
    for (unsigned char i = 0; i 0 && i 8 && i 16 && i < 33)
    {
    ret |= stateArray[i] < TIMEOUT)
    {
    break;
    }
    }

    return micros() - start;
    }
    void Fernbedienung() {

    /*
    0: 59670
    100+: 58905
    200+: 61965
    1: 62220
    2: 59160
    3: 41310
    4: 63240
    5: 58140
    6: 42330
    7: 48450
    8: 44370
    9: 46410
    CH-: 47685
    CH: 47430
    CH+: 47175
    prev: 47940 !
    next: 48960 !
    Play: 48195
    Vol-: 63495 !
    Vol+: 59925 !
    eq: 62985
    */
    // warten bis der pin auf LOW Level gezogen wird
    if (digitalRead(IRPIN) == LOW)
    {
    // wait for next high
    while (digitalRead(IRPIN) == LOW) {}
    unsigned int t = startReceive();

    if (t > 0)
    {
    switch (t) {
    case 59670: t = 0; break;
    case 62220: t = 1; break;
    case 59160: t = 2; break;
    case 41310: t = 3; break;
    case 63240: t = 4; break;
    case 58140: t = 5; break;
    case 42330: t = 6; break;
    case 48450: t = 7; break;
    case 44370: t = 8; break;
    case 46410: t = 9; break;
    }
    Serial.println();
    Serial.print("IR-Code = ");
    Serial.println(t);
    }
    }
    }

    void Interruptaufruf() {
    Serial.println("Interruptaufruf");
    }

    • Kalle sagt:

      Moin Detlef,
      vielen Dank für deine Mühe. Entschuldige bitte, dass ich dir jetzt erst antworte.
      Beim Arduino Code ist es leider nicht immer ersichtlich was im Hintergrund alles passiert. Das ist wohl der „Einfachheit“ geschuldet.
      Ich hatte schon des öfteren Probleme mit Interrupts in einem Arduino Code.
      Daher wäre es interessant, ob du das Problem genauer lokalisieren kannst.

      Dazu kommt, wenn während des Empfangs ein Interrupt ausgelöst wird, dann wieder dieser vorrangig behandelt und stört somit den Empfang. Ein Interrupt wird z.B. oft vom internen Timer ausgelöst um die micros und millis hoch zu zählen. Daher ist meine Variante mit den Micros auch eher sub optimal.

      Eigentlich müsste man während des Empfangs alle Interrupts deaktivieren und über einen Timer die Takte zählen.

      LG
      Kalle

  2. Detlef sagt:

    Hallo Kalle,
    vielen Dank für den Code. Die Fernbedienung liefert munter Daten, im Polling-Betrieb klappt es wirklich gut, solange keine anderen Unterprogramme laufen. Andernfalls tritt das Problem auf, dass entweder FB-Signale überhört werden oder die anderen Aufgaben nicht abgearbeitet werden. Hast Du mal versucht, Deine Loop in ein Unterprogramm auszulagern und die FB über Interrupt abzufragen?

    • Kalle sagt:

      Moin Detlef,
      nein das habe ich noch nicht geprüft. Hatte bisher noch nicht die Zeit dazu.
      Wäre aber nett, wenn du künftige Erfahrungen auch noch mal posten kannst.
      Gerne können wir auch ein repo auf Github dazu anlegen in dem wir zusammen den Code weiter entwickeln könnten.

      LG
      Kalle

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Time limit is exhausted. Please reload CAPTCHA.