Pages: [1]   Go Down
Author Topic: telecommande infrarouge pour apn  (Read 1751 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 20
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

bonjour a tous, je suis en train de m'arracher les cheveux pour mettre au point une telecommande pour appareil photo numerique a base d'arduino. Je commence par emuler une telecommande wl-dc100 canon. J'ai trouve les definition des trames pour cette telecommande ici http://www.icb.chel.su/~sapa/lj/rc/pic_v4m.asm en assembleur pic et la http://lirc.sourceforge.net/remotes/canon/WL-DC100 sous une forme plus lisible. Malheureusement rien ne se passe. Voici mon code, voyez vous quelque chose qui vous choque, car ca a l'air pourtant correct. De plus, je vois bien la led ir clignoter en regardant par mon apn.

Code:
/* Exemple Emetteur WL-DC100    */
/* Jean-Christophe DURANTON 24/12/2007  */

#define LEDIR 3  // n° broche numérique de l'anode de la LED infrarouge  

int wldc_zero[]   = {612,512};
int wldc_one[]    = {612,1621};
int wldc_header[] = {9042,4379};
int wldc_ptrail[] = {599,107448};
int wldc_repeat[] = {9039,2115};
int wldc_bits     = 16;
int wldc_prebits  = 16;
int wldc_predata  = 0x538D;       // 0101001110001101
int wldc_snap     = 0xF807;        // 1111100000000111
int wldc_zoomin   = 0x42BD;     // 0100001010111101
int wldc_zoomout  = 0xC23D;    // 1100001000111101

void sendIRvalue(int value[])
{
  digitalWrite(LEDIR, HIGH);
  delayMicroseconds(value[0]);
  digitalWrite(LEDIR, LOW);
   delayMicroseconds(value[1]);
}  

void sendIRCodes(int hexval,int bytval)
{
  int cmp;
  int result[bytval];
  for(int itmp=0; itmp < bytval; itmp++)
  {
    int cmp = 1 << itmp;
    if ((hexval | cmp) == hexval)
    {
      result[bytval-1-itmp] = 1;
    }else
    {
      result[bytval-1-itmp] = 0;
    }
  }
  for(int jtmp=0; jtmp < bytval; jtmp++)
  {
    if(result[jtmp] == 1)
    {
      sendIRvalue(wldc_one);
    }else
    {
      sendIRvalue(wldc_zero);
    }  
  }  
}

void setup ()
{
  pinMode (LEDIR, OUTPUT);
}

void loop ()
{
  //header
  sendIRvalue(wldc_header);
  //predata
  sendIRCodes(wldc_predata,wldc_prebits);
  //snap
  sendIRCodes(wldc_snap,wldc_bits);
  //ptrail
  sendIRvalue(wldc_ptrail);
  delay(5000);
}

Si vous avez une petite idee, je suis preneur. Car je vois vraiment plus trop quoi teste.

Bonnes fetes.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 20
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bon j'ai compris ce qu'il ne marche pas : la modulation à 38 Khz :-(
Merci à Plasma qui m'a mit sur la voie dans ce post : http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1198744543.

J'ai trouvé des solutions sur le net pour faire cette porteuse avec un NE555 ou un TL555, mais j'aimerais bien savoir comment effectuer cette porteuse de manière logicielle.

Essayons de savoir si j'ai compris quelque chose à cette histoire de porteuse :-)
Soit une fréquence de 38 Khz, cela veut dire qu'il faut osciller toute les 1/38000s = 26µs (à la louche bien sur). Ce qui signifie qu'il faut que la led soit allumée pendant 13µs et eteinte pendant 13µs.

Si on reprend mon exemple pour la telecommande canon alors un zero doit être codé de la manière suivante :
 - 612µs en état high soit 612/13= 47 fois hight et 47 fois low
 - 512µs en état high soit 512/13= 39 fois hight et 39 fois low

J'ai tout compris ?
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 31
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonsoir,
merci pour les liens, c'est intéressant, j'ai aussi trouvé celui-ci qui devrait t'intéresser:
http://www.datelec.fr/detectir/p0.htm
selon ce qui est écrit, il faut respecter un rapport cyclique de 25%, donc si je reprend tes 26 micro-secondes, cela fait environs 6 ou 7 micro-secondes à l'état haut, le reste à zero, pour la porteuse à appliquer avec un et logique sur ton signal...
Vu la précision attendue, il faut bien sure connaître le temps d'exécution de chaque instruction afin de pouvoir ajuster les différents délais, l'idéal, étant d'avoir un oscilloscope pour vérifier tout cela...
Tiens nous au courant
Denis
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 20
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

 Excellent ce lien, je n'ai plus qu'a tester tout cela. Selon moi l'avantage de le faire en soft est de pouvoir gérer différentes porteuses.
A priori le digitalwrite prend 10µs, donc il vas falloir que je prenne cela en compte.

Au passage j'ai fait un erreur dans mon explication, à la place de
 - 612µs en état high soit 612/13= 47 fois hight et 47 fois low  
 - 512µs en état high soit 512/13= 39 fois hight et 39 fois low  
Il faut plutot faire
 - 612µs en état high soit 612/13= 47 fois hight et 47 fois low  
 - 512µs en état low
Pas besoin de faire de modulation sur l'etat low :-)

Voila ma modif :
Code:
int wlcd_freq     = 38;        // carrier freq 38khz

void sendIRvalue(int value[], int freq)
{
  int space = abs(1/freq*1000)/2;
  int nb_space = abs(value[0]/space);
  for (int i=0; i<nb_space; i++)
  {
    digitalWrite(LEDIR, HIGH);
    delayMicroseconds(13);
    digitalWrite(LEDIR, LOW);
    delayMicroseconds(13);
  }  
  digitalWrite(LEDIR, LOW);
  delayMicroseconds(value[1]);
}  
Pour rappel value[0] contient la duree en µs de l'etat hight et value[1] contient la duree en µs de l'etat low.

Et voila le code complet (non testé pour le moment) je pense qu'il doit encore y avoir un problème de timing à cause du délai d'execution de digitalWrite.
Code:
/* Exemple Emetteur WL-DC100    */
/* Jean-Christophe DURANTON 24/12/2007  */

#define LEDIR 3  // n° broche numérique de l'anode de la LED infrarouge  

int wldc_zero[]   = {612,512};
int wldc_one[]    = {612,1621};
int wldc_header[] = {9042,4379};
int wldc_ptrail[] = {599,107448};
int wldc_repeat[] = {9039,2115};
int wldc_bits     = 16;
int wldc_prebits  = 16;
int wldc_predata  = 0x538D;    // 0101001110001101
int wldc_snap     = 0xF807;    // 1111100000000111
int wldc_zoomin   = 0x42BD;    // 0100001010111101
int wldc_zoomout  = 0xC23D;    // 1100001000111101
int wlcd_freq     = 38;        // carrier freq 38khz

void sendIRvalue(int value[], int freq)
{
  int space = abs(1/freq*1000)/2;
  int nb_space = abs(value[0]/space);
  for (int i=0; i<nb_space; i++)
  {
    digitalWrite(LEDIR, HIGH);
    delayMicroseconds(13);
    digitalWrite(LEDIR, LOW);
    delayMicroseconds(13);
  }  
  digitalWrite(LEDIR, LOW);
  delayMicroseconds(value[1]);
}  

void sendIRCodes(int hexval,int bytval, int freq)
{
  int cmp;
  int result[bytval];
  for(int itmp=0; itmp < bytval; itmp++)
  {
    int cmp = 1 << itmp;
    if ((hexval | cmp) == hexval)
    {
      result[bytval-1-itmp] = 1;
    }else
    {
      result[bytval-1-itmp] = 0;
    }
  }
  for(int jtmp=0; jtmp < bytval; jtmp++)
  {
    if(result[jtmp] == 1)
    {
      sendIRvalue(wldc_one, freq);
    }else
    {
      sendIRvalue(wldc_zero, freq);
    }  
  }  
}

void setup ()
{
  pinMode (LEDIR, OUTPUT);
}

void loop ()
{
  //header
  sendIRvalue(wldc_header,wldc_freq);
  //predata
  sendIRCodes(wldc_predata,wldc_prebits,wldc_freq);
  //snap
  sendIRCodes(wldc_snap,wldc_bits,wldc_freq);
  //ptrail
  sendIRvalue(wldc_ptrail,wldc_freq);
  delay(5000);
}

A+
« Last Edit: January 03, 2008, 06:02:31 am by deldude » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 31
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour Jean-Christophe,

merci pour les mises à jour, c'est intéressant! En fouillant un peu, j'ai trouvé une discussion concernant les performances:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1198758865/6#6

c'est intéressant, mais à vérifier avec un oscilloscope... notamment sur le fait que l'instruction:
digitalWrite(PIN, HIGH);
soit plus lente que:
PORTB = 0x40;

me semble pas si évident, étant donné que les instructions sont compilées...
En tout cas il serait bon d'en être sur.
Bonne journée

Denis



Logged

FR
Offline Offline
Full Member
***
Karma: 0
Posts: 105
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour a vous 2,

En effet le digitalWrite est bcp + long que le PORTB = 0x40;

Pour se faire une première idée vous pouvez allez voir le code source (dans /lib/targets/arduino/wiring_digital.c).
Vous y verrez le code source de digitalWrite().

Si vous avez besoin d'un décompte précis du nombre d'instructions exécutées il faut désassemblé un sketch :
1) ecrire un sketch avec un digitalWrite() + le compiler
2) dans un terminal taper la commande  (avr-objdump -S /le/path/vers/ton/home/arduino/applet/TonSketchxxxx.elf)
3) tu auras dans ce fichier le digitalWrite décompilé
4) en comptant le nombre d'instructions (la plus part des instructions s'exécute en 1 seul cycle d'horloge dans la famille avr cf datasheet du atmega168) et en divisant par 16 000 000 (16Mhz) tu auras le temps en seconde.

