Télécommande IR pour Nikon

Idéal pour les photos sur trépieds

Le concept

Les amateurs de photo sont rapidement tentés par la réalisation de prises de vue nocturnes, la réalisation de Timelapses ou la photo HDR. Toutes ces techniques requièrent l’utilisation d’un trépieds et le maintient parfait de l’appareil photo. Le simple appuie sur le déclencheur peut ruiner la pose! Pour me simplifier la vie, j’ai conçu une petite télécommande qui me permet, en plus de déclencher l’appareil, de lancer une suite de prises de vue avec un intervalle fixe mais long (plusieurs secondes voir plusieurs minutes).

Le protocole de communication

L’une des constante que l’on retrouve souvent dans les liaisons numériques infrarouge est la double modulation de l’onde lumineuse. Tout d’abord, la source lumineuse, une LED IR, émet de la lumière aux alentours de 940nm. Cette onde lumineuse est ensuite hachée à une quarantaine de kHz pour former un signal porteur carré (les récepteurs IR intégré du type TSOP 1133 démodulent directement ce signal carré). Ce signal est ensuite modulé pour transmettre l’information. Si le codage Manchester est souvent utilisé pour la modulation, Nikon ne semble pas l’utiliser. Le site SBProject présente la forme de la trame envoyée par la télécommande:

Trame IR

Ce motif vient moduler un signal carré à 38kHz avant d’être appliqué aux LED infrarouge. Le motif est répété 2 fois à 63.2ms d’intervalle. Les 2 motifs commandent une seule prise de vue.

Le fonctionnement de la télécommande

Ma télécommande vise la simplicité: un seul bouton et un double afficheur 7 segments. Avec ceci, je veux pouvoir prendre des photos à l’appuie sur le bouton, fixer une période de répétition, lancer et arrêter une séquence de prise de vue. Voici les différentes actions possibles :

  • Pas de durée de répétition fixée:
    • Appuie court: Prise de vue
    • Appuie long: Incrémentation de la durée de répétition (tant que le bouton est maintenu)
  • Une durée de répétition est fixée:
    • Appuie court: Arrêter/Démarrer la séquence
    • Appuie long: Remise à zéro de la durée de répétition

Un appuie court dure moins de 750ms. Un appuie long dure plus de 750ms et est maintenu tant que le bouton est enfoncé.

Le matériel

Pour réaliser cette télécommande, il vous faut: un micro-contrôleur (et tout ce qui l’accompagne), un afficheur, un bouton, une pile (et le circuit d’alimentation) et des LED infrarouge. Voici mes choix technologiques:

  • Un PIC18F4550 cadencé à 48MHz (un peu gros mais c’est le seul que j’avais sous la main)
  • Un double afficheur 7 segments à anodes communes
  • 3 LED infrarouge et un transistor NPN pour les commander
  • Une pile 9V et un 7805 pour fournit le 5V
  • Un bouton poussoir
  • Un boitier étanche (même s’il faut percer des trous pour les LED et les boutons…) et antichocs

Et maintenant, le schéma:

Schéma de la télécommande

On retrouve le PIC18F4550 avec ses capacités de découplage, son horloge, son circuit de Reset et son connecteur de programmation. Autours de lui, on a l’afficheur 7 segments directement alimenté par le PIC, avec les deux digits multiplexés, et le bouton poussoir relié à la broche RB0 qui présente le double avantage de générer une interruption processeur et de proposer une résistance de Pull-Up intégrée (comme tout le port B).

Le programme

Ce programme a été écrit pour l’environnement MikroC. C’est bien sûr un exemple. Chacun est libre d’adapter le fonctionnement de la télécommande à son inspiration et son envie.

#define MAIN_CLK 48000000
#define CARRIER_CLK 38000
#define DEMI_PERIODE_US     13
#define PERIODE_AFF_MS      10
 
