Indice
Comunicazione a infrarosso
Esperimenti di comunicazione a infrarosso con Arduino usando un ricevitore IR integrato e un IRED:
- decodifica dei segnali di un telecomando
- telecomando per scatto remoto di una macchina fotografica digitale
- telecomando di una TV
Hardware
ricevitore IR
Un integrato con un fotodiodo e un circuito di condizionamento che si occupa della demodulazione del segnale a 38kHz inviato dal trasmettitore.
Tre piedini: Vcc, GND e segnale.
Segnale in uscita: alto quando non riceve (space), basso quando riceve un segnale IR a 38kHz (mark/burst).
Decodifica: esistono tanti protocolli che codificano 0 e 1 un maniera differente (ma sempre in base alla durata di space e mark). Il protocollo definisce anche cosa viene trasmesso e con che tempi (in genere 8 bit per indirizzo e comando che vengono inviati due volte e un codice per il repeat).
Trasmettitore
Un LED a infrarosso della lunghezza d'onda giusta (compatibile col ricevitore) da pilotare a 38kHz con un microcontrollore.
Idee per progetti
- video/foto di un telecomando mentre va (si vede col sensore di una camera digitale)
- reverse engineering di un protocollo IR
- copiare i dati di un telecomando (usare la libreria) per fare un telecomando con arduino e IRED
Osservazioni
- perché 38kHz? non confonde il segnale con altro
- non si riesce a vedere il segnale modulato, il ricevitore dà in uscita un segnale già demodulato
Decodifica segnale IR con Arduino
Esiste una libreria molto facile da utilizzare fatta da Ken Shirrif. Il programma seguente invece non usa librerie ed è sufficientemente facile da capire. Prerequisiti:
- tipi di dati
- bitwise math (shift, AND)
- array
- registri microcontrollori
/* TODO - MAXPULSE dice che sono ms ma viene confrontato con variabili che sono us/20 RICEVITORE IR demodula il segnale di un trasmettitore IR generando - livello H per space (trasmettitore off) - livello L per mark/burst (impulsi a 38kHz) LEGGERE I SEGNALI CON I REGISTRI I/O l'istruzione digitalRead() è troppo lenta perciò bisogna usare l'accesso diretto ai pin con i registri I/O PIND è il registro che permette di leggere il valore degli ingressi da 0 a 7 (0 livello L, 1 livello H) il terzo bit da destra di PIND è riferito al pin 2 nel test del ciclo while shifta 1 a sinistra di due posizioni (da 00000001 a 00000100) poi fa un AND con gli otto bit di PIND; se il risultato è ancora 00000100 il segnale è alto vedi PortManipulation e BitMath nella Reference PROGRAMMA ORIGINALE da adafruit modificato nello stile (const invece che define) e commentato in italiano */ // pin segnale ricevitore IR const byte IRpin = 2; // valore massimo di highpulse/lowpulse prima del timeout // 65000 intervalli da 20us = 1.3 secondi const unsigned int MAXPULSE = 65000; // risoluzione in us nella lettura degli impulsi // (gli intervalli saranno multipli di questo valore) const byte RESOLUTION = 20; // memorizza la durata di H e L per 100 impulsi unsigned int pulses[100][2]; byte currentpulse = 0; // indice dell'array pulses void setup(void) { Serial.begin(9600); Serial.println("Attesa sequenza IR!"); } void loop(void) { // durata H e L in numero di intervalli di 20us unsigned int highpulse, lowpulse; // azzerati a ogni ciclo highpulse = lowpulse = 0; // se il segnale demodulato è alto (space) while (PIND & (1 << IRpin)) { // incrementa highpulse e aspetta 20 us highpulse++; delayMicroseconds(RESOLUTION); // timeout: stampa la sequenza di impulsi, azzera // l'indice e esce da loop (ricominicia da capo) if ((highpulse >= MAXPULSE) && (currentpulse != 0)) { //printpulses(); printpulses2(); currentpulse=0; return; } } // il segnale diventa L (o timeout) // scrivo la durata dell'impulso H pulses[currentpulse][0] = highpulse; // se il segnale è basso (mark) while (! (PIND & (1 << IRpin))) { // incrementa lowpulse e aspetta 20 us lowpulse++; delayMicroseconds(RESOLUTION); // timeout: stampa la sequenza di impulsi, azzera // l'indice e esce da loop (ricominicia da capo) if ((lowpulse >= MAXPULSE) && (currentpulse != 0)) { //printpulses(); printpulses2(); currentpulse=0; return; } } // il segnale diventa H (o timeout) // scrivo la durata dell'impulso L pulses[currentpulse][1] = lowpulse; // passiamo al prossimo impulso (coppia durate H/L) currentpulse++; } void printpulses(void) { // \n\r newline + return lascia un linea vuota Serial.println("\n\rSequenza impulsi (tempi in microsecondi)"); Serial.println("space (H)\tmark (L)"); Serial.println("IR OFF\t\tIR ON"); for (byte i = 0; i < currentpulse; i++) { Serial.print(pulses[i][0] * RESOLUTION, DEC); Serial.print("\t\t"); Serial.println(pulses[i][1] * RESOLUTION, DEC); } } void printpulses2(void) { // \n\r newline + return lascia un linea vuota Serial.println("\n\rSequenza impulsi (tempi in microsecondi)"); Serial.println("mark (L)\tspace (H)"); Serial.println("IR ON\t\tIR OFF"); Serial.print(pulses[0][1] * RESOLUTION, DEC); for (byte i = 1; i < currentpulse; i++) { Serial.print("\t\t"); Serial.println(pulses[i][0] * RESOLUTION, DEC); Serial.print(pulses[i][1] * RESOLUTION, DEC); } }
Telecomando IR con Arduino
Programma adattato da adafruit per pilotare lo scatto remoto della mia Nikon D50 (funziona). Il codice IR è stato ottenuto con un telecomando Nikon e qualcosa tipo il programma sopra. Non usa i registri quindi è sicuramente migliorabile lato prestazioni.
// Intervallometro IR per la Nikon D50 (da adafruit) // IRED sul pin 13 con resistore da 1k byte IRED = 13; // intervallo in secondi tra gli scatti byte intervallo = 5; void setup() { pinMode(IRED, OUTPUT); Serial.begin(9600); } void loop() { Serial.println("Invio sequenza IR"); // invia comando scatto SendNikonCode(); // intervallo delay(intervallo * 1000); } // genera un segnale a 38kHz per tot microsecondi void pulseIR(long usecs) { // disattiva gli interrupt noInterrupts(); while (usecs > 0) { // 38 kHz corrisponde circa a 26 us (3+10+3+10) // digitalWrite impiega 3 us (usare i registri?) digitalWrite(IRED, HIGH); delayMicroseconds(10); digitalWrite(IRED, LOW); delayMicroseconds(10); usecs -= 26; } // riattiva gli interrupt interrupts(); } // sequenza IR per scatto remoto Nikon D50 void SendNikonCode() { // comando scatto pulseIR(2000); // 2080 codice adafruit non va! delay(27); pulseIR(440); delayMicroseconds(1500); pulseIR(460); delayMicroseconds(3440); pulseIR(480); // pausa delay(65); // ripetizione comando scatto pulseIR(2000); delay(27); pulseIR(440); delayMicroseconds(1500); pulseIR(460); delayMicroseconds(3440); pulseIR(480); }
Telecomando ON/OFF TV LG
La sequenza corretta è stata ottenuta confrontando il protocollo utilizzato dalla TV LG (il protocollo NEC) con la sequenza ottenuta col programma che decodifica i segnali IR (vedi sopra). E' possibile accendere e spegnere la TV con Arduino, un IRED (di lunghezza d'onda compatibile) e resistore. Testato su smart TV LG 43LF590V.
// TODO riscriverlo con array (o byte per la sequenza) // on/off smart tv LG // invia il comando e lo ripete dopo 2 minuti // reset per rilanciarlo // IRED sul pin 13 con resistore da 1k byte IRED = 13; void setup() { pinMode(IRED, OUTPUT); Serial.begin(9600); } void loop() { Serial.println("Invio sequenza IR tra un secondo"); delay(1000); // invia comando on/off SendCode(); // intervallo delay(120000); } // genera un segnale a 38kHz per tot microsecondi void pulseIR(long usecs) { // disattiva gli interrupt noInterrupts(); while (usecs > 0) { // 38 kHz corrisponde circa a 26 us (3+10+3+10) // digitalWrite impiega 3 us (usare i registri?) digitalWrite(IRED, HIGH); delayMicroseconds(10); digitalWrite(IRED, LOW); delayMicroseconds(10); usecs -= 26; } // riattiva gli interrupt interrupts(); } // sequenza IR per pulsante on/off LG // il protocollo e il NEC // 562 + 562 codifica il valore logico 0 // 562 + 1687 codifica il valore logico 1 // ottenuto con arduino e un ricevitore IR è questo //mark (L) space (H) //IR ON IR OFF //8880 4420 9ms + 4ms per inizio trasmissione //560 540 8 bit per l'indirizzo //560 540 //560 1660 indirizzo 00100000 //540 540 //560 540 //540 540 //560 540 //560 540 //560 1660 ancora l'indirizzo ma complementato //540 1660 //540 540 complementato 11011111 //560 1680 //520 1680 //520 1680 //520 1680 //520 1680 //520 540 8 bit del comando //560 540 //560 540 comando 00010000 //560 1680 //520 540 //560 540 //560 540 //560 540 //560 1660 ancora il comando ma complementato //540 1660 //540 1660 11101111 //540 540 //540 1680 //540 1660 //540 1660 //540 1660 //540 fine trasmissione void SendCode() { // inizio trasmissione pulseIR(9000); delayMicroseconds(4000); // indirizzo 00100000 pulseIR(560); delayMicroseconds(560); pulseIR(560); delayMicroseconds(560); pulseIR(560); delayMicroseconds(1687); pulseIR(560); delayMicroseconds(560); pulseIR(560); delayMicroseconds(560); pulseIR(560); delayMicroseconds(560); pulseIR(560); delayMicroseconds(560); pulseIR(560); delayMicroseconds(560); // indirizzo complementato 11011111 pulseIR(560); delayMicroseconds(1687); pulseIR(560); delayMicroseconds(1687); pulseIR(560); delayMicroseconds(560); pulseIR(560); delayMicroseconds(1687); pulseIR(560); delayMicroseconds(1687); pulseIR(560); delayMicroseconds(1687); pulseIR(560); delayMicroseconds(1687); pulseIR(560); delayMicroseconds(1687); // comando 00010000 pulseIR(560); delayMicroseconds(560); pulseIR(560); delayMicroseconds(560); pulseIR(560); delayMicroseconds(560); pulseIR(560); delayMicroseconds(1687); pulseIR(560); delayMicroseconds(560); pulseIR(560); delayMicroseconds(560); pulseIR(560); delayMicroseconds(560); pulseIR(560); delayMicroseconds(560); // comando complementato 11101111 pulseIR(560); delayMicroseconds(1687); pulseIR(560); delayMicroseconds(1687); pulseIR(560); delayMicroseconds(1687); pulseIR(560); delayMicroseconds(560); pulseIR(560); delayMicroseconds(1687); pulseIR(560); delayMicroseconds(1687); pulseIR(560); delayMicroseconds(1687); pulseIR(560); delayMicroseconds(1687); // fine trasmissione pulseIR(560); delayMicroseconds(4000); }
Riferimenti
- protocollo NEC (usato anche dalla mia smart TV LG) https://techdocs.altium.com/display/FPGA/NEC+Infrared+Transmission+Protocol
- tutorial e programma senza librerie (adattato sopra) https://learn.adafruit.com/ir-sensor/using-an-ir-sensor
- tutorial con molti riferimenti utili https://learn.sparkfun.com/tutorials/ir-communication#ir-communication-basics
- autore della libreria IR http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html
- generalità sulla trasmissione IR https://www.sbprojects.net/knowledge/ir/index.php
- circuito di un ricevitore vishay https://www.vishay.com/docs/80069/circuit.pdf