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.
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.
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 !
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.
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 :
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)”