/* Brochage afficheur 7 segments :
**     Cathodes :
**       ___
**     | RE0 |
** RE1 |     | RA1
**     | ___ |
**     | RA5 |
** RA3 |     | RA2
**     | ___ |
**       RA4
**
**      Anodes:
**       _   _
**      |_| |_|
**      |_| |_|
**      RE2 RA0
*/
 
short displayed = 12;
short toogle = 0;
short intervalle = 0;
short running = 0;
int inc = 0;
int old_pushed_button = 0;
 
void IrCycles (int nbCycles) {
     int i = 0;
     
     for (i=0; i<nbCycles; i++) {
         latd.f1 = 1;
         Delay_us(DEMI_PERIODE_US);
         latd.f1 = 0;
         Delay_us(DEMI_PERIODE_US);
     }
}
 
void WaitCycles (int nbCycles) {
     int i = 0;
     
     latd.f1 = 0;
 
     for (i=0; i<nbCycles; i++) {
         Delay_us(DEMI_PERIODE_US);
         Delay_us(DEMI_PERIODE_US);
     }
}
 
void TakePhoto (void) {
     latd.f2 = 1;
     IrCycles(76);
     WaitCycles(1064);
     IrCycles(15);
     WaitCycles(60);
     IrCycles(15);
     WaitCycles(136);
     IrCycles(15);
     Delay_us(63200);
     IrCycles(76);
     WaitCycles(1064);
     IrCycles(15);
     WaitCycles(60);
     IrCycles(15);
     WaitCycles(136);
     IrCycles(15);
     latd.f2 = 0;
}
 
void DisplayNumber (char number) {
     number = number%16;
     
     switch (number) {
      case 0:
           lata.f1 = 0;
           lata.f2 = 0;
           lata.f3 = 0;
           lata.f4 = 0;
           lata.f5 = 1;
           late.f0 = 0;
           late.f1 = 0;
           break;
      case 1:
           lata.f1 = 0;
           lata.f2 = 0;
           lata.f3 = 1;
           lata.f4 = 1;
           lata.f5 = 1;
           late.f0 = 1;
           late.f1 = 1;
           break;
      case 2:
           lata.f1 = 0;
           lata.f2 = 1;
           lata.f3 = 0;
           lata.f4 = 0;
           lata.f5 = 0;
           late.f0 = 0;
           late.f1 = 1;
           break;
      case 3:
           lata.f1 = 0;
           lata.f2 = 0;
           lata.f3 = 1;
           lata.f4 = 0;
           lata.f5 = 0;
           late.f0 = 0;
           late.f1 = 1;
           break;
      case 4:
           lata.f1 = 0;
           lata.f2 = 0;
           lata.f3 = 1;
           lata.f4 = 1;
           lata.f5 = 0;
           late.f0 = 1;
           late.f1 = 0;
           break;
      case 5:
           lata.f1 = 1;
           lata.f2 = 0;
           lata.f3 = 1;
           lata.f4 = 0;
           lata.f5 = 0;
           late.f0 = 0;
           late.f1 = 0;
           break;
      case 6:
           lata.f1 = 1;
           lata.f2 = 0;
           lata.f3 = 0;
           lata.f4 = 0;
           lata.f5 = 0;
           late.f0 = 0;
           late.f1 = 0;
           break;
      case 7:
           lata.f1 = 0;
           lata.f2 = 0;
           lata.f3 = 1;
           lata.f4 = 1;
           lata.f5 = 1;
           late.f0 = 0;
           late.f1 = 1;
           break;
      case 8:
           lata.f1 = 0;
           lata.f2 = 0;
           lata.f3 = 0;
           lata.f4 = 0;
           lata.f5 = 0;
           late.f0 = 0;
           late.f1 = 0;
           break;
      case 9:
           lata.f1 = 0;
           lata.f2 = 0;
           lata.f3 = 1;
           lata.f4 = 0;
           lata.f5 = 0;
           late.f0 = 0;
           late.f1 = 0;
           break;
      case 0xa:
           lata.f1 = 0;
           lata.f2 = 0;
           lata.f3 = 0;
           lata.f4 = 1;
           lata.f5 = 0;
           late.f0 = 0;
           late.f1 = 0;
           break;
      case 0xb:
           lata.f1 = 1;
           lata.f2 = 0;
           lata.f3 = 0;
           lata.f4 = 0;
           lata.f5 = 0;
           late.f0 = 1;
           late.f1 = 0;
           break;
      case 0xc:
           lata.f1 = 1;
           lata.f2 = 1;
           lata.f3 = 0;
           lata.f4 = 0;
           lata.f5 = 1;
           late.f0 = 0;
           late.f1 = 0;
           break;
      case 0xd:
           lata.f1 = 0;
           lata.f2 = 0;
           lata.f3 = 0;
           lata.f4 = 0;
           lata.f5 = 0;
           late.f0 = 1;
           late.f1 = 1;
           break;
      case 0xe:
           lata.f1 = 1;
           lata.f2 = 1;
           lata.f3 = 0;
           lata.f4 = 0;
           lata.f5 = 0;
           late.f0 = 0;
           late.f1 = 0;
           break;
      case 0xf:
           lata.f1 = 1;
           lata.f2 = 1;
           lata.f3 = 0;
           lata.f4 = 1;
           lata.f5 = 0;
           late.f0 = 0;
           late.f1 = 0;
           break;
     }
}
 
