|
Comunicazioni IR tramite Arduino
Cosa occorre per comunicare con arduino tramite Infrarossi?
Arduino può comunicare tramite infrarossi grazie a led IR e IR receiver. I led IR sono molto comuni e si trovano perlopiù nei telecomandi di televisioni o di apparecchi casalinghi, mentre i ricevitori IR si trovano in televisioni pc con porta a Infrarossi ecc ecc.
La luce generata dai led IR ha una lunghezza d'onda superiore a quella della luce visibile, per questo non è possibile vederla. Per testare se un led Ir funziona dovremo quindi collegarlo ad una batteria con una resistenza per limitarne la corrente, poi prendere un dispositivo dotato di telecamera (es. un cellulare), inquadrare il led e vedremo una lucina altrimenti invisibile a occhio nudo.
Utiliziamo trasmissioni a Infrarossi soprattutto perchè sono pressochè insensibili alla luce visibile, sono insensibili ai disturbi causate dalle onde radio e inoltre trasmettitori e ricevitori hanno un basso costo. Le trasmissioni IR hanno una portante di 38KHz.
I ricevitori più famosi sono i TSOP173X TSOP183X e servono per decodificare i segnali inviati da qualsiasi telecomando.

Protocolli di comunicazione IR
Per le comunicazioni IR sono stati sviluppati diversi tipi di protocolli e la libreria di Ken Shirriff è in grado di gestirne la maggior parte, questi protocolli sono:
- NEC: vengono trasmessi 32bit e i più significativi vengono trasmessi per primi, in foto un esempio del protocollo.

- Sony: vengono trasmessi generalmente 12 o più bit, e i più significativi per primi, in foto un esempio del protocollo

- RC5: vengono trasmessi 12 o più bit e il messaggio inizia sempre con 2 bit che però non vanno considerati per estrapolare l'informazione trasmessa. In figura un esempio del protocollo:

- RC6: vengono trasmessi generalmente 12bit e i più significativi per primi. Il messaggio inizia con un "leader pulse" (in foto) che serve a guadagnarsi l'attenzione del ricevitore. La portante è a 36KHz.

Successivamente viene inviato il segnale, modulato sulla posizione come si capisce bene dalla figura seguente:

Con lo standard sony e RC5/6 il segnale viene inviato 3 volte prima di terminare la trasmissione.
I protocolli sono gestiti dalla libreria e basterà specificare il nome del protocollo che vogliamo utilizzare in trasmissione, quindi non dobbiamo preoccuparci tanto di capire i protocolli, quanto di capire che protocollo utilizzi il dispositivo a cui vogliamo comunicare.
Per installare la libreria di Ken Shirriff basterà scompattarla in libraries nella cartella di Arduino.
- Ricevere Dati
Per ricevere dati sulla porta a infrarossi dovrete contollare il datasheet del vostro integrato. Sicuramente sarà una specie di bussolottino con 3 gambe, per essere sicuri di non sbagliare collegamenti dovrete individuare quindi la Vs e la GND (Alimentazione e Massa) e poi l'OUT ovvero da dove esce il segnale.

int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
Serial.begin(9600);
irrecv.enableIRIn(); // inizializza il ricevitore
}
void loop() {
if (irrecv.decode(&results)) {
Serial.println(results.value, HEX);
irrecv.resume(); // è pronto per ricevere il valore successivo
}
}
Per trasmettere dati co un led IR dovrete seguire questo schema
IRsend irsend;
void setup()
{
Serial.begin(9600);
}
void loop() {
if (Serial.read() != -1) {
for (int i = 0; i < 3; i++) {
irsend.sendSony(0xa90, 12); // Codice per spengere le tv sony
delay(100);
}
}
}
Uno sketch molto interessante è questo, che ho leggermente riadattato avendo un solo led rbg:
Dovrete collegare ai pin di arduino un led rbg, il rosso va al pin 11, il blu al 10 e il verde al 9. Tra arduino e i pin del led mettete delle resistenze da 220ohm. collegate poi l'uscita del tsop al pin 2 e alimentatelo nella maniera corretta.
/* Milliseconds to change from old to new value */
unsigned long changeSpeed = 200;
/* How fast to change when a button is pressed */
#define SatStep 0.05
#define BrightStep 0.01
#define SpeedStep 50
#define RC5pulseLength 889
/* Different programs */
#define NrOfPrograms 2
int program = 1;
/* IR Remote stuff */
int ir_data_pin = 2;
/* The portnumbers of the leds */
#define red_led_Port 11
#define green_led_Port 9
#define blue_led_Port 10
unsigned long lastChangeMoment = 0;
unsigned long moment = 0;
double Hue = 0.0;
double Saturation = 1;
double Brightness = 1;
unsigned long border;
void setup() {
Serial.begin(9600);
pinMode(red_led_Port, OUTPUT);
pinMode(green_led_Port, OUTPUT);
pinMode(blue_led_Port, OUTPUT);
pinMode(ir_data_pin, INPUT);
border = RC5pulseLength * 1.5;
}
// the loop() method runs over and over again,
// as long as the Arduino has power
void loop()
{
int T;
int Address;
int Command;
getRC5Data(ir_data_pin, LOW, &T, &Address, &Command);
if (Command != 0)
{
Serial.print(T, HEX);
Serial.print(" ");
Serial.print(Address, HEX);
Serial.print(" ");
Serial.println(Command, HEX);
if ((Address == 0) && (Command == 0x01))
Saturation = (Saturation SatStep ? Saturation - SatStep : 0);
else if ((Address == 0) && (Command == 2))
Brightness = (Brightness BrightStep ? Brightness - BrightStep : 0);
else if ((Address == 0) && (Command == 3))
changeSpeed = (changeSpeed SpeedStep ? changeSpeed - SpeedStep : SpeedStep);
else if ((Address == 0) && (Command == 7))
{
program += (program 1 ? 1 : 0);
}
else if ((Address == 0) && (Command == 9))
{
Hue = 0.0;
Saturation = 1;
Brightness = 1;
changeSpeed = 200;
}
}
moment = millis();
if (moment - lastChangeMoment > changeSpeed)
{
switch(program)
{
case 1:
SlowHSVProgram();
break;
case 2:
FullyRandom();
break;
}
lastChangeMoment = moment;
}
}
void FullyRandom()
{
lightLeds((double)random(512)/2, (double)random(512)/2, (double)random(512)/2);
}
void SlowHSVProgram()
{
/* get new rgb values */
Hue = Hue + 0.005;
if (Hue >= 1)
{
Hue=0;
}
double r;
double g;
double b;
HSVtoRGB(Hue, Saturation, Brightness, &r, &g, &b);
lightLeds(r, g, b);
}
void lightLeds(double r, double g, double b)
{
analogWrite(red_led_Port, r * 510 / 2);
analogWrite(green_led_Port, g * 510 / 2);
analogWrite(blue_led_Port, b * 510 / 2);
}
/* Shamelessly copied from http://www.tecgraf.puc-rio.br/~mgattass/color/HSVtoRGB.htm */
void HSVtoRGB(double h, double s, double v, double* r, double* g, double* b)
{
if ( s == 0 )
{
*r = v;
*g = v;
*b = v;
}
else
{
double var_h = h * 6;
double var_i = floor( var_h );
double var_1 = v * ( 1 - s );
double var_2 = v * ( 1 - s * ( var_h - var_i ) );
double var_3 = v * ( 1 - s * ( 1 - ( var_h - var_i ) ) );
if ( var_i == 0 ) {
*r = v ;
*g = var_3 ;
*b = var_1;
}
else if ( var_i == 1 ) {
*r = var_2 ;
*g = v ;
*b = var_1;
}
else if ( var_i == 2 ) {
*r = var_1 ;
*g = v ;
*b = var_3;
}
else if ( var_i == 3 ) {
*r = var_1 ;
*g = var_2 ;
*b = v;
}
else if ( var_i == 4 ) {
*r = var_3 ;
*g = var_1 ;
*b = v;
}
else {
*r = v ;
*g = var_1 ;
*b = var_2;
}
}
}
/* Gets the RC5 data in separate variables, that is:
T - an alternating value. Every time you push a button, it changes. This helps recognize auto-repeat
Address - The device (TV, VCR1, etc)
Command - The command
*/
void getRC5Data(int ir_data_pin, int pin_level, int* T, int* Address, int* Command)
{
/* Get the button pressed */
unsigned long key = getRC5Key(ir_data_pin, pin_level);
if (key > 0) /* Did we get a key? */
{
/* First bit is the autorepeat recognizer */
*T = key >> 11;
/* Bits 4-8: what device? */
*Address = (key & 0x7C0) >> 6;
/* Bits 9-14 are command identifier */
*Command = (key & 0x3F);
}
else
{
*T = 0;
*Address = 0;
*Command = 0;
}
}
/* returns the RC5 data */
unsigned long getRC5Key(int ir_data_pin, int pin_level)
{
/* get the startbit */
unsigned long r = pulseIn(ir_data_pin, pin_level, 1000);
unsigned long noPulseStart = micros();
int pulseTrain[40];
int currentPulse = 0;
unsigned long retval = 0;
if (r == 0)
{
return 0;
}
else
{
for (int i =0; i < 20; i++)
{
r = pulseIn(ir_data_pin, LOW, border*2);
if (r==0) {
}
else {
unsigned long now = micros();
if (now - noPulseStart - r < border)
{
pulseTrain[currentPulse++] = 0;
}
else
{
pulseTrain[currentPulse++] = 0;
pulseTrain[currentPulse++] = 0;
}
noPulseStart = now;
if (r < border)
{
pulseTrain[currentPulse++] = 1;
}
else
{
pulseTrain[currentPulse++] = 1;
pulseTrain[currentPulse++] = 1;
}
}
}
for (int i = 2; i < currentPulse; i+=2) {
if (pulseTrain[i] == 0 && pulseTrain[i+1] == 1)
retval = ( retval << 1 ) + 1;
else
retval = ( retval << 1 );
}
return retval;
}
}
}
Articolo liberamente riadattato in italiano, tratto dal Blog inglese di Ken Shirriff's.
![]()