Arduino – Telecomando per Radio FM con TEA5767

 

Oggi vediamo come poter controllare a distanza la radio FM basata sul modulo TEA5767 presentata in un precedente articolo tramite l’utilizzo di un vecchio telecomando TV e il relativo modulo ricevente siglato KY 022. Grazie a ciò, tutte le operazioni che normalmente si effettuano tramite i quattro pulsanti visti nello schema di base, cioè sintonizzazione delle frequenze, memorizzazione delle stazioni radio, commutazione audio, etc, possono essere eseguite a distanza in maniera abbastanza semplice.

Come mostrato nello schema qui sotto, tutto quello che bisogna fare è collegare il modulo ricevente ad infrarossi all’entrata 10 di Arduino, mentre nel codice bisogna stabilire quali sono i tasti che si vogliono usare per eseguire le operazioni richieste.

 

Il modulo ad infrarossi usato, costato poco più di 1 Euro, opera ad una frequenza di 37.9 KHz ed ha soltanto tre terminali : i due dell’alimentazione ( che va da 2.7 a 5.5 V ) e quello per il trasferimento dati contrassegnato con S. La distanza massima che può coprire, stando alle caratteristiche riportate dalla casa costruttrice, si aggira intorno a 18 metri.

 

Nello sketch vediamo come siano state aggiunte le librerie per il funzionamento del modulo ad infrarossi ( in particolare <IRremote.h> ) e della parte dedicata alla codifica dei pulsanti del telecomando che nel mio caso corrisponde a quanto riportato nella tabella sottostante :

 

Tasto telecomandoCodice corrispondente ( Decimale )Funzione
Rosso119Modo radio
Verde118Modo memoria
Vol -81Audio OFF
Vol + 80Audio ON
OK117Memorizza frequenza
P +96 Sintonia manuale in avanti o scorrimento delle stazioni in memoria
P -97Sintonia manuale indietro o scorrimento delle stazioni in memoria

 

 

#include <EEPROMVar.h>
#include <EEPROMex.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#include <TEA5767.h>
#include <boarddefs.h>
#include <IRremote.h>
#include <IRremoteInt.h>
#include <ir_Lego_PF_BitStreamEncoder.h>


#define btn1 8
#define btn2 9
#define btnMemo 13
#define btnSel 3

float frequenza = 0;
float frSint;
int indiceLettura = 2;
int indiceScrittura;
short selezione = 0;
int indic;
unsigned long t;
unsigned long t1 = 0;
short selCorrente;

int pinRicezione = 10;
IRrecv irrecv(pinRicezione);
decode_results results;
unsigned long codice;

TEA5767 radio = TEA5767();
LiquidCrystal lcd(12, 11, 5, 4, 7, 6);

// Caratteri personalizzati per il display

byte scala[] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00100,
  B00100,
  B10101,
  B10101
};
byte cursore[] = {
  B00100,
  B00100,
  B00100,
  B00100,
  B00100,
  B00100,
  B10101,
  B10101
};
byte fm1[] = {
  B00000,
  B00000,
  B00000,
  B00111,
  B00100,
  B00111,
  B00100,
  B00100
};
byte fm2[] = {
  B00000,
  B00000,
  B00000,
  B10001,
  B11011,
  B10101,
  B10001,
  B10001
};
byte audioON[] = {
  B00001,
  B00011,
  B00101,
  B11001,
  B11001,
  B00101,
  B00011,
  B00001
};
byte modoRadio[] = {
  B10000,
  B01000,
  B00100,
  B00010,
  B11111,
  B10001,
  B10001,
  B11111
};
byte modoMemoria[] = {
  B00000,
  B00111,
  B00101,
  B01111,
  B01010,
  B11110,
  B10100,
  B11100
};
byte modoReset[] = {
  B01110,
  B01110,
  B01110,
  B01110,
  B01110,
  B01110,
  B00000,
  B01110
};


// Funzione di riavvio usata dopo il reset della EEprom

void(* Riavvia)(void) = 0;


// Disegno della scala graduata sul display

void scalaGrad()
{
  indic = map(frequenza, 87, 108, 3, 12);

  if (frequenza <= 109 || frequenza >= 87 ) {
    for (int j = 2; j <= 13; j++)
    {
      lcd.setCursor(j, 1);
      lcd.write(3);
    }
    lcd.setCursor(indic, 1);
    lcd.write(4);
  }
}

/*
    Aggiornamento della frequenza dopo
    aver premuto i pulsanti avanti-indietro
*/

void aggiornaFrequenza()
{
  frequenza = constrain(frequenza, 87.5, 108.5);
  lcd.clear();
  lcd.setCursor(1, 0);
  lcd.write(1);
  lcd.setCursor(2, 0);
  lcd.write(2);
  lcd.setCursor(4, 0);
  lcd.print(frequenza);
  lcd.setCursor(11, 0);
  lcd.print("Mhz");
  if (radio.isStereo()) {
    lcd.setCursor(0, 1);
    lcd.print("s");
  } else {
    lcd.setCursor(0, 1);
    lcd.print("m");
  }
  radio.setFrequency(frequenza);
  scalaGrad();
}

