Indice |
La situazione in casa
Avrete sicuramente a disposizione un televisore, nonché il suo relativo telecomando, e quindi, si spera in quest'articolo, qualche pulsante inutile che non svolga alcuna funzione. Mi riferisco ad esempio alla fila di pulsanti sul fondo del dispositivo, quelli dediti ad eventuali videoregistratori o blocchi multimediali della stessa marca e modello del televisore che probabilmente nessuno acquisterà mai.
Il mio telecomando per esempio dispone di un pulsante marchiato "D", che sta ad abbreviare una funzionalità equipaggiata da alcuni aggeggi Samsung che riescono ad essere attivati dalla sua pressione. In condizioni nominali il televisore non dispone di altre periferiche, e alla sua pressione non avviene assolutamente nulla.
Ebbene poltrendo sul divano davanti al suddetto televisore mi è balenata in testa l'idea di assegnare a questo benedetto pulsante una funzione, così, per dargli un po' di dignità insomma... La funzione che svolge adesso è quella di accendere e spegnere le luci esterne, quelle in giardino. Alla sua pressione avviene un toggle dell'illuminazione.
Ovviamente si può assegnare qualsiasi funzione a qualsiasi cosa, ammesso che questo qualcosa esista e compia un lavoro di qualche genere... In pratica come avrete già capito si può far fare all'attuatore qualsiasi gesto, anche aprire un diga o lanciare un missile balistico, la parte difficile è la parte di decodifica del comando.
Non ha molto senso scrivere un articolo riguardante casi generali per qualsiasi protocollo di comunicazione, quindi qui mi limiterò a parlare di telecomandi e treni di impulsi nell'IR, quindi mi spiace ma niente radiofrequenze o ponti laser (in realtà penso ne siate mediamente più che contenti).
Dopo questa lunga e inutile introduzione, vediamo come interpretare la magia nera del telecomando.
Un po' di teoria
Un telecomando è un dispositivo che permette di inviare un treno di impulsi a frequenza infrarossa. La sua capacità di discriminazione tra un tasto e l'altro è legata alla presenza di piste resistive che per ogni pulsante comunicano al microcontrollore al suo interno che sequenza inviare attraverso il led posto sul fronte. Alla pressione di un qualsiasi tasto una portante intorno ai 40 kHz è modulata da un'onda quadra e spedita da questo sotto forma di luce. La portante è in alta frequenza rispetto al segnale da trasmettere che è in banda base, ciò avviene perché il ricevitore (TSOP in questo articolo) contiene al suo interno un filtro passa-banda abbastanza stretto da estrarre e convertire in "rettangoli" di tensione solo le componenti nella banda di interesse. Il sole, gli altri telecomandi e la luce artificiale renderebbero altrimenti impossibile la trasmissione corretta di un messaggio, dato che le componenti nell'infrarosso di questi elementi creerebbero un offset imprevedibile ed onnipresente su qualsiasi componente in ricezione non filtrato.
Un esempio
Un telecomando deve comunicare al ricevitore della TV la sequenza "11010", che quindi verrà interpretata e verrà eseguito il comando correlato. Va detto che la sequenza è di solito molto più lunga, sopratutto perché prima della sequenza il telecomando trasmette un "header", ossia un blocco di bit che rimane invariato per ogni tasto. Questo consente di comunicare solo col dispositivo realmente interrogato: solo il televisore che riceve l'header che è stato programmato a ricevere interpreterà la sequenza che segue ad esso. Gli altri "bussolotti", invece, ignoreranno il messaggio valutandolo come disturbo, pensando "no, non sta parlando con me". I ricevitori IR più comuni sono infatti costruiti più o meno vicini ai soliti 40 kHz, c'è chi scende a 38, chi sale a 45, ma la reiezione di banda non è certamente netta, non abbiamo alcun delta di Dirac centrato sulla nostra portate e ne segue che qualsiasi cosa che più o meno oscilli lì attorno verrà valutata e messa in output, magari più o meno disturbata. Con il nostro header (che sarà certamente anch'esso una sequenza di bit alquanto lunga) assoceremo univocamente il telecomando alla televisione. Questo è quello che quindi accade:
Cosa ci serve
Facciamo il punto della situazione, questo è quello che dobbiamo fare.
- Capire cosa siamo in grado di realizzare, cosa ne sappiamo di elettronica analogica. Se anche non foste molto ferrati nella costruzione di cose strane ma bravi con i PIC, sappiate che la cosa più semplice da realizzare è il pilotaggio di un relè. So che l'hobbista punta alla fine sempre a questo, quindi sì, viste le potenzialità di questo apparecchio elettromeccanico vediamo come pilotarne uno per poi collegarci il carico che più ci è comodo
- Identificare sul telecomando un pulsante inutilizzato e possibilmente non interferente con il televisore da adibire ai nostri scopi (magari che non cambi canale o lo spenga!)
- Identificazione della sequenza inviata alla pressione del suddetto tasto, riconoscimento dell'header e della sequenza ad esso associata
- Scelta del microcontrollore, stesura di un flow chart, realizzazione del codice, programmazione del dispositivo, interfacciamento con il mondo reale
Analisi del treno di impulsi
Procuriamoci un oscilloscopio. Grazie al mio illimitato budget da studente ho utilizzato la scheda audio del PC collegando all'ingresso Line In un jack che finisce in due coccodrilli. Un software gratuito e utilissimo per sfruttare questa feature dei poveri è Visual Analyser, che implementa inoltre un analizzatore di spettro con cui potrete identificare la frequenza a cui è centrato il led del vostro telecomando, sempre che la vostra scheda audio non sia già a -600 dB alla vertiginosa frequenza di 40 kHz. Se così fosse (e probabilmente sarà proprio così) non preoccupatevi, la precisione non è richiesta, anche perché io non avendo proprio modo di misurarla ho smontato un vecchio decoder in cui ho trovato un TSOP, che ha funzionato lo stesso per forza di cose. Vi ricordo infatti che avendo un ricevitore centrato un po più in là della nostra portante avremo un degrado del segnale che si traduce solo in un minor "raggio d'azione" del telecomando, a meno di casi patologici. Un dispositivo come il TSOP1740 è esattamente ciò che ci serve: si tratta di un circuito integrato prodotto dalla Vishay che riceve un segnale infrarosso e genera in uscita dei treni di impulsi in banda base con logica invertita. Questo significa semplicemente che alla ricezione della portante l'uscita è LOW, mentre quando il TSOP non riceve nulla, o meglio riceve rumore luminoso ambientale troppo distante dalla frequenza ad esso associata (si veda il datasheet per i codici frequenza corrispondenti) l'uscita è HIGH, vicino al rail di alimentazione. Va costruito quindi un circuito di prova utilizzando uno di questi ricevitori e puntandogli il telecomando contro, oppure aprendo il telecomando e agganciandosi al led di trasmissione. Nel mio caso alla pressione del tasto voluto ho ottenuto la sequenza in figura.
Come vi avevo predetto la cattura è triste ma tutto sommato sufficiente, tanto da consentirmi il calcolo della base dei tempi necessaria alla decodifica e la posizione dei singoli bit. Come è evidente ogni bit è separato dagli altri da uno spazio morto, in cui la portante è soppressa, di durata sempre uguale. Nel caso di uno zero logico la portante continua a rimanere soppressa. L'header (a sfondo bianco) è stato identificato con la cattura della pressione di vari tasti e cercando la parte minima di ripetizione. Vorrei precisare che il rilevamento dell'header non è essenziale, ma ci risparmia la stesura nel codice di un flow condizionale più lungo che implica tra l'altro considerazioni temporali e logiche per ogni fronte di salita e discesa. Avendo identificato la forma dell'header potremo aspettare in polling il ricevitore e controllare che all'arrivo di un blocco questo sia della durata giusta, per poi procedere "saltando" di qualche millisecondo in avanti. Di solito l'header a sua volta inizia con uno stato HIGH più lungo di tutti gli altri, per permettere al dispositivo di prepararsi alla decodifica, magari dandogli il tempo di svegliarsi da un'istruzione SLEEP attendendo il fronte di discesa. Nel mio caso il primo tratto dura 5 ms, mentre l'header totale dura in ogni caso per ben 21 ms: questo fatto può essere sfruttato nel codice rilevando la durata del primo blocco di 5 ms per poi "volare" 16 ms più avanti e controllare il comando vero e proprio. Questo salto temporale sembrerebbe vanificare tutte le promesse di robustezza fatte fin qui, tuttavia notiamo il seguente: in un salotto standard abbiamo un televisore, un decoder (se non è integrato), uno stereo (ormai quasi più) e un dvd player (ancora più raro). Anche ammesso che ogni dispositivo moduli la stessa portante, la probabilità che ci siano telecomandi con uno stesso header sono quasi nulle (è fatto di proposito giustamente), inoltre quel che davvero ci interessa è la discriminazione della pressione di un tasto del telecomando della TV rispetto agli altri della stessa TV. Risulta praticamente impossibile che altri dispositivi riescano a trasmettere un treno di impulsi che sia in grado di attraversare i blocchi condizionali del codice che andremo a scrivere.
La nostra cattura andrà analizzata con cura, confrontandola con quella degli altri tasti e calcolando bene le tempistiche tra un fronte e l'altro, in modo da scrivere correttamente una routine che arrivi finalmente alla commutazione del relè.
L'analogica del caso
Il circuito è molto semplice. Il segnale è invertito via software (il TSOP inverte la logica del segnale che riceve).
Il package in cui si presenta il ricevitore utilizzato
Il programma
Questa parte verrà presentata in linguaggio HiTech C, uno standard utilizzato in larghissima parte dai neofiti (quale io sono!) che si trovano alle prese con i primi PIC. Il codice è molto semplice, la parte importante è la comprensione del suo meccanismo.
Discriminiamo una sequenza
Ammettiamo che il nostro PIC (o qualche suo parente) sia configurato per avere in ingresso il segnale negato di un TSOP (ricordatevi che questo tipo di integrato inverte il segnale logico!) e disponga della funzione COMMUTAZIONE RELE, che ogni volta che viene chiamata commuta il relè, tralasciando la parte di pilotaggio che vedremo dopo. Il PIC quindi riceve un segnale alto costante o basso costante, non sono ammessi altri stati (questo è garantito dal TSOP, che rimane active_low in presenza della portante e viceversa). Diciamo anche che conosciamo la durata dell'header: questo significa che possiamo aspettare un fronte di salita, aspettare un tempo di header e poi controllare se riceviamo la sequenza del nostro tasto, che in questo esempio è "001" (per comodità del lettore). Il programma seguirà la seguente successione condizionale:
Per una sequenza come la mia andranno quindi inseriti 35 controlli a intervalli di 1 ms (si veda la cattura sopra), al cui termine, se ci si arriva, si può commutare il relè poiché è stato premuto il tasto giusto e il treno verificato.
Scriviamo il codice
Il PIC utilizzato è il solito PIC16F648A, che risulta anche esagerato per il caso in questione. Ne avanzavo uno di un vecchio ordine e ho deciso di renderlo utile.
Dire che il codice sia grezzo è un complimento, ma vista l'applicazione univoca e statica di questo caso una cascata di if() risulta sufficiente senza complicarsi la vita con estrazione della sequenza in un vettore, cosa che avevo immaginato di fare all'inizio ma poi ho abbandonato dato che avevo solo un tasto a disposizione. Sarebbe tornata utile solo per eventuali applicazioni future di scelta multipla. La scrittura di una funzione di riconoscimento e salvataggio non è difficile, è sufficiente aggiornare uno o due variabili intere ad ogni lettura; così facendo si potranno assegnare funzioni diverse a tasti diversi. Prima di iniziare ci tengo a precisare che il seguente l'ho scritto per un telecomando specifico e con delle regolazioni che si riconducono solo al mio caso quali offset dei tempi, tolleranze sui tempi di bit e immunità alla deriva di scarica della batteria del telecomando, ma come ho detto il codice è talmente semplice che adattarlo sarà facile. Le tecniche di attesa e controllo possono essere inoltre più efficaci e sintetiche delle seguenti.
#include <pic.h> |
L'inizio del codice è costituito dalle direttive al compilatore, ossia l'inclusione dell'header del PIC (che poi sarà interpretato da MPLab), l'assegnazione dei nomi mnemonici OUT (commutazione relè) e IRL (IR led, ossia l'ingresso invertito via software). La direttiva WAIT è in realtà un modo un po brutto per implementare una funzione d'attesa. Ogni qualvolta il compilatore trovi "WAIT" nel codice ad alto livello lo sostituisce con i quattro comandi accanto; la "funzione" aspetta due volte l'overflow di TMR2 che impostato da PR2 per resettarsi al tempo richiesto salta di valore in valore lungo la sequenza ricevuta in ingresso, controllando se ci sia un valore HIGH o LOW tramite semplici if().
__CONFIG ( MCLRE_OFF & FOSC_HS & WDTE_OFF & PWRTE_ON & BOREN_OFF & LVP_OFF & CPD_OFF & CP_OFF ); static unsigned int value; void main (void) { unsigned char i; TRISA = 0b00000010; TRISB = 0; GIE = 0; // TMR1, prescaler 1:1 T1CON = 0b00000001; // TMR2, prescaler 1:16 T2CON = 0b00000010; TMR2 = 0; // PR2 set for 0.536 ms every overflow PR2 = 105; |
Per prima cosa imposto i fuses del PIC, per poi dichiarare un valore lungo 16 bit che poi utilizzerò per salvare il valore di Timer1. In questo caso il pin MCLRE* può essere dichiarato "internally tied to Vdd" per risparmiare una connessione esterna.
Nel main definisco "i" come unsigned char (si noterà poi che si sarebbe potuto utilizzare uno static bit, non è importante), per poi configurare un ingresso in TRISA, disabilitare gli interrupts (che non ci servono dato che useremo un polling sul bit di overflow dei timer) e impostare i timer.
La parte dei timer è delicata: TMR1 viene utilizzato per il conteggio di tempi lunghi mentre TMR2 è impostato per raggiungere l'overflow ogni 105 incrementi. Se questa parte non dovesse essere chiara consiglio la lettura del datasheet di questo PIC. "Purtroppo" per poter scrivere il codice autonomamente la lettura va fatta.
Come ho detto prima, TMR2 con l'oscillatore esterno e con questa impostazione consente alla direttiva WAIT di far passare circa 1 ms "lanciando" il controllo circa sopra al bit in ricezione (il controllo non è effettuato da WAIT ovviamente, come vedremo dopo).
Una nota
Questo tipo di controllo in anello aperto non è consigliabile per sequenze più lunghe: i controlli infatti sono effettuati in modo assoluto, ossia forzando i timer a scandire un tempo deciso da un'osservazione "personale" e che "di solito" rimane entro certi limiti. Se il telecomando si scaricasse e per qualche motivo i fronti ricevuti si allontanassero (o si avvicinassero) di qualche frazione della base dei tempi i controlli finirebbero sistematicamente fuori dai punti di interesse poiché i tempi del ricevitore rimarrebbero indipendenti dal trasmettitore. Questo suggerisce che la "brevità" della nostra sequenza è un caso particolare: per sequenze più lunghe (per altre applicazioni) dovremmo individuare i fronti che delimitano i bit e confrontare la durata tra di essi con intervalli di confidenza predefiniti per poi scegliere tra un "1" e uno "0".
In ogni caso da qui in poi si entra in un while(1) che nella quasi totalità del tempo aspetta che arrivi il nostro comando. Inserirò in commenti nel codice per maggior fluidità di lettura. Si ricordi sempre il diagramma di flusso riportato sopra. Ho preferito lasciare nel codice i commenti in inglese, che sono quelli originali che ho messo per mia utilità.
while(1) |
L'assemblaggio
Il mio impianto luci si compone di un timer comune per tutte le case, esso pilota in contemporanea tutte le luci esterne. Ho posizionato in una scatola impermeabile il circuito programmato insieme ad un alimentatore ricavato da un vecchio carica batterie per cellulare che fornisce 4.5 V più o meno precisi, con una buona corrente per eccitare il relè. La scatola si interpone in serie all'alimentazione delle luci del mio giardino e ad inizio programma si presenta a riposo, di modo che anche spegnendole l'assenza di alimentazione diurna porti il programma in reset (il PIC si dimentica dello stato precedente, eventualmente si può memorizzare nella memoria non volatile l'ultimo stato assunto dall'uscita per poi ripristinarlo alla prossima accensione). La scatola presenta un connettore femmina da cui si dipanano tre cavi scollegabili di piccola sezione adibiti all'alimentazione e al segnale del ricevitore posto davanti alla mia finestra, posizionata al piano superiore.
I due blocchi sono fissati con cinque punti di colla a caldo all'interno della plastica. La scatola presenta degli ingressi in gomma per isolarne l'interno dall'umidità del garage. Nella foto manca solo il cablaggio relè-morsetti e il microcontrollore, che verrà inserito nello zoccolo, installato per eventuali riprogrammazioni.
Il fissaggio è stato fatto attraverso un singolo tassello. Nella scatola entra il cavo di alimentazione luci pilotato dal relè, che poi torna nella solita sede. Per gentile concessione di mio fratello piccolo che ha fatto la foto, dato che io sono lontano da casa, è incluso un ragno nella foto conclusiva.
Il ricevitore è fissato con una goccia di colla a caldo all'interno dell'ampolla di una luce esterna. A luce accesa la capacità passa-banda del circuito integrato consente al segnale di essere discriminato molto efficacemente dal rumore luminoso di enorme intensità proveniente dalla lampadina sopra di questo.
Conclusione
L'esempio presentato in quest'articolo può funzionare come linea guida per l'analisi di un segnale nell'infrarosso. Una volta raggiunta la fine del flusso di riconoscimento l'azione eseguibile può essere, come già discusso, una qualsiasi. È interessante osservare la robustezza di questo meccanismo di riconoscimento (se costruito a dovere) rispetto alla sua facilità di implementazione, cosa che a livello amatoriale può conseguire in svariate idee per l'ambiente domestico di facile realizzazione. Il codice che ho riportato è molto spartano, si può costruire una funzione a tempi relativi molto più forte di quelle presentate, utilizzare un microcontrollore più piccolo, omettere il quarzo esterno ed implementare uno standby per il circuito in caso di alimentazione autonoma. Il caso quasi-duale che sarebbe interessante realizzare sarebbe la realizzazione di un dispositivo che registri un buon numero di sequenze esterne (magari le più utilizzate) per poi trasformarsi in un telecomando multiplo per tutta la sala.
Per ora sono solo interessanti passatempi di uno studente di Ing. Elettronica.