Arduino – Ricevitore programmabile per telecomandi ad infrarossi

 

Il ricevitore descritto in questo articolo permette di poter comandare a distanza e in maniera indipendente un gruppo di utilizzatori o di aggiungere a qualche nostro progetto la capacità di poter essere controllato attraverso un qualsiasi telecomando ad infrarossi. Ogni uscita quindi potrà essere pilotata attraverso una coppia di codici ( uno per l’accensione e l’altro per lo spegnimento ) che andremo a memorizzare sulla EEPROM dell’ Atmega 328. Questa funzionalità si rivela molto comoda perchè se in futuro vorremo cambiare i codici associati alle uscite o cambiare telecomando, non dovremo far altro che impostare il tutto attraverso una semplice procedura senza la necessità di ricompilare lo sketch da far girare su Arduino.

 

Schema elettrico

Guardando lo schema elettrico riportato in basso, vediamo come il tutto si realizza attraverso l’utilizzo di pochi componenti tra i quali il sensore all’infrarosso tipo KY 022 già usato in un altro progetto. Vediamo poi il display sul quale sarà indicato lo stato delle uscite, i tre pulsanti per l’impostazione dei codici e i due led ( U1 e U2 ) che rappresentano le uscite da comandare. Al posto dei led possiamo naturalmente collegare dei relè comandati da transistor come mostrato più avanti. Nello schema ho usato solo due uscite ma ne possiamo usare quante ne vogliamo in base alle nostre necessità e naturalmente al numero di pin disponibili.

 

 

Schema ricevitore ad infrarossi Arduino

 

 

In basso la variante da usare per le uscite in sostituzione dei led


Come si impostano i codici

Facendo riferimento allo schema elettrico appena visto, si vuole fare in modo che premendo un tasto sul telecomando, ad esempio il numero 1, il led sull’uscita U1 si accenda mentre per spegnerlo vogliamo usare il tasto numero 2. Allo stesso modo per accendere il led collegato sull’uscita U2 scegliamo il tasto 3 e per spegnerlo invece il tasto numero 4.  Per memorizzare i codici corrispondenti ai tasti scelti bisogna procedere in questo modo:

 

  • Premere il pulsante btn1 : sul display uscirà la scritta “Setup Codici IR
  • Premere il pulsante btn2 : sul display uscirà la scritta “Uscita1 ON“. A questo punto, direzionando il telecomando verso il sensore, premiamo il tasto 1 e vedremo sul display il codice corrispondente sotto forma di un numero. Per memorizzarlo basta agire sul pulsante btnMemo.
  • Premere di nuovo il pulsante btn2: sul display uscirà ora la scritta “Uscita1 OFF“. Premiamo sul telecomando il tasto numero 2 e poi di nuovo sul pulsante btnMemo.
  • Stessa cosa per l’uscita U2, cioè premere il pulsante btn2 finchè non comparirà la scritta “Uscita2 ON“, premere sul telecomando il pulsante numero 3 e successivamente btnMemo per memorizzarlo. Cliccare nuovamente su btn2 per visualizzare sul display la scritta “Uscita2 OFF“, cliccare sul telecomando il tasto 4 ed infine premere il tasto btnMemo. Cliccando un’ultima volta sul pulsante btn2 sul display uscirà scritto “FINE” e da quel momento in poi potremo usare i tasti scelti per accendere e spegnere i due led U1 e U2.

 

Pulsante telecomandoUscita
1U1 : ON
2U1 : OFF
3U2 : ON
4U2 : OFF

 

 

 

Volendo cambiare i codici o il tipo di telecomando sarà sufficiente eseguire la stessa procedura vista fin qui. Se volessimo invece cambiarne solo alcuni e lasciare inalterati gli altri, basterà cambiare solo i codici che ci interessano tralasciando gli altri premendo ripetutamente il pulsante btn2 fino a visualizzare sul display “FINE”. Si potrebbe fare la stessa cosa premendo il pulsante btn1 così da uscire immediatamente dal setup.

 

