Problèmes signaux IR

Bonjour, bonsoir vous tous !

Depuis longtemps intéressé par l'informatique mais depuis peu par l'électronique par le biais d'un amis, j'ai décidé de me créer une box domotique controlé par Application Android. La box domotique a été soudé par mon amis avec les éléments de base : (de souvenir) Atmega328, récepteur/émetteur RF et IR, led RGB, module ethernet, ... Je la commande par requêtes Http et je n'ai aucun soucis pour cela. Mais c'est aux niveau des signaux IR envoyé. La télécommande de ma télé de chez Ikea ( télé TCL ) envoie des signaux inconnue mais lus comme signaux Raw. J'arrive tout à fait à les récupérer et à les renvoyer pour ma box. Donc au début, j'avais programmer les signaux de base (Allumé/éteindre, monter chaine, descendre chaine ) Mais pour aller plus loin, j'ai décide de récupérer tous les numéros pour aller directement sur la chaine. Malheureusement, et pour une raison, je ne peux rajouter aucune nouvelle requêtes qui renvoie un signal Raw car ils font planter ma box ( en gros, elle envoie des signaux toutes seules en continus ). Alors je voulais savoir d'ou cela pouvait venir, si il y avait un nombre max de signaux Raw ( je ne peux en avoir que 5 opérationnelle en même temps ) et comment je pouvais régler mon problème...

Je sais que mon problème parait compliquer à comprendre mais je pourrais être plus précis et répondre à vos questions, merci d'avance.

Bonjour,

Difficile de pouvoir t'aider face à un problème qui semble bien particulier. Ton problème renvoit à priori à une faiblesse dans le programme arduino.

De quelle manière procèdes-tu pour ajouter de nouvelles entrées Ir dans ta box ?

  • Tu agis directement sur le programme ?
  • Une interaction a été prévu avec la box domotique ?

Comment sont enregistrés les signaux raw ?

  • Dans une Eeprom liée à l'Atmega328 ?
  • Dans la mémoire vive de l'Atmega328 ?

Dans le contexte actuelle et avec si peu d'informations (manque le code, le schéma de cablâge, etc), je m'evertuerais à tester et récuperer les codes de la télécommande avec un petit montage vite fait à côté (arduino + récepteur Ir), dont tu trouveras pléthore d'exemples sur internet.
Une fois toutes les fonctions de la télécommande récupérées, elles seront plus faciles à intégrer dans le programme si celui-ci demande à être modifié.

@+

Zoroastre.

Pour une meilleur compréhension de mon problème, voici mon programme Arduino :

// variable pour l'ethernet
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
static byte myip[] = { 192,168,1,36 };
byte Ethernet::buffer[500];
BufferFiller bfill;

RCSwitch mySwitch = RCSwitch(); //Création d'un objet pour l'éméteur RF
IRsend irsend;

#define RAWBUF 100

