Fonctionnement et émulation USB d’une télécommande infrarouge pour LED RGB (Partie 1)

En traînant un peu sur le net, je suis tombé sur des bandes de diodes RGB (rouge/vert/bleu) contrôlées par télécommande (44 boutons) pour une trentaine d’euros les dix mètres. Il s’agit d’un clone chinois des lampes Living Colors de Phillips.

Après l’avoir installé et joué un peu avec l’éclairage, j’ai cherché à savoir comment celui-ci fonctionne ; l’idée étant de pouvoir contrôler le tout depuis un PC.

J’aurais pu démonter le boitier de commande de la bande de diodes, mais cela m’aurait forcer à tirer un second câble (en plus de l’alimentation) du PC jusqu’à la bande de diode, ce qui n’est pas pratique. Alors pour le défi, j’ai cherché à savoir comment fonctionne la télécommande, et comment émuler ses fonctions.

Télécommande RGB

S’équiper à moindre frais

Si vous disposez d’un PC avec une entrée pour micro, vous n’aurez pas besoin d’investir dans beaucoup de matériel. Prenez une prise jack mâle, une diode infrarouge réceptrice, une résistance de 4.7kΩ et un peu de fil.

irda_schema

Puis, téléchargez le logiciel Audacity (open-source). Il s’agit d’un éditeur de signal sonore, dont l’interface est un peu rude, mais il est très simple à utiliser.

Il suffit maintenant de choisir la bonne source de son, et de démarrer la capture. Un petit clic sur un des boutons de la télécommande, et hop !

irda_large

C’est quoi ce bazar ?!

Ici, on récupère le signal émis par la télécommande, mais seulement, celui-ci est échantillonné a 44100Hz. C’est bien pour « lire » le signal, mais ceci ne suffit pas à l’émuler.

Il est nécessaire de comprendre comment fonctionne, en théorie, le signal infrarouge.

La théorie (oui, il en faut un peu tout de même)

L’infrarouge est un signal très rudimentaire, qui à la fâcheuse tendance d’être sensible à la chaleur. En effet, toute source de chaleur (corps vivant, soleil, ampoule, …) émet naturellement des rayonnements infrarouges. Cela peut interférer avec le transfert d’un signal. Il n’est donc pas possible de considérer la présence d’un rayonnement comme un [ccie]1[/ccie] et l’absence comme un [ccie]0[/ccie].

On va alors utiliser un signal pulsé à une fréquence particulière. Ainsi, un [ccie]1[/ccie] sera un signal pulsé d’une durée déterminée, tandis qu’un [ccie]0[/ccie] sera un silence de même durée. Ceci implique de synchroniser le signal sur une fréquence particulière.

Rendered by QuickLaTeX.com

Pour déterminer cette fréquence, la méthode du microphone atteint ses limites ; il faudrait ici un oscilloscope avec une fréquence d’échantillonnage d’au moins une centaine de kilohertz. À défaut, il faut chercher un peu.

Prenons le signal acquis, et observons le. On a :

  • une longue crête de ~9ms
  • une longe crête de ~4.5ms
  • 4 paquets de 16 crêtes de ~0.5ms ou ~1.5ms

En fouillant, je suis tombé sur cet article (en anglais). Il s’agit du protocole infrarouge NEC.

On y est presque !

Le protocole NEC

Il s’agit d’un code, utilisant une fréquence de 38kHz (soit une modulation de 26.3µs) et dont le protocole est :

  • initialisation par un signal pulsé de 9ms (342 modulations), suivi d’un silence de 4.5ms
  • adresse du matériel (ici 0x00) sur 8 bits
  • inverse de l’adresse sur 8 bits
  • commande (ici 0x02 pour « POWER ») sur 8 bits
  • inverse de la commande sur 8 bits

Pour la transmission de l’adresse et de la commande, on code chaque bit de la façon suivante (le bit fort en premier) :

  • un signal pulsé de 560µs (21 modulations), suivi d’un silence de même durée pour [ccie]0[/ccie]
  • un signal pulsé de 560µs, suivi d’un silence de 1690µs pour [ccie]1[/ccie]

Voici ce que donne donc la trame qui permet l’allumage (ou l’extinction) des diodes :

Rendered by QuickLaTeX.com