Display Ricevitore programmabile raggi infrarossi
Foto della breadbord

 

Lo sketch

Sin da subito vediamo che lo sketch usa la libreria “<IRremote.h>” per il modulo ricevitore ad infrarossi e la “<EEPROMVar.h>” per poter memorizzare i codici nella memoria dell’ATmega 328 di Arduino. Essenzialmente si compone di tre parti principali, ovvero la routine statoUscite() che visualizza sul display lo stato di attivazione delle uscite U1 e U2,  impTelecomando() che serve per associare i tasti del telecomando a ciascuna uscita ed infine la routine ricevi() che decodifica i segnali ad infrarossi. La routine memorizzaCodice() invece è quella che effettua la memorizzazione sulla EEPROM attraverso il passaggio di tre variabili come argomenti, cioè long codiceLed che rappresenta il codice relativo al tasto premuto sul telecomando e che si intende memorizzare, int indiceMemoria che indica in quale posizione di memoria ( da 0 a 1024 ) deve essere memorizzato tale valore ed infine la variabile long x_codiceLed che rappresenta il valore memorizzato di ciascun tasto. Tale accorgimento è stato adottato per far in modo che all’accensione del dispositivo i valori memorizzati in memoria vengano letti una sola volta tutti insieme e resi disponibili attraverso le corrispondenti variabili di programma. Questo serve sia per avere una risposta piè rapida sia per evitare continue letture dirette sulla EEPROM.  Il resto del codice riguarda la gestione dei tre pulsanti funzione e dovrebbe essere abbastanza chiaro.

 

#include <EEPROMVar.h>
#include <EEPROMex.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#include <IRremote.h>

#define btn1 8
#define btn2 9
#define btnMemo 13
#define U2 A2
#define U1 A0

int pinRicezione = 2;

IRrecv irrecv(pinRicezione);
decode_results results;
LiquidCrystal lcd(12, 11, 5, 4, 7, 6);

bool imp = false;
bool stUscite = true;
short set = 0;

// codice proveniente dal sensore
//
unsigned long  str;
//
// codici di accensione e spegnimento dei led registrati sulla EEPROM
//
unsigned long strLed1on, strLed1off, strLed2on, strLed2off;
//
// stato dei led
//
String statoUsc1, statoUsc2;
//

// veriabili usate per leggere dalla EEPROM i codici di accensione e spegnimento
//
unsigned long x_Led1on, x_Led1off, x_Led2on, x_Led2off;

void(* Riavvia)(void) = 0;

void statoUscite()
{

  if (imp == false) {
    switch (digitalRead(U2))
    {
      case HIGH:
        statoUsc1 = "U1:ON         ";
        break;
      case LOW:
        statoUsc1 = "U1:OFF        ";
        break;
    }

    switch (digitalRead(U1))
    {
      case HIGH:
        statoUsc2 = "U2:ON         ";
        break;
      case LOW:
        statoUsc2 = "U2:OFF        ";
        break;
    }
    lcd.setCursor(0, 0);
    lcd.print(statoUsc1);
    lcd.setCursor(0, 1);
    lcd.print(statoUsc2);
  }
}


