esempio: Trasmissione ricezione IR
Costruire il seguente circuito (serve un ricevitore, un trasmettitore IR e una resistenza da 180 ohm)
Costruiamo i due circuiti:
Ecco l'immagine del circuito ricevente
e quello del circuito trasmissivo.
Per la trasmissione IR è sufficiente un LED IR ed una
resistenza per limitare la corrente di 100 Ohm (ho
usato una da 180 Ohm). Se aumento la
resistenza riduco la “luminosità” del LED IR riducendo la portata del
segnale.
Disponiamo poi circuiti in modo che il ricevitore e il trasmettitore possano
comunicare.
Il modo più semplice per gestire la trasmissione IR è quello di utilizzare una opportuna libreria IRRemote.zip . Va scompattata nella cartella delle librerie di arduino ovvero in: C:\Program Files\Arduino\libraries. La cartella ottenuta va rinominata in Keypad e poi, tramite il menu di arduino Sketch => Importa Libreria ... ==> AddLibrary, va aggiunta. Questa classe mette a disposizione alcuni metodi che semplificano di molto l’obiettivo.
La libreria IRremote consente sia la trasmissione
che la ricezione. Vediamo ora i comandi disponibili:
Ricezione:
IRrecv irrecv(receivePin) : Crea un oggetto ricevente. Il nome della
variabile (istanza) può essere definito a piacere.
irrecv.enableIRIn() : Inizia il processo di ricezione. Attiva un timer
che utilizza una piccola quantità di CPU ogni 50 µs (microsecondi 10-6).
irrecv.decode(&results): Tenta di ricevere un segnale IR.
Restituisce vero se un segnale è stato ricevuto, falso altrimenti. Quando un
segnale è stato ricevuto, immagazzina l'informazione all'interno della variabile
strutturata "results". I campi di tale variabile sono:
results.decode_type: Restituisce uno dei seguenti valori:
NEC, SONY, RC5, RC6 o UNKNOWN.
results.value: Il tipo di codifica IR (0 se il tipo è
sconosciuto UNKNOWN)
results.bits: Il numero di bits utilizzati dal segnale
results.rawbuf: L'array contenete i segnali ricevuti
results.rawlen: Il numero di elementi inseriti nell'array
irrecv.resume() : Va eseguita dopo il comando di ricezione per resettare il
ricevitore e prepararlo al successivo segnale
irrecv.blink13(true) : Abilita il lampeggio del LED di ricezione (per
vedere l'effetto di questa istruzione basta inserire l'anodo [gambino lungo] di
un led sul pin 13 e il catodo su GND). Questa funzionalità è utilizzata solo per
verificare il corretto trasferimento poiché la luce infrarossa non risulta
visibile.
Trasmissione:
IRsend irsend : Crea un oggetto trasmittente. La libreria
utilizzata utilizza sempre il pin 3 per pilotare il LED IR per cui non è
necessario passarglielo come argomento.
irsend.sendNEC(IRcode, numBits) : Spedisce un segnale in codifica NEC.
irsend.sendSony(IRcode, numBits) : Spedisce un segnale utilizzando la
codifica standard Sony.
irsend.sendRC5(IRcode, numBits) : Spedisce un segnale utilizzando la
codifica RC5.
irsend.sendRC6(IRcode, numBits) : Spedisce un segnale utilizzando
la codifica standard RC6
irsend.sendRaw(rawbuf, rawlen, frequency) : Invia utilizzando la codifica generica RAW. La variable rawbuf è un buffer contenete i singoli dati da
inviare, rawlen la lunghezza del buffer e frequency
la frequenza di invio dei dati (tipicamente 38 => 38 kHz).
Per inviare i segnali la libreria IRRemote utilizza la tecnologia PWM ed un timer che gestisce i segnali utilizzando il pin numero 3. Se volete cambiare pin dovete mettere mano alla libreria e modificarla, cosa che peraltro nelle ultime versioni è decisamente più semplice da farsi, comunque, a meno che non abbiate esigenze particolari, non dovrebbe essere un problema usare il pin 3 anziché altri.
ESEMPIO 1
Passiamo a realizzare il primo sketch di esempio:
Codice Sorgente Ricevitore
#include <IRremote.h> int RECV_PIN = 3; // Pin di ricezione IRrecv irrecv(RECV_PIN); void setup() { Serial.begin(9600); irrecv.enableIRIn(); // Inizializzo il ricevitore } void loop() { decode_results results; if (irrecv.decode(&results)) { // Tipi di codifica: ------------- // results.decode_type == NEC // results.decode_type == SONY // results.decode_type == HEX // results.decode_type == RC5 // results.decode_type == RC6 // ------------------------------- if (results.decode_type == SONY) Serial.print((char)results.value); irrecv.resume(); // Receive the next value } }
Codice Sorgente Trasmettitore
#include <IRremote.h> void setup() { } void loop() { //http://www.pjrc.com/teensy/td_libs_IRremote.html IRsend irsend; // IRCode, Nr. Bit irsend.sendSony((int)'A', 12); delay(40); irsend.sendSony((int)'v', 12); delay(40); irsend.sendSony((int)'e', 12); delay(40); irsend.sendSony((int)'\n', 12); delay(4000); // Aspetto 4 secondi }Il risultato sul monitor seriale è il seguente
ESEMPIO 2
La IRremote ci permette di ottenere dati più precisi sulla decodifica
effettuata utilizzando la proprietà decode_type dell'oggetto ricevitore
di tipo decode_results. In altre parole possiamo avere due codici
identici che però assumono significati diversi a seconda della codifica
utilizzata. In particolare possiamo
interpretare correttamente la codifica dopo aver stabilito la corretta codifica
mediante decode_type. I codici attualmente supportati sono NEC, SONY, RC5,
RC6, DISH, SHARP, PANASONIC, JVC, SANYO, MITSUBISHI ed UNKNOWN.
Passiamo a realizzare il secondo esempio che consente la spedizione tramite IR del testo scritto sul monitor seriale dell'emettitore.
Codice Sorgente Ricevitore
Lo stesso dell'esempio 1
Codice Sorgente Trasmettitore
#include <IRremote.h> boolean MandaInvio=false; void setup() { Serial.begin(9600); } void loop() { IRsend irsend; if (Serial.available()) // se ho caratteri { irsend.sendSony((int)Serial.read(), 12); delay(40); MandaInvio=true; } else if (MandaInvio) { irsend.sendSony((int)'\n', 12); delay(40); MandaInvio=false; } }
Il risultato sul monitor seriale del ricevente (se sul trasmettitore ho scritto: "Questo è un esempio\ndi trasmissione tramite IR\nAve a tutti\n" sarà il seguente
ESEMPIO 3
Passiamo a realizzare il terzo esempio. Prima di passare alla questione software vorrei prima fare
alcune precisazioni. Istintivamente potremmo pensare che per inviare dei dati
binari via infrarossi potrebbe bastare accendere il
LED IR quando voglio rappresentare l'uno e toglierlo per gli zero. Questo però non è fattibile poiché
lampadine, sole etc. utilizzano l'infrarosso al pari del LED IR. Per distinguere perciò un segnale non voluto dalla
nostra comunicazione si usa inviare pacchetti di 0/1 per indicare uno stato
alto, e l’assenza di segnali per quello basso. Questo è il motivo per cui i
sensori IR sono sensibili ad una specifica frequenza e tagliano le frequenze
indesiderate.
Analizziamo quindi il comportamento di un segnale IR. Quando premo uno dei bottoni di un telecomando a infrarossi il dispositivo emette un segnale. Questa trasmissione consiste in un segnale a 40kHz che viene acceso e spento seguendo un particolare schema (pattern). Bottoni differenti determinano sequenze on/off con pattern differenti. Quando il segnale è alto, un segnale IR a 40Khz viene emesso mentre quando è basso non viene trasmesso nulla.
Ad esempio un segnale IR Sony inizia con 2400 microsecondi (10-6) ON e 600 microsecondi OFF: si tratta del primo impulso che definisce lo start della trasmissione. Successivamente l'1 viene identificato con un segnale con 1200 microsecondi a ON e 600 a OFF mentre lo 0 con una trasmissione 600 a ON e 600 a OFF (Questa codifica si chiama SIRC). La differente ampiezza del segnale OFF / ON permette al ricevitore IR di riconoscere i bit trasmessi.
La forma d'onda sottostante rappresenta una trasmissione di 12-bit. La trasmissione è normalmente ripetuta per tutto il periodo di pressione sul bottone per un minimo di 3 volte (nel protocollo Sony). Ogni trasmissione inizia 45 microsecondi dopo la precedente trasmissione. Il protocollo Sony supporta trasmissioni a 15 e 20 bits.
Se il protocollo di decodifica è “UNKNOWN”, ossia sconosciuto, ci sono alcune preziose ulteriori
informazioni che possiamo raccogliere: in particolare rawlen ci fornisce
la lunghezza del buffer mentre l’array rawbuf contiene i dati ricevuti Grazie a questo
array possiamo stamparne il contenuto. E' possibile stabilire la sequenza di bit
di qualsiasi segnale ad infrarosso, calcolando il tempo in cui il segnale è alto
e il tempo in cui il segnale è basso.
Obiettivo del terzo esempio è scrivere
programma che invia un'informazione in RAW e un secondo che decodifica
il segnale ricevuto.
Codice Sorgente Trasmettitore
#include <IRremote.h> // Definisco lo schema di rappresentazione dell'1 e dello 0 #define IR_1_A 700 #define IR_1_B 1600 #define IR_0_A 700 #define IR_0_B 400 // ---------------------------- // A => 65 => 0100 0001 // unsigned int S_Frase[18]={4600,4400, 700,400, 700,1600, 700,400, 700,400, 700,400, 700,400, 700,400, 700,1600 }; // ---------------------------- unsigned int S_Frase[20]={0}; void Codifica(unsigned int c, unsigned int S[18]) { int i, p=2, resti[8]; unsigned int num=c; String Frase="",base2="",Bit="",s=""; // Passo dalla codifica in base 10 a quella in base 2 for(int i=7; i>=0 ; i--) { resti[i]= num % 2; num=num/2; } // Codifica in BIT e somma di potenze di 2 for(int i=0; i<8 ; i++) { Bit=Bit+resti[i]; if (resti[i]==1) { // Serie di potenze di 2 if (base2!="") base2=base2+"+"; base2=base2+"2^"+(7-i); } } // Start Trasmissione S[0]=4600; S[1]=4400; // Decodifico gli 1 e 0 in impulsi IR for(int i=0; i<8 ; i++) { if (resti[i] == 1) { S[p++]=IR_1_A; S[p++]=IR_1_B; s=s+IR_1_A+" "+IR_1_B+" "; } else { S[p++]=IR_0_A; S[p++]=IR_0_B; s=s+IR_0_A+" "+IR_0_B+" "; } } // Descrivo la sequenza inviata Frase="Simbolo inviato: '"+String((char)c)+"' -> "+c; Frase=Frase+" - Decodifica in BIT: "+Bit; Frase=Frase+" - Somma potenze di 2: "+base2+"\n"; Frase=Frase+"Codifica IR inviata: "+s+"\n"; Serial.println(Frase); } void setup() { Serial.begin(9600); } void loop() { IRsend irsend; Codifica('A',S_Frase); // A => 65 => 0100 0001 irsend.sendRaw(S_Frase,20,38); delay(40); Codifica('v',S_Frase); // v => 118 => 0111 0110 irsend.sendRaw(S_Frase,20,38); delay(40); Codifica('e',S_Frase); // e => 101 => 0110 0101 irsend.sendRaw(S_Frase,20,38); delay(40); delay(3000); // Attendo 3 secondi }Il seguente codice produce il seguente output sul monitor seriale:
Codice Sorgente Ricevitore
I valori ricevuti, moltiplicati per USECPERTICK che è impostato nella libreria a 50, permette di ottenere i microsecondi degli zeri e uni che si susseguono nella trasmissione e che in gergo sono chiamati rispettivamente Space e Mark. Il parametro D serve per definire il range di errore accettabile sull'intervallo in microsecondi rilevato in ricezione. Ad esempio se la durata per per la trasmissione del segnale alto è 1600 μs allora qualsiasi durata in ricezione compresa tra [1600-D,1600+D] verrà interpretata come 1600.
#includeIl risultato sul monitor seriale del ricevente sarà il seguente (si notino le differenti codifiche IR ricevute!)// Definisco lo schema di rappresentazione dell'1 e dello 0 #define IR_1_A 700 #define IR_1_B 1600 #define IR_0_A 700 #define IR_0_B 400 #define D 130 // Margine di errore nella lettura int RECV_PIN = 3; // Pin di ricezione IRrecv irrecv(RECV_PIN); void setup() { Serial.begin(9600); irrecv.enableIRIn(); // Inizializzo il ricevitore } unsigned int Decodifica(decode_results results) { unsigned int c=0, r1, r2; int e=7, p2=128; // 2^7 String d="", r="", base2="", Frase=""; r=r+(results.rawbuf[1]*USECPERTICK)+" "; r=r+String(results.rawbuf[2]*USECPERTICK)+" "; // posso anche usare String // Salto i primi 2 (Start of trasmission) for (int i=3; i<(results.rawlen-1) ; i=i+2) { r1=results.rawbuf[i]*USECPERTICK; r2=results.rawbuf[i+1]*USECPERTICK; r=r+r1+" "+r2+" "; if ( (r1<=(IR_1_A+D)) && (r1>=(IR_1_A-D)) && (r2<=(IR_1_B+D)) && (r2>=(IR_1_B-D)) ) { d=d+"1"; if (base2!="") // Serie di potenze di 2 base2=base2+"+"; c=c+p2; base2=base2+"2^"+e; } else if ( (r1<=(IR_0_A+D)) && (r1>=(IR_0_A-D)) && (r2<=(IR_0_B+D)) && (r2>=(IR_0_B-D)) ) d=d+"0"; else d=d+"?"; e--; p2=p2/2; } // Descrivo la sequenza ricevuta Frase="Codifica IR ricevuta: "+r+"\n"; Frase=Frase+"Decodifica in BIT: "+d; Frase=Frase+" - Somma potenze di 2: "+base2+" = "+c; Frase=Frase+" - Ascii: '"+(char)c+"'\n"; Serial.println(Frase); } void loop() { decode_results results; if (irrecv.decode(&results)) // Se ho qualcosa da decodificare ... { Decodifica(results); irrecv.resume(); // Ricevo il prossimo valore delay(40); } }
http://www.logicaprogrammabile.it/motore-passo-passo-bipolare-driver-l298n/