unsigned int tvOnOff[51] = {3900,3950,500,2000,400,2050,450,2000,400,2050,400,1050,450,1000,450,2000,450,1000,500,1950,500,1000,450,2000,450,1000,450,1000,500,1000,450,1000,450,1000,500,1950,500,1950,500,1000,450,2000,450,1000,450,2000,450,1000,500,1950,500};
unsigned int tvchp[51] = {3950,3950,500,1950,500,1950,500,1950,500,1950,500,1000,450,1000,500,1950,500,950,450,2000,450,2000,450,1000,500,1950,500,1000,400,1050,450,1000,450,1000,450,2050,450,2000,450,1000,500,1950,450,1000,450,1000,500,1950,500,1000,450};
unsigned int tvchm[51] = {3900,4000,500,1950,450,2000,500,1950,500,1950,450,1000,500,950,500,2000,450,1000,450,2000,450,2000,450,1000,500,1000,500,950,450,1000,500,950,500,1000,450,2000,500,1950,450,1000,500,1950,450,1000,450,1050,400,2050,450,2000,450};
unsigned int tvmute[51] = {3900,4000,400,2050,450,2000,400,2050,450,2000,450,1000,500,1000,400,2000,400,2050,500,1950,450,2000,500,1950,500,1950,500,1000,450,1000,450,1000,450,1050,450,2000,450,2000,450,1000,500,950,450,1000,550,950,450,1000,500,1000,400};
unsigned int tvsource[51] = {3900,4000,450,2000,500,1950,500,1950,500,1950,500,1950,450,1000,450,2000,450,1000,500,950,500,1000,500,1950,450,2000,500,950,450,1000,500,950,500,1000,450,1000,450,2000,500,950,500,1950,500,1950,500,1950,500,1000,450,1000,450};
unsigned int tvok[51] = {3900,4000,500,1950,450,2000,450,2000,450,2000,450,2000,450,2000,450,2000,450,2000,450,1050,400,2050,400,1050,450,1000,450,1050,400,1050,450,1000,450,1050,400,1050,450,1000,450,1000,450,1050,400,2050,400,1050,450,2000,450,2000,450};
unsigned int tv1[51] = {3950,3950,500,1950,500,1950,500,1950,500,1950,500,1000,450,1000,450,2000,450,2000,500,950,450,1000,500,1000,450,2000,450,1000,500,950,450,1000,500,1000,450,2000,450,2000,450,1000,450,1000,500,1950,500,1950,500,1950,500,1000,450};
unsigned int tv2[51] = {3900,4000,450,2000,500,1950,500,1950,500,1950,450,1000,500,1000,450,2000,450,2000,400,1050,450,1000,450,2000,450,1050,400,1050,450,1000,450,1000,450,1050,450,2000,450,2000,450,1000,450,1000,450,2000,450,2050,400,1050,450,2000,400};
unsigned int tv3[51] = {3900,4000,500,1950,500,1950,500,1950,500,1950,500,950,500,1000,500,1950,500,1950,500,950,450,1000,500,1950,500,1950,550,900,500,1000,500,950,450,1000,500,1950,450,2000,500,1000,500,950,450,2000,450,2000,550,900,500,1000,500};

int RVB_R = 10;
int RVB_G = 9;
int RVB_B = 6;
int temps = 0;


void setup () {  
  pinMode(RVB_R, OUTPUT);
  pinMode(RVB_G, OUTPUT);
  pinMode(RVB_B, OUTPUT);
  Serial.begin(9600);
  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) //verification du module ethernet
    Serial.println( "Failed to access Ethernet controller");
  ether.staticSetup(myip); 
  
  mySwitch.enableTransmit(5);
  mySwitch.setRepeatTransmit(5);
  RGB(0,255,0);
  temps=millis();
}

static word homePage() {
  bfill = ether.tcpOffset();
  bfill.emit_p(PSTR(
    "HTTP/1.0 200 OK\r\n"
    "Content-Type: text/html\r\n"
    "\r\n"
    "<title>Domoduino</title>"));
  return bfill.position();
}