Ca donne qq chose comme ca (instruction en 3eme colonne paramètre après) :

000003f2 <digitalWrite>:
 3f2:      48 2f             mov      r20, r24
 3f4:      55 27             eor      r21, r21
 3f6:      ca 01             movw      r24, r20
 3f8:      81 5a             subi      r24, 0xA1      ; 161
 3fa:      9f 4f             sbci      r25, 0xFF      ; 255
 3fc:      fc 01             movw      r30, r24
 3fe:      24 91             lpm      r18, Z
 400:      ca 01             movw      r24, r20
 402:      85 5b             subi      r24, 0xB5      ; 181
 404:      9f 4f             sbci      r25, 0xFF      ; 255
 406:      fc 01             movw      r30, r24
 408:      94 91             lpm      r25, Z
 40a:      49 5c             subi      r20, 0xC9      ; 201
 40c:      5f 4f             sbci      r21, 0xFF      ; 255
 40e:      fa 01             movw      r30, r20
 410:      34 91             lpm      r19, Z
 412:      33 23             and      r19, r19
 414:      11 f1             breq      .+68           ; 0x45a <digitalWrite+0x68>
 416:      22 23             and      r18, r18
 418:      81 f0             breq      .+32           ; 0x43a <digitalWrite+0x48>
 41a:      23 30             cpi      r18, 0x03      ; 3
 41c:      19 f4             brne      .+6            ; 0x424 <digitalWrite+0x32>
 41e:      8f b5             in      r24, 0x2f      ; 47
 420:      8f 77             andi      r24, 0x7F      ; 127
 422:      04 c0             rjmp      .+8            ; 0x42c <digitalWrite+0x3a>
 424:      24 30             cpi      r18, 0x04      ; 4
 426:      21 f4             brne      .+8            ; 0x430 <digitalWrite+0x3e>
 428:      8f b5             in      r24, 0x2f      ; 47
 42a:      8f 7d             andi      r24, 0xDF      ; 223
 42c:      8f bd             out      0x2f, r24      ; 47
 42e:      05 c0             rjmp      .+10           ; 0x43a <digitalWrite+0x48>
 430:      25 30             cpi      r18, 0x05      ; 5
 432:      19 f4             brne      .+6            ; 0x43a <digitalWrite+0x48>
 434:      85 b5             in      r24, 0x25      ; 37
 436:      8f 7d             andi      r24, 0xDF      ; 223
 438:      85 bd             out      0x25, r24      ; 37
 43a:      e3 2f             mov      r30, r19
 43c:      ff 27             eor      r31, r31
 43e:      e3 5d             subi      r30, 0xD3      ; 211
 440:      ff 4f             sbci      r31, 0xFF      ; 255
 442:      e4 91             lpm      r30, Z
 444:      ff 27             eor      r31, r31
 446:      66 23             and      r22, r22
 448:      29 f4             brne      .+10           ; 0x454 <digitalWrite+0x62>
 44a:      80 81             ld      r24, Z
 44c:      90 95             com      r25
 44e:      89 23             and      r24, r25
 450:      80 83             st      Z, r24
 452:      08 95             ret
 454:      80 81             ld      r24, Z
 456:      89 2b             or      r24, r25
 458:      80 83             st      Z, r24
 45a:      08 95             ret
  