/*
    Ricerca manuale delle stazioni tramite i
    pulsanti di aumento e decremento della frequenza

*/
void ricerca()
{
  while (digitalRead(btn1) == LOW || codice == 65 )
  {
    frequenza += 0.1;
    aggiornaFrequenza();
    scalaGrad();
    delay(200);
  }

  while (digitalRead(btn2) == LOW  || codice == 67)
  {
    frequenza -= 0.1;
    aggiornaFrequenza();
    scalaGrad();
    delay(200);
  }
}

/*
    Procedura di memorizzazione di una stazione radio su EEPROM.
    Nelle posizioni 0-1 si memorizza con un valore int il
    numero delle stazioni contenute nella memoria,mentre a partire
    dalla posizione 3 vengono memorizzate le frequenze con un valore
    float. Da notare che si tiene conto della lunghezza delle variabili
    usate, cioè int = 2 byte e float = 4 byte.
*/

void memorizzaSuEeprom()
{
  frSint = radio.getFrequency();
  delay(100);
  indiceScrittura = EEPROM.readInt(0);
  EEPROM.writeFloat(indiceScrittura, radio.getFrequency());
  delay(5);
  lcd.setCursor(0, 1);
  lcd.print("Memoriz. OK !");
  indiceScrittura = indiceScrittura + 4;
  EEPROM.writeInt(0, indiceScrittura);
  delay(1000);
  frequenza = frSint;
  aggiornaFrequenza();
}

/*
    Lettura delle stazioni memorizzate su EEPROM

*/

void leggiEeprom()
{
  if (digitalRead(btn2) == LOW)
  {
    frequenza =  EEPROM.readFloat(indiceLettura);
    delay(5);
    if (frequenza >= 87.5  && frequenza <= 108.5) {
      aggiornaFrequenza();
      indiceLettura = indiceLettura + 4;
    } else {
      indiceLettura = 2;
    }
    scalaGrad();
    delay(300);
  }


  if (digitalRead(btn1) == LOW)
  {
    frequenza =  EEPROM.readFloat(indiceLettura);
    delay(5);
    if (frequenza >= 87.5 && frequenza <= 108.5 && indiceLettura >= 2) {
      aggiornaFrequenza();
      indiceLettura = indiceLettura - 4;
    } else {
      indiceLettura = 2;
    }
    scalaGrad();
    delay(300);
  }
}

/*
    Cancellazione EEPROM e riavvio dell'ATmega 328
    Questa procedura richiede alcuni secondi
*/

void cancellaEprom()
{
  if (digitalRead(btn2) == LOW || digitalRead(btn1) == LOW)
  {
    frSint = radio.getFrequency();
    lcd.setCursor(0, 1);
    lcd.print("Reset in corso..");
    delay(1);
    EEPROM.writeInt(0, 2);
    delay(10);

    for (int i = 2; i < 1024; i++)
    {
      EEPROM.writeInt(i, 0);
      delay(5);
    }
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Reset finito    ");
    lcd.setCursor(0, 1);
    lcd.print("Riavvio in corso..");
    delay(3000);
    Riavvia();

  }
}

void setup()
{
  delay(1000);
  Wire.begin();
  pinMode(btn1, INPUT);
  pinMode(btn2, INPUT);
  pinMode(btnMemo, INPUT);
  pinMode(btnSel, INPUT);
  Serial.begin(9600);
  irrecv.enableIRIn();

  frequenza = 91.1;
  radio.setMuted(false);
  radio.setFrequency(frequenza);

  lcd.createChar(1, fm1);
  lcd.createChar(2, fm2);
  lcd.createChar(3, scala);
  lcd.createChar(4, cursore);
  lcd.createChar(5, audioON);
  lcd.createChar(6, modoRadio);
  lcd.createChar(7, modoMemoria);
  lcd.createChar(8, modoReset);

  lcd.begin(16, 2);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Arduino Radio FM");
  lcd.setCursor(4, 1);
  lcd.print("TEA 5767");
  delay(2000);

  lcd.clear();
  lcd.setCursor(1, 0);
  lcd.write(1);
  lcd.setCursor(2, 0);
  lcd.write(2);
  lcd.setCursor(4, 0);
  lcd.print(frequenza);
  lcd.setCursor(11, 0);
  lcd.print("Mhz");
  if (radio.isStereo()) {
    lcd.setCursor(0, 1);
    lcd.print("s");
  } else {
    lcd.setCursor(0, 1);
    lcd.print("m");
  }
  lcd.setCursor(15, 1);
  lcd.write(6);
  scalaGrad();
}