void impTelecomando() {

  if (digitalRead(btn1) == LOW) {

    imp = not imp;

    delay(300);
    if (imp == true) {
      lcd.setCursor(0, 0);
      lcd.print("Setup Codici IR");
      lcd.setCursor(0, 1);
      lcd.print("                ");
      delay(300);
    } else {
      set = 0;
      imp = false;

      Riavvia();
    }
  }
  if (imp == true && digitalRead(btn2) == LOW)
  {
    set++;
    lcd.setCursor(0, 0);
    lcd.print("                ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    delay(300);
  }


  switch (set)
  {
    case 1:
      lcd.setCursor(0, 0);
      lcd.print("Uscita1 ON     ");
      lcd.setCursor(0, 1);
      lcd.print("cod: ");
      memorizzaCodice(str, 0, x_Led1on);
      break;

    case 2:
      lcd.setCursor(0, 0);
      lcd.print("Uscita1 OFF     ");
      lcd.setCursor(0, 1);
      lcd.print("cod: ");
      memorizzaCodice(str, 5, x_Led1off);
      break;

    case 3:
      lcd.setCursor(0, 0);
      lcd.print("Uscita2 ON     ");
      lcd.setCursor(0, 1);
      lcd.print("cod: ");
      memorizzaCodice(str, 10, x_Led2on);
      break;

    case 4:
      lcd.setCursor(0, 0);
      lcd.print("Uscita2 OFF     ");
      lcd.setCursor(0, 1);
      lcd.print("cod: ");
      memorizzaCodice(str, 15, x_Led2off);
      break;

    case 5:
      lcd.setCursor(0, 0);
      lcd.print("                ");
      lcd.setCursor(0, 1);
      lcd.print("FINE            ");
      delay(1000);
      Riavvia();
      break;
  }

  if (irrecv.decode(&results) && imp == true)
  {
    str = results.value;
    lcd.setCursor(5, 1);
    lcd.print(str);
    irrecv.resume();
    delay(200);

  }

}

void memorizzaCodice(long codiceLed, int indiceMemoria, long x_codiceLed)
{
  if (digitalRead(btnMemo) == LOW) {
    lcd.setCursor(12, 0);
    lcd.print("OK!" );
    codiceLed =  str;
    EEPROM.writeLong(indiceMemoria , codiceLed);
    delay(300);
    lcd.setCursor(12, 0);
    lcd.print("              ");
    x_codiceLed =  EEPROM.readLong(indiceMemoria);
    delay(10);
  }
}

void ricevi()
{
  if (irrecv.decode(&results) && imp == false)
  {

    str = results.value;

    if (str ==  x_Led1on) {

      digitalWrite(U2, HIGH);
    } else if (str ==  x_Led1off) {

      digitalWrite(U2, LOW);
    } else if (str ==  x_Led2on) {

      digitalWrite(U1, HIGH);
    } else if (str ==  x_Led2off) {

      digitalWrite(U1, LOW);
    }

    irrecv.resume();
    delay(100);
  }
}

void setup()
{
  pinMode(btn1, INPUT);
  pinMode(btn2, INPUT);
  pinMode(btnMemo, INPUT);
  pinMode(U2, OUTPUT);
  pinMode(U1, OUTPUT);
  irrecv.enableIRIn();
  lcd.begin(16, 2);
  lcd.clear();
  x_Led1on = EEPROM.readLong(0);
  x_Led1off = EEPROM.readLong(5);
  x_Led2on = EEPROM.readLong(10);
  x_Led2off = EEPROM.readLong(15);
  delay(1000);

}


void loop()
{

  statoUscite();
  impTelecomando();
  ricevi();

}
















 

 

 

I quattro codici delle uscite vengono memorizzati sulla EEPROM attraverso una variabile di tipo Long che occupa 4 byte. Nello specifico essi vengono scritti negli indirizzi 0 – 5  – 10 – 15, distanziati fra di loro di 2 byte, ossia : il codice U1 ON dall’indirizzo 0 all’indirizzo 3, il codice U1 OFF dall’indirizzo 5 all’indirizzo 8, il codice U2 ON dall’indirizzo 10 all’indirizzo 13 ed infine il codice U2 OFF dall’indirizzo 15 all’indirizzo 18. Di questo si deve tener conto se si decide di aumentare il numero delle uscite del dispositivo.

 

 

 

Video dimostrativo del ricevitore

 

 

 

 

KY022
Sensore KY022 usato nel progetto

 

 

 

Qui sotto è possibile scaricare i file relativi al progetto

IRremote-2.2.3

Telecomando_Infrarossi

TelecomandoInfrarossiArduino.png