void loop () {
  word len = ether.packetReceive();
  word pos = ether.packetLoop(len);
  if(strstr((char *)Ethernet::buffer + pos, "GET /?priseOn") != 0) { // PRISE RF ON
      signal();
      mySwitch.send(983232, 24);
    }
  if(strstr((char *)Ethernet::buffer + pos, "GET /?priseOff") != 0) { // PRISE RF OFF
      signal();
      mySwitch.send(983040, 24);
    }
  if(strstr((char *)Ethernet::buffer + pos, "GET /?vol-") != 0) { //AMPLI +
      signal();
      irsend.sendNEC(0xa55ad02f, 32);
    }
  if(strstr((char *)Ethernet::buffer + pos, "GET /?vol+") != 0) { //AMPLI -
      signal();
      irsend.sendNEC(0xa55a50af, 32);
    }
  if(strstr((char *)Ethernet::buffer + pos, "GET /?volmute") != 0) { //AMPLI MUTE
      signal();
      irsend.sendNEC(0xa55a48b7, 32);
    }
  if(strstr((char *)Ethernet::buffer + pos, "GET /?tvon") != 0) { //TV-ON/OFF
      signal();
      irsend.sendRaw(tvOnOff,51,38);
    }
  if(strstr((char *)Ethernet::buffer + pos, "GET /?tvmute") != 0) { // TV MUTE
      signal();
      irsend.sendRaw(tvmute, 51, 38);
    }
  if(strstr((char *)Ethernet::buffer + pos, "GET /?tvsource") != 0) { // TV SOURCE
      signal();
      irsend.sendRaw(tvsource, 51, 38);
    }
  if(strstr((char *)Ethernet::buffer + pos, "GET /?ch+") != 0) { // TV CH+
      signal();
      irsend.sendRaw(tvchp, 51, 38);
    }
  if(strstr((char *)Ethernet::buffer + pos, "GET /?ch-") != 0) { // TV CH-
      signal();
      irsend.sendRaw(tvchm, 51, 38);
    }
  /*if(strstr((char *)Ethernet::buffer + pos, "GET /?tv1") != 0) { // TV 1
      RGB(255,0,255);
      irsend.sendRaw(tv1, 51, 32);
    }
  /*if(strstr((char *)Ethernet::buffer + pos, "GET /?tv2") != 0) { // TV 2
      signal();
      irsend.sendRaw(tv2, 51, 38);
    }
  if(strstr((char *)Ethernet::buffer + pos, "GET /?tv3") != 0) { // TV 3
      signal();
      irsend.sendRaw(tv3, 51, 38);
    }*/
   if (pos){
    envoiePage();}
  if (millis()-temps > 500){
    RGB(0,0,0);
  }
}

void RGB(int rouge, int vert, int bleu){
  analogWrite(RVB_R, rouge);
  analogWrite(RVB_G, vert);
  analogWrite(RVB_B, bleu);
}
void signal(){
  RGB(0,0,255);
  temps = millis(); 
  
}
void envoi(unsigned int*a){
 irsend.sendRaw(a, 51, 38); 
}
void envoiePage(){
    ether.httpServerReply(homePage()); // send web page data 
}

Pour ajouter de nouveaux signaux IR, j'agis directement sur le programme que je télévise après.
Et pour l'enregistrement les signaux Raw, ils sont aussi dans le programme Arduino.

Bonsoir,

Sans être certain de mon coup, tu devrais vérifier l'utilisation de la Ram de l'arduino. Il existe une bibliothèque et une fonction pour afficher la mémoire restante.

http://playground.arduino.cc/Code/AvailableMemory

Un unsigned int occupe 2 octets, soit dans ton programme (juste pour la partie télécommande) 9 tableaux de 51 x 2 octets = 918 octets au total, soit quasiment la moitié de la capacité de l'arduino.

(La partie internet consomme pas mal aussi...)

De toute manière, je te conseille d'optimiser l'utilisation de la mémoire et d'utiliser PROGMEM pour placer des données volumineuses et statiques en mémoire flash (1Kb pour un ATmega328) ou d'utiliser l'EEPROM de l'arduino (1Kb pour un ATmega328) ou une externe.

@+

Zoroastre.

Je vais voir ça, mais le soucis, c'est que même en décomptant tous les unsigned int, j'ai toujours le même problème donc je vais voir tout ça... Merci en tout cas !
Si quelqu'un a une autre idée en passant, je suis preneur ! :slight_smile:

EDIT : J'ai essayé de retirer quelques un des signaux que j'avais ajouter et comme vous l'avez dit, cela viens de la mémoire ! Je vous remercie beaucoup de m'avoir aidé et de m'avoir lancé dans cet idée de mémoire et de m'avoir proposer PROGMEM.

Salut, il y a moyen d'alléger largement tes tableaux ...