void loop()
{

  // Indica lo stato ON-OFF dell'uscita audio
  //
  t = millis();
  if (radio.isMuted() == false) {
    lcd.setCursor(15, 0);
    lcd.write(5);
  } else {
    if ( t > t1 + 300) {
      lcd.setCursor(15, 0);
      lcd.print(" ");
    }
    if ( t > t1 + 600 ) {
      lcd.setCursor(15, 0);
      lcd.write(5);
      t1 = millis();
    }
  }


  //------------------------------------------------------------------//
  //----------Sezione comando a distanza con telecomando--------------//
  //------------------------------------------------------------------//

  // Selezione delle funzioni
  //
  if (irrecv.decode(&results))
  {
    codice = results.value;

    Serial.println(codice);

    if (codice == 119) { // tasto rosso = modo Radio
      selezione = 0;

    } else if (codice == 118) { // tasto verde = modo Memoria
      selezione = 1;
    }

    else if (codice == 81) { //  audio- = audio OFF

      selezione = 3;
    }

    else if (codice == 80) { // audio+ = audio ON
      radio.setMuted(false);
      lcd.setCursor(15, 1);
      lcd.print(" ");
      if (selCorrente == 1) {
        selezione = 0;
      } else if (selCorrente == 2) {
        selezione = 1;
      }
    }

    else if (codice == 117) { // tasto OK = memorizzazione su EEPROM
      memorizzaSuEeprom();
    }

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


  // Scansione canali tramite telecomando
  //
  if (codice == 96 && selezione == 0) { // tasto 1
    frequenza += 0.1;
    aggiornaFrequenza();
    scalaGrad();
    delay(150);
    codice = 0;
  }
  if (codice == 97  && selezione == 0) { //  tasto 3
    frequenza -= 0.1;
    aggiornaFrequenza();
    scalaGrad();
    delay(150);
    codice = 0;
  }

  // Scansione canali memorizzati sulla EEPROM
  //

  if (codice == 96 && selezione == 1) {

    frequenza =  EEPROM.readFloat(indiceLettura);
    delay(5);
    if (frequenza >= 87.5  && frequenza <= 108.5) {
      aggiornaFrequenza();
      indiceLettura = indiceLettura + 4;
    } else {
      indiceLettura = 2;
    }
    scalaGrad();
    delay(250);
    codice = 0;

  }

  if (codice == 97  && selezione == 1) {

    frequenza =  EEPROM.readFloat(indiceLettura);
    delay(5);
    if (frequenza >= 87.5 && frequenza <= 108.5 && indiceLettura >= 2) {
      aggiornaFrequenza();
      indiceLettura = indiceLettura - 4;
    } else {
      indiceLettura = 2;
    }
    scalaGrad();
    delay(250);
    codice = 0;
  }


  //------------------------------------------------------------//
  //--------------Sezione comando su scheda---------------------//
  //------------------------------------------------------------//
  /*
      Pulsante per memorizzare la frequenza
      su cui si è sintonizzati
  */
  if (digitalRead(btnMemo) == LOW) {
    memorizzaSuEeprom();
  }

  /*
          Pulsante selezione delle funzioni :
      1 - Scorrimento avanti/indietro delle frequenze
      2 - Lettura delle stazioni memorizzate sulla EEPROM
      3 - Cancellazione EEPROM e riavvio
      4 - Audio OFF
      5 - Audio ON

  */
  if (digitalRead(btnSel) == LOW) {
    selezione++;

    delay(200);
    if (selezione > 4 )
    {
      selezione = 0;
    }
  }


  switch (selezione)
  {
    case 0 :
      selCorrente = 1;
      lcd.setCursor(15, 1);
      lcd.write(6);
      ricerca();
      break;

    case 1:
      selCorrente = 2;
      lcd.setCursor(15, 1);
      lcd.write(7);
      leggiEeprom();
      break;

    case 2:
      lcd.setCursor(15, 1);
      lcd.write(8);
      cancellaEprom();
      break;

    case 3:
      delay(250);
      radio.setMuted(true);
      lcd.setCursor(15, 1);
      lcd.print(" ");


      break;

    case 4:
      delay(250);
      radio.setMuted(false);
      lcd.setCursor(15, 1);
      lcd.print(" ");
      break;
  }

}
















 

Ovviamente nello sketch andranno inseriti i codici corrispondenti dei tasti che si ha intenzione di usare e del tipo di telecomando che si ha a disposizione. Per il resto, e in particolare la sezione dedicata alla ricezione dei segnali, tutto dovrebbe essere abbastanza chiaro.

 

La procedura vista, seppur semplice, obbliga a ricompilare lo sketch ogni volta che per qualche motivo si volessero cambiare i codici o il tipo di telecomando . In un altro articolo dimostro come risolvere tale problema.

 

 

Il sensore KY 022 usato nello schema

 

 

 

 

Qui sotto è possibile scaricare i file del progetto

 

RadioFMArduinoTelecTV.png

ProgrammaRadioFMTEAE5767_con_Telecomando

IRremote-2.2.3