Eine besonders günstige IR-Fernbedienung für Nikon Spiegelreflexkameras

Figure 8
Die IR-Fernbedienung

Während eines Moments der Langeweile habe ich mich dazu entschieden, eine Infrarot-Fernbedienung für meine Nikon Digitalkamera zu bauen. Dabei stellte sich heraus, dass es sich dabei um ein extrem einfaches Projekt handelt, perfekt, wenn man einen Tag lang nichts zu tun hat. Die Fernbedienung hat eine Reichweite von mindestens 15 - 20 Meter, mehr konnte ich bislang nicht testen.

Die Fernbedienung besteht hauptsächlich aus einem Mikrocontroller, der per Knopfdruck mit Strom versorgt wird. Daraufhin wird eine Infrarot-LED mit einer Frequenz von ca. 38kHz angesteuert, die ein bestimmtes Leuchtmuster an die Kamera sendet. Die Fernbedienung ist funktionsgleich zu Nikon's ML-L3 und funktioniert somit mit einer vielzahl von Nikon Kameras.

Hardware

Für die Fernbedienung wird nur eine geringe Anzahl an Bauteilen benötigt. Wer öfter mit Elektronischen Schaltungen bastelt, wird vermutlich alle Bauteile lagernd haben. Nachfolgend eine genaue Auflistung:

  • Plastikgehäuse für die Schaltung (am besten, wenn es ein Fernbedienungsgehäuse wie im obigen Foto ist)
  • Ein Stück Loch- oder Streifenrasterplatine
  • 1x Atmel ATTiny13 Mikrocontroller
  • 1x 8 MHz Quarzoszillator
  • 1x 3V Knopfzelle (z.B. CR2032, vorzugsweise mit Lötfahnen)
  • 1x Taster
  • 1x Infrarot-LED
  • 1x ca. 1 bis 2 Ohm Widerstand
  • 1x 100 Ohm Widerstand
  • 1x 10 kOhm Widerstand
  • 1x BC547 NPN Transistor (oder äquivalentes Modell)
  • 2x 100 nF Kondensator

Theoretisch sollte die Fernbedienung auch mit dem internen Oszillator funktionieren. In der Praxis erwies sich der Einsatz eines externen Quarzoszillators allerdings deutlich zuverlässiger. Hier der Schaltplan der Fernbedienung:

Figure 12
Schaltplan

Ich werde hier kein Platinenlayout zur Verfügung stellen, da das Layout stark von der Wahl der Bauteile und des Gehäuses abhängt. Außerdem habe ich nicht erwähnt, ob ich DIP oder SMD Bauteile verwendet habe - suchen Sie sich einfach die Form aus, die Ihnen am besten passt! Ich persönlich habe eine Mischung aus beidem verwendet, da ich nur Bauteile verwenden wollte, die ich bereits lagernd hatte. Nachfolgend eine Innenansicht meiner Fernbedienung:

Figure 10
Ja, das ist ein SSOP Controller, wo eigentlich ein DIP Controller sein sollte - ich hatte keine mehr übrig und der letzte ist durch einen kleinen Fehler gestorben ;-)

Software

Bevor ich den eigentlichen Quellcode vorstelle, möchte ich ein paar Worte über das Protokoll verlieren, welches die Fernbedienung einsetzt. Das Infrarot-Signal wird mit einer Frequenz von etwa 38,4 Kilohertz moduliert. Das bedeutet, wenn die LED "an" ist, leuchtet sie nicht durchgehend, sondern blinkt 38400 mal in der Sekunde. Weiterhin muss die LED zwei mal in einem ganz bestimmten Muster leuchten (mit einer Pause von 63ms), damit sie von der Kamera erkannt wird. Im Quellcode nenne ich dieses Muster "burst". Glücklicherweise haben sich bereits einige Leute mit dieser Thematik befasst und das Signal der Original-Fernbedienung genaustens analysiert. Ich habe die Daten von BigMike's Webseite genommen.

Der Quellcode für den Mikrocontroller ist relativ simpel. Da der Schalter einfach die Stromversorgung aktiviert und nicht etwa als digitaler Eingang agiert, ist das einzige, was der Controller tun muss, direkt nach dem Start das richtige Muster auszugeben. Diese Tatsache spiegelt sich in der extrem kurzen Hauptmethode wieder:

int main(void) {
  // Initialize port
  DDRB |= (1 << IO_IR);
 
  burst();
  _delay_ms(63);
  burst();
   
  while(1) {}
}
Das war einfach, nicht wahr? Viel interessanter ist die burst Methode:

// Clock-counts at which the LED state has to be toggled
// The values are determined by experimenting, they work
// with a 8MHz crystal oscillator
const uint16_t thresholds[8] = {2,164, 2564, 2597, 2727, 2760, 3054, 3087};
 
// Sends a single data burst (two of them are needed)
void burst() {
  uint16_t clock = 0;
  uint8_t current_threshold = 0;
  uint8_t status = 0;
     
  while(clock++ < BURST_LENGTH) {
    if (clock == thresholds[current_threshold]) {
      status ^= 1;
      current_threshold++;
    }
     
    if (clock & status) {
      LED_ON();
    } else {
      LED_OFF();
    }      
         
    _delay_us(CLOCK_DURATION);
  }
     
  LED_OFF();
  return;
}

Nun, was passiert hier? Ein Durchlauf der while-Schleife benötigt ungefähr 13 Mikrosekunden, wodurch die Modulationsfrequenz von 38.4 kHz erreicht wird. Während jeder Iteration wird ein Zähler inkrementiert. Dieser Zähler entspricht der Anzahl der bisher erfolgten Takte. Pro Durchlauf wird er mit einem Array von Schwellwerten verglichen. Wird ein Schwellwert erreicht, schaltet der LED Zustand von "an" auf "aus" oder umgekehrt (wobei "an" wie vorhin erwähnt Blinken mit 38.4 kHz bedeutet).

Damit die LED also wirklich leuchtet, müssen zwei Bedingungen gelten:

  1. Der aktuelle Takt ist ungerade (dadurch wird das Blinken mit Modulationsfrequenz erreicht)
  2. Der Zustand der LED ist "an"

Auch wenn die status Variable ein 8-bit Integer ist, verwende ich nur das niederwertigste Bit zur Indikation des Zustandes. Der Zähler wird bei jedem Schleifendurchlauf inkrementiert, das heißt, dass das niederwerigste Bit des Zählers bei jedem Durchlauf zwischen Null und Eins springt. Nun kann man einfach die beiden Variablen UND-verknüpfen - wenn das Ergebnis der Verknüpfung eine Eins ist, heißt es, dass beide Bedingungen erfüllt sind und die LED leuchten kann.

Mit dieser Methode haben wir alles, was wir für eine funktionierende Fernbedienung benötigen. Ich hoffe, dieser Artikel bietet ausreichend Informationen für einen erfolgreichen Nachbau. Bei Fragen, senden Sie mir einfach eine E-Mail!