Pour commencer, chaque code IR commence par 4000, 4000, 500 (3950 ou 4000 c'est pareil pour les signaux IR)
Ensuite tu as toujours un couple de 1000 ou 2000 suivit d'un 500 ... C'est dans le 1000 et 2000 que se trouve le codage réellement ...

tu définis que 0 c'est 1000 et 1 c'est 2000, tu ne mets pas les 500 dans les tableaux ... Et tes tableaux deviennent des tableaux de byte du genre (1,0,0,1,0...) pour 500,2000,500,1000,500,1000,500,2000,500,1000,... Déjà tu vas diviser par 4 la mémoire utlisee par les tableaux (2X plus courts et byte au lieu de int)

Je suis sur tablette alors c pas facile d'écrire de lignes de code ...

Fonction émission

//Partie commune à toutes les trames
Envoi High, attend 4000 us (micro secondes)
Envoi Low, attend 4000 us
Envoi high, attend 500 us

//Ensuite le lit te bon tableau (qui ne contiennent que des 0 ou 1)
Pour i=0 jusqu'à nn
Écrit low
Si tableau == 0 attend 1000us sinon attend 2000us

  • Écrit high, attend 500 us*
    //pour finir la trame
    Écrit low
    J'utilise ce genre de méthode pour piloter les clims (IR) et mes prises télécommandées (433MHZ) et ça marche très bien sans utliser la bibliothèque IR
    Je pourrait t'en dire plus demain... Et aussi comment diviser par 8 la taille de tes tableaux qui ont été déjà divisés par 4 ...

Salut à toi.

Merci à vous 2 pour votre aide déjà ! Alors PROGMEM ne fonctionne pas dans mon cas, malheureusement ... Donc je vais plus me pencher sur l'idée de B83s qui a l'air de fonctionner ! Je t'attends pour avoir plus d'information car je t'avoue ne pas avoir tout compris et donc je voudrais plus de précision. Merci d'avance.

Oups, pas le temps de répondre aujourd'hui ... Demain je m'y mets !

Ps: comme émetteur IR tu utilises une simple diode ? (je dis ça pour savoir si c'est ton microcontroleur qui génère le 38kHz ... Ou si tu as un circuit externe qui s'en charge)
Sur quelle sortie est ton émetteur IR ... ?

Pas de soucis ! j'étais occupé aujourd'hui de toute façon :wink:

J'utilise une simple diode. elle est branché sur le port 3 de l'atmega.

Ok, as-tu un oscillo ou une autre carte arduino pour t'en servir comme oscilloscope ?

Je m'explique ... Pour générer la fréquence de 38kHz il y a deux moyens ...
Le bourrin : c'est de faire des on/off avec un délai qui va bien ( mais il faut vérifier la sortie sur un oscillo pour ajuster la fréquence)
Le futé : utiliser les timers, prescaler et compagnie mais pour moi c'est un peu du chinois ... Mais il y a moyen de trouver les bonnes commandes sur le forum ... Voire meme juste extraire les parties de la librairie qui vont bien

bon voilà mon code ...

comme tu utilises la librairie IRsend pour ton ampli, j'ai utilisé ses fonctions pour générer les signaux à 38KHz. J'ai vérifié sur un oscillo la qualité des signaux aussi...

J'ai commenté le code pour t'aider à comprendre ...

Tu dois encore :

  • coder les 8 dernières touches (j'ai fais la première comme exemple)
  • intégrer ce bout de programme dans le tiens ...
//unsigned int tvOnOff[51] =    {3900,3950,500,2000,400,2050,450,2000,400,2050,400,1050,450,1000,450,2000,450,1000,500,1950,500,1000,450,2000,450,1000,450,1000,500,1000,450,1000,450,1000,500,1950,500,1950,500,1000,450,2000,450,1000,450,2000,450,1000,500,1950,500};
// etat diode (H pour High)       H  , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  , H , L  
// codage (0 = 1000, 1 = 2000)  (commun à tous),1  ,     1  ,     1  ,     1  ,     0  ,     0  ,     1  ,     0  ,     1  ,     0  ,     1  ,     0  ,     0  ,     0  ,     0  ,     0  ,     1  ,     1  ,     0  ,     1  ,     0  ,     1  ,     0  ,     1
// les valeurs 450 (400 ou 500) sont fixes ... elles sont émises entre les signaux utiles, il n'est pas utile de les coder
// si on regroupe les 24 bits utiles (hors partie commune), il reste :  1,1,1,1,0,0,1,0,1,0,1,0,0,0,0,0,1,1,0,1,0,1,0,1
// que l'on peut écrire dans un long (4 bytes soit 32 bits) 
// le tableau de 51 int (102 bytes) se résume à 4 bytes ... pas mal non ?

#include <IRremote.h>

IRsend irsend;

// tu définis des noms clairs pour chaque touche
#define ONOFF 0
#define CHP 1
//... ainsi de suite pour les autres codes

//tableau qui va contenir les 9 codes
long tvcode[9]; 


void setup() {
 
  tvcode[ONOFF] = 15900885; //équivalent de 111100101010000011010101 (coller le binaire dans la calculatrice scientifique en mode binaire pour avoir la valeur décimale);
  //... ainsi de suite pour les autres codes
}

//fonction qui remplace ta télécommande, "touche" est le n° de la touche que tu simules (0 à 8)
void telecommande(byte touche) {
  //initialisation de la pin d'émission à 38 kHz
  irsend.enableIROut(38);
  
  //partie commune de l'émission
  irsend.mark(4000); 
  irsend.space(4000); 
  irsend.mark(450); 
  
  //partie propre à chaque touche 
  //il faut lire le code de gauche à droite, donc du bit 23 au bit 0 (24 bits en tout)
  for (byte i = 23; ; i--) {
    //on commence par une pause de 1000 ou 2000 ms
    if (bitRead(tvcode[touche],i) == 0) irsend.space(1000);  
    else irsend.space(2000); 
    
    //on envoie un pulse (toujours de 450 us)
    irsend.mark(450); 
    
    // quand on a lu le bit 0 (i=0) on sort
    if (i == 0) break;
  }
  irsend.space(0); //pour être sur d'éteindre la ledIR
}

Dragafe:
... car je t'avoue ne pas avoir tout compris et donc je voudrais plus de précision. Merci d'avance.

J'ai rien compris à la solution de B83s non plus...Comment se fait-il que des valeurs de 3900; 2000, 1050 se résume à des 0/1 ???

Pourquoi faire compliqué quand on peut faire simple ? Une explication s'impose...

@+

Zoroastre.

Zoro ... La solution simple fonctionne très bien ... Jusqu'à ce que ... Ca ne marche plus !

Si tu relis les messages plus haut tu verras que l'auteur atteint la limite de la mémoire de son micro ... Je lui propose une solution pour gagner de la place en mémoire ...si tu n'as pas de souci de mémoire ... Tu n'es pas concerné

Les signaux IR (et 433 ou 866MHz) sont des salves de flash émis plus ou moins longs entrecoupés de pauses plus ou moins longues ...

Les librairie IR remote renvoie les codes qu'elle ne connait pas en mode raw : c'est le timing des flash et des pauses ... Leur durée est dans le tableau en microsecondes. Exemple {4000,4000,450,2000,450...} c'est
J'allume pendant 4000 us (allumage a 38kHz)
J'eteinds pendant 4000us
J'allume pendant 450 us
J'eteinds pendant 2000us
J'allume pendant 450us
...

Si tu compares les différents codes que l'auteur a mis .. Ils commencent tous par {4000,4000,450} (comme je l'ai dit avant, 3950 4000 ou 4500 c'est la même chose pour le récepteur IR) : ce n'est pas la peine de les coder dans les tableaux...
Ensuite tu as une serie de {x,450,x,450...} avec x= 1000 ou 2000us (temps ou la diode est éteinte) et 450 c'est le temps ou la diode est allumée (a 38KHz si tu suis...) ... Donc on éteint pendant x us et on allume pdt 450 us ... Quand on est riche on peut se permettre de bourrer son tableau de 450 ... Quand on a des économies de mémoire a faire ... On trouve une autre solution !

Je propose cette solution (elle n'est pas universelle et si tu as mieux en performance de mémoire je suis preneur de ta solution!) qui permet de réduire un tableau de 51 int (102 octets) a seulement 1 long (4 octets) ... Je suis assez content de moi... :stuck_out_tongue:

Et pour finir ... Tu peux écrire ce que tu veux dans ton code, pour ton microcontroleur il ne se résumera qu'a des 0 et des 1...

Et c'est pas fini ! J'utilise une méthode analogue chez moi pour commander mes clims ... Un ordre de clim (suivant le modèle) c'est 130 flashs entrecoupés de 130 pause ... Donc un tableau de 260 valeurs à remplir ... Rien que d'y penser ça me fout des boutons...

Yep!

Merci pour ton explication, j'avais bien suivi la discussion et j'ai déjà fais joujou avec des télécommandes, émetteur/récepteur Ir.

Le truc est que je ne capte pas ce que deviennent dans ta proposition les timing (uS) d'activation/désactivation de la led émettrice. Ne sont-ils pas important pour le fonctionnement du signal ?

@+

Zoroastre.

Si bien sur qu'ils sont importants (on n'est pas a la microsecondes non plus ...)

Tout est dans la fonction que j'ai proposée ... On envoie d'abord les flashs de synchro qui sont communs à tous les ordres (4000,4000,450) (c'est écrit en clair car il n'y a pas grand chose à optimiser )
Ensuit la boucle lit la valeur du code (mais en binaire et de gauche à droite) et le transforme en serie d'impulsions (si le code est 0: pause de 1000, sinon pause de 2000, puis un flash de 450)

La ou j'ai appris un truc c'est qu'on peut générer de 38kHz sur une broche avec le pwm... Et que la librairie IRremote a les fonctions qui permettent d'activer la led a 38kHZ c'est la fonction Irsend.Mark(durée)

Merci beaucoup a toi pour ta merveilleuse solution !! Par contre j'ai un petit dernier problème ... j'ai très bien compris ton système, sauf la partie ou je dois recréer mes propres valeurs binaires ... Je comprends pas la partie commune etc...

La partie commune c'est le 4000,4000,500 qui sont en tête de chacun des codes ... Il n'est pas nécessaire de la reproduire en binaire (c'est toujours émis quand tu appelles la fonction telecommande()

Par contre après ces trois premières valeurs, c'est le code de la touche qui commence (x,450,y,450,z,450, ...)
Pour chaque code il faut remplacer les x y z par des 0 si x=1000 ou 1 si x=2000
Tu auras alors 24 1 ou 0 ... Que tu mets dans la calculatrice en binaire et que tu convertis en décimal ... C'est cette dernière valeur qu'il faut mettre dans ton programme

B83s:
Si bien sur qu'ils sont importants (on n'est pas a la microsecondes non plus ...)

Tout est dans la fonction que j'ai proposée ... On envoie d'abord les flashs de synchro qui sont communs à tous les ordres (4000,4000,450) (c'est écrit en clair car il n'y a pas grand chose à optimiser )
Ensuit la boucle lit la valeur du code (mais en binaire et de gauche à droite) et le transforme en serie d'impulsions (si le code est 0: pause de 1000, sinon pause de 2000, puis un flash de 450)

La ou j'ai appris un truc c'est qu'on peut générer de 38kHz sur une broche avec le pwm... Et que la librairie IRremote a les fonctions qui permettent d'activer la led a 38kHZ c'est la fonction Irsend.Mark(durée)

Merci B83s !

Là où j'ai été trompé est que justement je m'attendais à retrouver des pulses parfaitement identiques à la uS près au code au format raw. Au pis aller je pense que le timing peut être ajusté si le récepteur est un peu récalcitrant...

En tout cas, c'est une belle optimisation ! J'essaierai !!

@+

Zoroastre.

je viens de finir de traduire tous mes signaux Raw et je tiens a te remercier pour ton super travail fournis qui marche parfaitement !!! ( juste le 9 et 0 mais cela doit venir d'un problème d'enregistrements... )
Je n'en reviens pas de l'efficacité de ta solution et je ne te remercie jamais assez ! Je peux enfin continué le développement de mon programme et de mon application Android ! Super, merci à vous !!

de rien ! en plus j'ai appris certaines choses ...