infrarosso
no way to compare when less than two revisions
Differenze
Queste sono le differenze tra la revisione selezionata e la versione attuale della pagina.
Revisione precedente | |||
— | infrarosso [2020/07/03 15:58] (versione attuale) – modifica esterna 127.0.0.1 | ||
---|---|---|---|
Linea 1: | Linea 1: | ||
+ | ====== Comunicazione a infrarosso ====== | ||
+ | |||
+ | Esperimenti di comunicazione a infrarosso con Arduino usando | ||
+ | * 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/ | ||
+ | |||
+ | 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 | ||
+ | |||
+ | |||
+ | <code C> | ||
+ | /* | ||
+ | TODO | ||
+ | - MAXPULSE dice che sono ms ma viene confrontato con | ||
+ | | ||
+ | |||
+ | |||
+ | | ||
+ | | ||
+ | - livello H per space (trasmettitore off) | ||
+ | - livello L per mark/burst (impulsi a 38kHz) | ||
+ | |||
+ | | ||
+ | | ||
+ | usare l' | ||
+ | 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 | ||
+ | | ||
+ | otto bit di PIND; se il risultato è ancora 00000100 | ||
+ | il segnale è alto | ||
+ | vedi PortManipulation e BitMath nella Reference | ||
+ | |||
+ | | ||
+ | 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/ | ||
+ | // 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' | ||
+ | |||
+ | void setup(void) { | ||
+ | Serial.begin(9600); | ||
+ | Serial.println(" | ||
+ | } | ||
+ | |||
+ | 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' | ||
+ | if ((highpulse >= MAXPULSE) && (currentpulse != 0)) { | ||
+ | // | ||
+ | printpulses2(); | ||
+ | currentpulse=0; | ||
+ | return; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // il segnale diventa L (o timeout) | ||
+ | // scrivo la durata dell' | ||
+ | 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' | ||
+ | if ((lowpulse >= MAXPULSE) | ||
+ | // | ||
+ | printpulses2(); | ||
+ | currentpulse=0; | ||
+ | return; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // il segnale diventa H (o timeout) | ||
+ | // scrivo la durata dell' | ||
+ | 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(" | ||
+ | Serial.println(" | ||
+ | Serial.println(" | ||
+ | for (byte i = 0; i < currentpulse; | ||
+ | Serial.print(pulses[i][0] * RESOLUTION, DEC); | ||
+ | Serial.print(" | ||
+ | Serial.println(pulses[i][1] * RESOLUTION, DEC); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void printpulses2(void) { | ||
+ | // \n\r newline + return lascia un linea vuota | ||
+ | Serial.println(" | ||
+ | Serial.println(" | ||
+ | Serial.println(" | ||
+ | Serial.print(pulses[0][1] * RESOLUTION, DEC); | ||
+ | for (byte i = 1; i < currentpulse; | ||
+ | Serial.print(" | ||
+ | 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. | ||
+ | |||
+ | <code C> | ||
+ | |||
+ | // 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, | ||
+ | Serial.begin(9600); | ||
+ | } | ||
+ | |||
+ | void loop() { | ||
+ | Serial.println(" | ||
+ | // 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, | ||
+ | delayMicroseconds(10); | ||
+ | digitalWrite(IRED, | ||
+ | delayMicroseconds(10); | ||
+ | usecs -= 26; | ||
+ | } | ||
+ | |||
+ | // riattiva gli interrupt | ||
+ | interrupts(); | ||
+ | } | ||
+ | |||
+ | // sequenza IR per scatto remoto Nikon D50 | ||
+ | void SendNikonCode() { | ||
+ | // comando scatto | ||
+ | pulseIR(2000); | ||
+ | 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. | ||
+ | |||
+ | <code C> | ||
+ | |||
+ | // 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, | ||
+ | Serial.begin(9600); | ||
+ | } | ||
+ | |||
+ | void loop() { | ||
+ | Serial.println(" | ||
+ | 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, | ||
+ | delayMicroseconds(10); | ||
+ | digitalWrite(IRED, | ||
+ | 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 | ||
+ | // | ||
+ | // | ||
+ | // | ||
+ | // | ||
+ | //540 540 | ||
+ | //560 540 | ||
+ | //540 540 | ||
+ | //560 540 | ||
+ | //560 540 | ||
+ | // | ||
+ | //540 1660 | ||
+ | // | ||
+ | //560 1680 | ||
+ | //520 1680 | ||
+ | //520 1680 | ||
+ | //520 1680 | ||
+ | //520 1680 | ||
+ | // | ||
+ | //560 540 | ||
+ | // | ||
+ | //560 1680 | ||
+ | //520 540 | ||
+ | //560 540 | ||
+ | //560 540 | ||
+ | //560 540 | ||
+ | // | ||
+ | //540 1660 | ||
+ | // | ||
+ | //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:// | ||
+ | * tutorial e programma senza librerie (adattato sopra) https:// | ||
+ | * tutorial con molti riferimenti utili https:// | ||
+ | * autore della libreria IR http:// | ||
+ | * generalità sulla trasmissione IR https:// | ||
+ | * datasheet https:// | ||
+ | * circuito di un ricevitore vishay https:// | ||
infrarosso.txt · Ultima modifica: 2020/07/03 15:58 da 127.0.0.1