Questa è una vecchia versione del documento!
Indice
Comunicazione a infrarosso
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
Esempio con decodifica segnale IR
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); } }
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
- datasheet