void interrupt (void) {
     if (INT0IF_bit) {
        if (!PORTB.f0) {
           if (intervalle != 0) inc = 0;
           else inc = 1;
        }
        
        INT0IF_bit = 0;
     }
 
     if (TMR0IF_bit) {
        if (displayed >=0) {
           if (toogle) {
              late.f2 = 1;   //dizaine
              lata.f0 = 0;   //unite
              DisplayNumber((displayed/10)%10);
           }
           else {
              late.f2 = 0;   //dizaine
              lata.f0 = 1;   //unite
              DisplayNumber((displayed)%10);
           }
        }
        else {
             late.f2 = 0;   //dizaine
             lata.f0 = 0;   //unite
        }
        toogle = !toogle;
        TMR0IF_bit = 0;
     }
}
 
void main() {
     int i = 0;
     int j = 0;
     int cligno = 0;
 
     trisd.f2 = 0;
     trisd.f1 = 0;
     trisa = 0;
     trise = 0;
     RBPU_bit = 0;
     latd.f2 = 0;
     INTEDG0_bit = 0; //falling edge
     INT0IE_bit = 1;
     TMR0IE_bit = 1;
     GIE_bit = 1;
     PEIE_bit = 1;
     T08BIT_bit = 0;
     T0CS_bit = 0;
     PSA_bit = 1;
     TMR0H = 0;
     TMR0L = 0;
     TMR0ON_bit = 1;
     
     intervalle = 0;
     
     i = -0;
     j = 0;
     inc = 0;
     cligno = 0;
     old_pushed_button = 0;
 
     while (1) {
         if (!running) {
           if (intervalle > 0) displayed = intervalle;
           else displayed = -1;
         }
         
         if (!portb.f0) {
            j = 0;
            if (inc == 1) {
              if ((intervalle < 10) && (i%50 == 0) && (i>0)) intervalle++;
              else if ((intervalle >= 10) && (intervalle < 99) && (i%25 == 0) && (i>0)) intervalle++;
            }
            else if ((i%50 == 0) && (i>0)) intervalle = 0;
            i++;
         }
         else {
           if ((i<50)&&(i>0)&& (old_pushed_button)) {
              if (intervalle == 0) TakePhoto();
              else running = !running;
           }
           i = -0;
           
           if (running) {
               if ((j/100<intervalle)) {
                   if (j%50 == 0) cligno = !cligno;
                   if (cligno) displayed = intervalle - j/100;
                   else displayed = -1;
                   j++;
               }
               else {
                  j = 0;
                  TakePhoto();
               }
           }
         }
         old_pushed_button = !portb.f0;
         Delay_ms(10);
     }
 
}

Quelques photos

  • La télécommande dans son boitier avec son alimentation par pile 9V

A vos reflex !

Laisser un commentaire