// Arduino: decodifica di un telecomando a raggi infrarossi 16 – decodifica di un telecomando a raggi infrarossi I raggi infrarossi sono delle radiazioni elettromagnetiche la cui lunghezza d’onda varia da 0,7 micron a 0,4 millimetri. Si tratta in pratica di una luce non percepibile dall’occhio umano ma percepita da particolari fotoresistenze. Volendo sintetizzare al massimo i tecnicismi relativi alla trasmissione infrarossa e’ possibile affermare che il telecomando altro non e’ che un led che emette luce infrarossa mentre il ricevitore e’ una fotoresistenza sensibile agli infrarossi. Il telecomando emette una serie di impulsi (che si concretizzano in brevissimi flash di luce infrarossa) che vengono letti ed interpretati dal ricevitore. Gli impulsi infrarossi trasmessi dal telecomando ricordano, a tratti, il vecchio alfabeto morse. Il trasmettitore invia al ricevitore bytes da 8 bit componendo gli “0” e gli “1” modulando opportunamente gli intervalli di tempo tra un flash e l’altro. Se il telecomando emettesse una luce visibile e se i tempi fossero dilatati potremmo distinguere lo zero dall’uno semplicemente misurando il tempo trascorso tra un’illuminazione e la successiva. Un tempo lungo corrisponderebbe ad un 1 mentre un tempo breve corrisponderebbe ad uno zero. In realta’ il protocollo di codifica e’ un po’ piu’ complicato di quanto detto poiche’ ogni comando e’ composto da una sequenza di 32 bit (4 bytes) preceduta da un segnale di sincronismo (un blocco luminoso da 9 microsecondi seguito da un blocco non luminoso da 4,5 microsecondi). Ogni bit rappresentato da flash da 0,56 microsecondi e da un intervallo senza luce che se e’ corto (0,56 microsecondi) indica uno zero mentre se e’ lungo (1,7 microsecondi) indica un 1. I quattro bytes rappresentano, nell’ordine, un indirizzo, la ripetizione dell’indirizzo, il comando e la ripetizione del comando (quest’ultimo con la sequenza di bit invertita). Sia il ricevitore che il trasmettitore devono essere in connessione “visiva” non devono cioe’ frapporsi ostacoli tra l’apparecchio trasmittente ed il modulo ricevente. Il ricevente inoltre interpreta al meglio il segnale quando il trasmettitore e’ posto esattamente davanti al bulbo (ad una distanza massima di 8 metri). Questo esercizio si concretizza nell’evidenziare sul monitor seriale i comandi inviati da un telecomando e puo’ quindi essere utilizzato anche per “decodificare” i segnali inviati dai vari telecomandi di casa. In questa tabella sono riportati i segnali trasmessi dai 21 tasti del telecomando illustrato in figura (valore HEX = valore esadecimale e valore DEC = valore decimale): pulsante valore HEX Valore DEC pulsante Valore HEX Valore DEC pulsante Valore HEX Valore DEC Bottone rosso VOL + FUNC/STOP Indietro veloce Pausa/avvio Avanti veloce Punta bassa 0xff00 0xfe01 0xfd02 0xfb04 0xfa05 0xf906 0xf708 0 1 2 4 5 6 8 VOL Punta alta 0 EQ ST/REPT 1 2 0xf609 0xf50a 0xf30c 0xf20d 0xf10e 0xef10 0xee11 9 10 12 13 14 16 17 3 4 5 6 7 8 9 0xed12 0xeb14 0xea15 0xe916 0xe718 0xe619 0xe51a 18 20 21 22 24 25 26 Il ricevitore utilizzato in questo esercizio, marchiato 1057 D21B, ha la piedinatura illustrata in figura. E’ ovviamente possibile utilizzare altri tipi di ricevitori, purche’ vengano rispettate le // Arduino: decodifica di un telecomando a raggi infrarossi funzionalita’ dei piedini (il positivo all’alimentazione da 5 volt, il negativo a terra ed il sensore alla porta 2). Nota: Questo esercizio e questa nota sono parte di una serie che vede protagonisti arduino ed alcuni dei componenti ad esso collegabili. Per la maggior parte degli esercizi e’ anche disponibile un filmato su youtube. Esercizi facenti parte della raccolta Filmati presenti su youtube Informazioni su arduino e sui componenti collegabili Breve manuale di programmazione Materiali 1 telecomando ad infrarosssi 1 modulo ricevitore di infrarossi 1 breadbord 3 cavetti Schema Programma /* Per comprendere al meglio questo esercizio e' opportuno comprendere prima i principi di funzionamento di un telecomando o, meglio, comprendere il protocollo di comunicazione dei segnali. Tutto cio' e' spiegato, anche se non in maniera esaustiva, nelle note descrittive su telecomando e ricevitore ad infrarossi che accompagnano questo esercizio. // Arduino: decodifica di un telecomando a raggi infrarossi Questo programma e' derivato da un programma, non professionale, esistente sul web ed il sistema telecomando / ricevitore ad infrarossi / arduino non sempre risponde con prontezza agli impulsi. E’ possibile che tale ritardo dipenda dal fatto che il momento di pressione di un tasto non sempre coincide con il momento in cui il programma verifica l'arrivo di un blocco di sincronismo Per ottenere una risposta e' quindi a volte necessario premere piu' volte ed in rapida successione un tasto, in modo da favorire la sincronizzazione tra telecomando ed apparato ricevente Un’ultima osservazione riguarda il telecomando illustrato in figura nelle note descrittive. Si tratta di un prodotto di infima qualita’ il cui cattivo funzionamento comporta spesso la necessita’ di premere piu’ volte un tasto. L’impianto risponde meglio se, in sua vece, si utilizza un qualunque telecomando di casa */ int IR_IN = 2; // inserisce 2 nella variabile IR_IN utilizzata per // indicare la porta alla quale e' collegato il ricevitore del segnale infrarosso int Pulse_Width = 0; int ir_code = 0x00; char adrL_code = 0x00; char adrH_code = 0x00; // zona di memorizzazione del tempo trascorso dal precedente impulso // zona di memorizzazione dell’indirizzo inviato dal telecomando // byte in cui viene memorizzato il comando // byte in cui viene memorizzato il comando invertito (Anti-code) void timer1_init(void) /* *******routine di inizializzazione delle zone di memorizzazione del tempo. Le seguenti variabili sono gestite ed autonomamente utilizzate da arduino per gestire il trascorrere del tempo. In particolare la variabile TCNT1 e’ di fatto un timer contenente un valore corrispondente al tempo trascorso dal suo ultimo azzeramento */ { TCCR1A = 0X00; TCCR1B = 0X05; // modulatore del tempo; con il valore 5, TCNT1 si incrementa di 15625 unita’ // ad ogni secondo TCCR1C = 0X00; TCNT1 = 0X00; // timer, con TTCCR1B = 5 si incrementa di 15625 unita' ad ogni secondo, // fino ad un massimo di circa 65000, poi si azzera e ricomincia TIMSK1 = 0X00; } char logic_value() /* ***********routine di analisi dell’impulso ricevuto. ************* Restituisce il valore 0 (0,56 microsecondi dal precedente impulso, corrispondente al valore 0) oppure 1 (1,7 microsecondi dal precedente impulso, corrispondente al valore 1) oppure -1 nessun tasto premuto o segnale non riconosciuto*/ { TCNT1 = 0X00; // azzera il timer while(!(digitalRead(IR_IN))); // se non c’e’ impulso verifica il tempo trascorso Pulse_Width=TCNT1; TCNT1=0; if(Pulse_Width>=7&&Pulse_Width<=10) // 0,56 microsecondi { while(digitalRead(IR_IN)); // se c’e’ un impulso Pulse_Width=TCNT1; //memorizza il tempo trascorso dal precedente impulso TCNT1=0; if(Pulse_Width>=7&&Pulse_Width<=10) // 0.56 microsecondi return 0; else if(Pulse_Width>=25&&Pulse_Width<=27) // 1.7 microsecondi // Arduino: decodifica di un telecomando a raggi infrarossi return 1; } return -1; } void pulse_deal() // ******Routine di memorizzazione dei 4 bytes di indirizzo e comando **** { int i; int j; ir_code=0x00; // azzera l'area di memorizzazione del comando adrL_code=0x00; // azzera l'area di memorizzazione dell'indirizzo adrH_code=0x00; // azzera l'area di memorizzazione dell'indirizzo inverso // nelle prossime righe analizza i valori trasmessi dal telecomando e compila, bit per bit, // i 4 bytes in cui viene memorizzato il comando (due bytes di indirizzo e due bytes di comando) for(i = 0 ; i < 16; i++) // memorizza i 16 bit dei due bytes di comando { if(logic_value() == 1) // se la routine di ricezione restituisce il valore 1 ir_code |= (1<<i); // Salva il bit del comando } for(i = 0 ; i < 8; i++) // memorizza gli 8 bit del byte di indirizzo { if(logic_value() == 1) adrL_code |= (1<<i); // salva il bit dell'indirizzo } for(j = 0 ; j < 8; j++) // memorizza gli 8 bit del byte del comando inverso { if(logic_value() == 1) adrH_code |= (1<<j); // Salva il bit dell'indirizzo inverso } } void remote_decode(void) // ************* Routine di ricezione e decodifica del segnale ********* { TCNT1=0X00; while(digitalRead(IR_IN)) // esegue la routine quando riceve un impulso { if(TCNT1>=1563) // se sono trascorsi piu' di 100 millisecondi dal precedente // impulso significa che il telecomando non e’ in uso e quindi azzera le zone di // memorizzazione dei codici e torna alla routine chiamante { ir_code=0x00ff; // inserisce il valore FF nel comando (0x00ff corrisponde al // tasto "spento" del telecomando) adrL_code=0x00; // azzera il byte di indirizzo adrH_code=0x00; // azzera il byte di indirizzo inverso return; } } // Se la durata e’ inferiore a 100 microsecondi significa che il telecomando e' in uso // e quindi si predispone a ricevere una sequenza di impulsi TCNT1=0X00; while(!(digitalRead(IR_IN))); // se non c'e' impulso verifica il tempo trascorso dal // precedente impulso Pulse_Width=TCNT1; TCNT1=0; if(Pulse_Width>=140&&Pulse_Width<=141) // 9 microsecondi. Se sono trascorsi 9 microsecondi // Arduino: decodifica di un telecomando a raggi infrarossi // significa che e' arrivato il primo segnale di sincronismo { while(digitalRead(IR_IN)); // verifica se dopo il primo blocco di sincronismo sono trascorsi // 4,5 microsecondi, (secondo segnale di sincronismo) Pulse_Width=TCNT1; TCNT1=0; if(Pulse_Width>=68&&Pulse_Width<=72) // 4.5ms { pulse_deal(); // Se e' arrivato anche il secondo segnale di sincronismo lancia la routine // di ricezione ed interpretazioni della sequenza di impulsi (pulse_deal) return; } else if(Pulse_Width>=34&&Pulse_Width<=36) //2.25ms { while(!(digitalRead(IR_IN))); // Low attesa Pulse_Width=TCNT1; TCNT1=0; if(Pulse_Width>=7&&Pulse_Width<=10) //0,56 microsecondi { return; } } } } void remote_deal(void) // ***********routine di esecuzione delle funzioni richieste dal telecomando // (e cioe’ visualizzazione, sul monitor di sistema, del comando ricevuto) { Serial.print ("codice: "); Serial.print (ir_code,HEX); // Visualizzazione esadecimale Serial.print (" indirizzo: "); Serial.println(adrL_code,HEX); // Visualizzazione esadecimale } void setup() { Serial.begin (9600); // predispone la porta seriale ad un velocita’ di 9600 bit al // secondo pinMode(IR_IN,INPUT); // definisce come porta di ingresso la porta IR_IN (la porta 2), // alla quale e' collegato il ricevitore infrarossi, } void loop() { timer1_init(); //inizializza le zone di gestione del tempo { remote_decode(); // lancia la routine di ricezione e decodifica dei segnali remote_deal(); // lancia la routine di visualizzazione dei comandi ricevuti } }