Mettons cela en pratique

Il suffit de prendre un microcontrôleur (un ATTiny85 peut suffire, mais j’ai préféré prendre un ATMega168 pour ajouter une connexion série par la suite) et d’y brancher une diode infrarouge (émettrice cette fois).

Voici un code minimaliste qui se contente d’allumer et d’éteindre toutes les secondes. Vous y trouverez également les commandes disponibles en macro.

[cce_c]
#include <avr/io.h>
#include <util/delay.h>
#include <avr/sleep.h>

#define IR_PORT    PORTD
#define IR_DDR     DDRD
#define IR_PIN    PD2

#define SIGNAL_BOTTOM()    IR_PORT |= (1<<IR_PIN)
#define SIGNAL_TOP()    IR_PORT &= ~(1<<IR_PIN)
//38kHz
#define PULSE()        {SIGNAL_TOP();_delay_us(13.2);SIGNAL_BOTTOM();_delay_us(13.2);}

#define CMD_UP        0x3A
#define CMD_DOWN    0xBA
#define CMD_PLAY    0xB2
#define CMD_POWER    0x02

#define CMD_RED        0x1A
#define CMD_GREEN    0x9A
#define CMD_BLUE    0xA2
#define CMD_WHITE    0x22

#define CMD_DEEPORANGE    0x2A
#define CMD_LIGHTGREEN    0xAA
#define CMD_DEEPBLUE    0x92
#define CMD_HOTWHITE    0x12

#define CMD_ORANGE    0x0A
#define CMD_LIGHTBLUE    0x8A
#define CMD_PURPLE    0xB2
#define CMD_WARMWHITE    0x32

#define CMD_BROWN    0x38
#define CMD_TURQUOISE    0xB8
#define CMD_PINK    0x78
#define CMD_COLDWHITE    0xF8

#define CMD_YELLOW    0x18
#define CMD_CYAN    0x98
#define CMD_MAGENTA    0x58
#define CMD_ICEWHITE    0xD8

#define CMD_RED_UP    0x28
#define CMD_GREEN_UP    0xA8
#define CMD_BLUE_UP    0x68
#define CMD_QUICK    0xE8

#define CMD_RED_DOWN    0x08
#define CMD_GREEN_DOWN    0x88
#define CMD_BLUE_DOWN    0x48
#define CMD_SLOW    0xC8

#define CMD_DIY1    0x30
#define CMD_DIY2    0xB0
#define CMD_DIY3    0x70
#define CMD_AUTO    0xF0

#define CMD_DIY4    0x10
#define CMD_DIY5    0x90
#define CMD_DIY6    0x50
#define CMD_FLASH    0xD0

#define CMD_JUMP3    0x20
#define CMD_JUMP7    0xA0
#define CMD_FADE3    0x60
#define CMD_FADE7    0xE0

void init_sequence(){
uint8_t i;
for(i = 0; i<255; i++) PULSE();
for(i = 0; i<88; i++) PULSE(); //too lazy too swap to uint_16t (love your memory)
_delay_us(4500);
}

void send(uint8_t bit){
int8_t i;
for(i = 0; i<21; i++) PULSE();
if (bit & 0x01) _delay_us(1130);
_delay_us(560);
}

void send_command(uint8_t address, uint8_t command){
init_sequence();
int8_t i;
for(i=7;i>=0;i–) send(address >> i);
for(i=7;i>=0;i–) send(~address >> i);
for(i=7;i>=0;i–) send(command >> i);
for(i=7;i>=0;i–) send(~command >> i);

}

int main(){
IR_DDR = (1<<IR_PIN);
for(;;){
send_command(0x00,CMD_POWER);
_delay_ms(1000);
}
}
[/cce_c]

Ou quelque chose de plus funky :

[cce_c]
int main(){
IR_DDR = (1<<IR_PIN);
for(;;){
send_command(0x00,CMD_TURQUOISE);
_delay_ms(100);
send_command(0x00,CMD_ORANGE);
_delay_ms(100);
send_command(0x00,CMD_PURPLE);
_delay_ms(100);
}
}
[/cce_c]

2 thoughts on “Fonctionnement et émulation USB d’une télécommande infrarouge pour LED RGB (Partie 1)”

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *