Infrarot Fernbedienung mit Arduino verwenden
In dieser Anleitung zeigen wir, wie eine Infrarot-Fernbedienung mit Empfänger an einem Arduino UNO kompatiblen Board verwendet wird.
Übersicht
IR-Fernbedienungen senden binäre Impulse als Signal im unsichtbaren Infrarotbereich aus. Um Störsignale von anderen Quellen zu vermeiden, werden die Signale vormoduliert und erst dann mit Hilfe einer IR-LED in einer bestimmten Frequenz gesendet.
Der IR-Empfänger besitzt in der Regel eine IR-Fotodiode, die Signale auf einer bestimmten Frequenz empfängt und Störungen von anderen Lichtquellen filtert. Hinter der IR-Fotodiode befindet sich dann meistens ein Signalverstärker und Demodulator, um das Signal weiterverarbeiten zu können.
Benötigte Komponenten
- Arduino UNO R3 kompatibles Board
- Breadboard
- 11 Jumperkabel
- 1x IR Fernbedienung
- 1x IR Empfänger
- 6x 220 Ohm Widerstand
- 6x LED
Funktionsweise
Der IR-Empfänger wandelt das Lichtsignal, welches von der IR-LED gesendet wird, in ein schwaches, elektronisches Signal um. Dieses Signal wird dann durch einen IC verstärkt, automatisch gefiltert, geglättet und demoduliert, bis das ursprüngliche Signal der Fernbedienung wiederhergestellt ist. Dieses Signal wird dann an den Output-Pin des IR-Empfängers gesendet.
Verschlüsselung mit NEC-Protokoll
Um die Signale einer IR-Fernbedienung auszulesen, muss zuerst bekannt sein, wie diese verschlüsselt sind. Die Verschlüsselung in unserem Beispiel ist das NEC-Protokoll.
Technische Daten des NEC-Protokolls
- 8-bit Adressen und 8-bit Befehlslängen.
- Adresse und Befehl werden zur Verlässlichkeit immer wiederholt.
- Puls Distance Modulation (PDM)
- Frequenz von 38 Khz
- Bit time von 1.125 ms oder 2.25 ms
Diese Abbildung zeigt eine typische Impulsfolge des NEC-Protokolls. Bei diesem Protokoll wird das LSB (Least Significant Bit) zuerst übertragen. In diesem Fall werden die Adresse $59 und der Befehl $16 übertragen. Eine Nachricht wird durch einen 9 ms AGC-Burst eingeleitet, der bei den früheren IR-Empfängern zur Einstellung der Verstärkung verwendet wurde. AGC steht kurz für engl. „automatic gain control“ und dient dazu, den Ausgangspegel eines Verstärkers konstant zu halten.
Auf diesen AGC-Burst folgt ein 4,5 ms langes Leerzeichen, auf das die Adresse und der Befehl folgen. Adresse und Befehl werden zwei Mal übertragen, um die Fehlerquote zu verringern. Beim zweiten Übertragen sind alle Bits invertiert und können zur Überprüfung der empfangenen Nachricht verwendet werden. Die Gesamtübertragungszeit ist konstant, da jedes Bit mit seiner invertierten Länge wiederholt wird. Wird diese Zuverlässigkeit nicht benötigt, können du die invertierten Werte auch ignoriert oder die Adresse und der Befehl auf jeweils 16 Bit erweitert werden.
Ein Impuls wird gesendet, wenn eine Taste gedrückt und nach einer bestimmten Zeit losgelassen wird.
Ein Befehl wird nur einmal übertragen, auch wenn die Taste der Fernbedienung gedrückt bleibt. Alle 110ms wird ein Wiederholungscode gesendet, solange die Taste gedrückt bleibt. Dieser Wiederholungscode ist einfach ein 9ms AGC-Burst, gefolgt von einer 2,25ms Pause und einem 560µs Burst.
Wenn der Impuls im Empfänger eintrifft, findet eine Dekodierung, Signalverstärkung und Wellenglättung statt. Es muss sichergestellt sein, dass der Ausgangspegel genau das Gegenteil von dem des sendenden Signals ist. Das heißt, wenn kein Infrarotsignal vorhanden ist, ist der Ausgangspegel hoch; Wenn ein Infrarotsignal vorhanden ist, ist der Ausgangspegel low. Das Signal des Empfängers kann mit einem Oszilloskop untersucht werden, um das Signal besser zu verstehen.
Anschlussplan
Den VOUT-Pin vom IR-Empfänger wir auf Pin 11 angeschlossen. Die LEDs mit den Widerständen kommen an die Pins 2, 3, 4, 5, 6, 7. Die Spannungsversorgung erfolgt über den BUS des Breadboards, verbunden mit GND und 5V vom Arduino.
Code für Arduino
Für den Code wird die IRremote Bibliothek verwendet. Das Programm dekodiert das verschlüsselte Signal der IR-Fernbedienung. So können im seriellen Monitor der Arduino IDE die Signale der Fernbedienung ausgelesen werden. Mit diesen Signalen kann dann die Anwendung - in diesem Beispiel die 6 LEDs - gesteuert werden.
Die Codes können je nach Fernbedienung und Charge variieren. Soll z. B. die Tastenbelegung zum Einschalten der ersten LED geändert werden, muss folgende Zeile geändert werden:
long on1 = 0x00FFA25D;
Diese Zeile wird angepasst, um die erste LED einzuschalten. Wie im seriellen Monitor zu erkennen, entspricht FFA25D der ersten Taste der Fernbedienung.
Nun können der angepasste Sketch erneut hochgeladen und die LEDs mit Hilfe der Taste angeschaltet werden. So können nach der Reihe alle LEDs den Tasten zugewiesen werden.
Code anzeigen / einklappen
#include <IRremote.h>
int RECV_PIN = 11; // Pin vom IR-Empfänger
int LED1 = 2; // LED Pin
int LED2 = 3; // LED Pin
int LED3 = 4; // LED Pin
int LED4 = 5; // LED Pin
int LED5 = 6; // LED Pin
int LED6 = 7; // LED Pin
// Ab hier können Sie die Tastenbelegung anpassen
long on1 = 0x00FFA25D;
long off1 = 0x00FFE01F;
long on2 = 0x00FF629D;
long off2 = 0x00FFA857;
long on3 = 0x00FFE21D;
long off3 = 0x00FF906F;
long on4 = 0x00FF22DD;
long off4 = 0x00FF6897;
long on5 = 0x00FF02FD;
long off5 = 0x00FF9867;
long on6 = 0x00FFC23D;
long off6 = 0x00FFB04F;
IRrecv irrecv(RECV_PIN);
decode_results results;
// Dumps out the decode_results structure.
// Call this after IRrecv::decode()
// void * to work around compiler issue
//void dump(void *v) {
// decode_results *results = (decode_results *)v
void dump(decode_results *results) {
int count = results->rawlen;
if (results->decode_type == UNKNOWN) {
Serial.println("Could not decode message");
} else {
if (results->decode_type == NEC) {
Serial.print("Decoded NEC: ");
} else if (results->decode_type == SONY) {
Serial.print("Decoded SONY: ");
} else if (results->decode_type == RC5) {
Serial.print("Decoded RC5: ");
} else if (results->decode_type == RC6) {
Serial.print("Decoded RC6: ");
}
Serial.print(results->value, HEX);
Serial.print(" (");
Serial.print(results->bits, DEC);
Serial.println(" bits)");
}
Serial.print("Raw (");
Serial.print(count, DEC);
Serial.print("): ");
for (int i = 0; i < count; i++) {
if ((i % 2) == 1) {
Serial.print(results->rawbuf[i]*USECPERTICK, DEC);
} else {
Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC);
}
Serial.print(" ");
}
Serial.println("");
}
void setup() {
pinMode(RECV_PIN, INPUT);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
pinMode(LED4, OUTPUT);
pinMode(LED5, OUTPUT);
pinMode(LED6, OUTPUT);
pinMode(13, OUTPUT);
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
}
int on = 0;
unsigned long last = millis();
void loop() {
if (irrecv.decode(&results)) {
// If it's been at least 1/4 second since the last
// IR received, toggle the relay
if (millis() - last > 250) {
on = !on;
// digitalWrite(8, on ? HIGH : LOW);
digitalWrite(13, on ? HIGH : LOW);
dump(&results);
}
if (results.value == on1)
digitalWrite(LED1, HIGH);
if (results.value == off1)
digitalWrite(LED1, LOW);
if (results.value == on2)
digitalWrite(LED2, HIGH);
if (results.value == off2)
digitalWrite(LED2, LOW);
if (results.value == on3)
digitalWrite(LED3, HIGH);
if (results.value == off3)
digitalWrite(LED3, LOW);
if (results.value == on4)
digitalWrite(LED4, HIGH);
if (results.value == off4)
digitalWrite(LED4, LOW);
if (results.value == on5)
digitalWrite(LED5, HIGH);
if (results.value == off5)
digitalWrite(LED5, LOW);
if (results.value == on6)
digitalWrite(LED6, HIGH);
if (results.value == off6)
digitalWrite(LED6, LOW);
last = millis();
irrecv.resume(); // Receive the next value
}
}