Y'a + fun comme sport mais si vous avez besoin de timing précis => il faut passer par la.

Nicolas
« Last Edit: January 04, 2008, 04:26:51 pm by nrolland » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 31
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour Nicolas,

merci beaucoup smiley je vais jouer un peu avec tout cela... ma première semaine d'arduino aura été instructive! En fait j'ai plein d'autres questions, mais je vais pas polluer le sujet de Jean-Christophe.
A+

Denis

Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 31
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Juste pour enfoncer le clou (pour dire combien j'avais tord!!) et après avoir joué avec avr-objdump...
Je me suis exectué deux petites boucles, l'une avec digitalWrite(PIN, HIGH), l'autre avec PORTB = 0x40, Le résultat est édifiant:

le premier:
Code:
#define PIN 13      
void setup()
{
  pinMode(PIN, OUTPUT);
  Serial.begin(9600);
}
void loop()
{
  long x;
  x = 2000000;
  Serial.print("Ca commence!: ");
  Serial.println(millis());
  while(x>0)
  {
    digitalWrite(PIN, HIGH);
    digitalWrite(PIN, LOW);
    x--;
  }
  Serial.print("C'est fini!");
  Serial.println(millis());
}

me sort:
Ca commence!: 12
C'est fini!14705
Ca commence!: 14727
C'est fini!29423
Ca commence!: 29445
C'est fini!44141

ca fait 14693 ms entre chaque boucle

le second:
Code:
void setup()
{
  Serial.begin(9600);
}
void loop()
{
  long x;
  x = 2000000;
  Serial.print("Ca commence!: ");
  Serial.println(millis());
  while(x>0)
  {
        PORTB = 0x40; // set pin 13 to high, all other port B pins low
        PORTB = 0x00; // set pin 13 and all other port B pins low
    x--;
  }
  Serial.print("C'est fini!");
  Serial.println(millis());
}

sort:
Ca commence!: 12
C'est fini!1029
Ca commence!: 1050
C'est fini!2069
Ca commence!: 2089
C'est fini!3109

soit 1017ms

cela fait un rapport de 14,4...

En plus il y a une incertitude de 3 ou 4ms sur les temps successifs, mais cela vient logiquement de la comparaison.

Autrement dit, il faut pas longtemps pour se rendre compte qu'il n'est pas inutile d'apprendre un peu d'assembleur smiley-wink

A+

Denis
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 20
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

j'ai corrigés mes erreurs de calculs sur les int et modifié très légérement mon wait pour me rapprocher des valeurs que je trouve en lançant le frequency test dispo ici http://www.arduino.cc/en/Reference/Millis et là surprise .....
ça ne marche toujours pas  ;D

Voici le code, j'en arrive à me demander si je n'ait pas une erreur ailleur, mais je ne vais pas vous infliger l'integralite du code encore une fois:
Code:
void sendIRvalue(int value[], int freq)
{
 int space = abs(1000/freq/2) - 4;  
 //le -4 correspond à la valeur que je trouve avec le frequency test ie 9 pour 38khz
 int nb_space = abs(value[0]/space);
 for (int i=0; i<nb_space; i++)
 {
   digitalWrite(LEDIR, HIGH);
   delayMicroseconds(space);
   digitalWrite(LEDIR, LOW);
   delayMicroseconds(space);
 }  
 digitalWrite(LEDIR, LOW);
 delayMicroseconds(value[1]);
}  


Je doit plus être très loin de la solution mais là je seche completement..
« Last Edit: January 05, 2008, 12:59:52 pm by deldude » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 31
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Salut Jean-Christophe,

je viens de bricoler avec une LED infra rouge, et j'ai vu que ses caractéristiques sont assez différentes de celles des Led communes, notamment il faut une intensité bien plus importante. Celle que j'ai acheté a une tension de 1,5V et fonctionne avec une intensité de 250 mA, (au lieu de 3,2V et 20 mA pour une led blanche). En fait, en utilisant la Webcam de mon ordi, j'ai vu qu'elle ne fonctionnait pas, (donc j'ai recherché ses caractéristiques), j'ai ajouté un transistor en commutation à mon montage et ca va  beaucoup mieux...

A+

Denis
Logged

Pages: [1]   Go Up
Jump to: