Edoardo Vignali
Comunicare con Arduino tramite IR
Tutorials -
Venerdì 30 Aprile 2010 09:42
Scritto da Edoardo Vignali

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.

tsop

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.

protocollo nec

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


protocollo sony

  • 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

  • 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.


leader pulse

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

logic 1-0 rc6

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.

ricevitore ir

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

trasmettitore Ir

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;
}

}

}

Ecco il video

Articolo liberamente riadattato in italiano, tratto dal Blog inglese di Ken Shirriff's.

CC

 

Gioblu Robotics © 2010 - 2012 · Sitemap · privacy

gioscarab@gmail.com

Gioblu BOTServer è online dal 10 Aprile 2010 - 319.232 Visite - 1.027.175 Pagine visualizzate - 182.309 Visitatori unici - 536 utenti attivi