Arduino – Radio FM con TEA5767

 

 

In questo articolo vediamo come realizzare con Arduino una semplice radio FM tramite un modulo dedicato che utilizza l’integrato TEA5767 della Philips. Questo modulo, molto popolare e del costo di pochi euro, contiene al suo interno tutto ciò che è necessario per realizzare un completo ricevitore radio ed è dotato di un amplificatore audio ( basato sull’integrato TDA1308 ) in grado di pilotare qualsiasi cuffia stereo o un amplificatore BF esterno. La gestione del modulo radio, e quindi la comunicazione con Arduino o qualsiasi altro microcontrollore, avviene attraverso il BUS I2C, ossia uno standard di comunicazione seriale che si svolge su due fili : uno usato per la trasmissione dati ( SDA = Serial Data Line ) e l’altro per il segnale di clock ( SCL= Serial Clock line ).

In figura si osserva come si presenta il modulo con i quattro terminali di collegamento, due per il BUS I2C e due per l’alimentazione, più i due jack femmina da 3.5 mm, uno per l’antenna e l’altro per le cuffie. Tutte le caratteristiche tecniche le si possono consultare attraverso il relativo datasheet scaricabile a fondo pagina.

TEA5767
Modulo Radio con TEA5767 Philips

Unica pecca di questo modulo, se così può essere chiamata, è l’impossibilità di regolare il volume audio di uscita in modo digitale e la mancanza del supporto RDS/RBSD, ossia l’impossibilità di visualizzare informazioni particolari sulla stazione sintonizzata, come il nome dell’emittente radio, autore e titolo del brano trasmesso, etc.

 

Schema elettrico della radio

Di seguito è riportato lo schema elettrico completo in tutte le sue parti. Esso si compone della scheda Arduino UNO che gestisce il modulo radio TEA 5767, i quattro pulsanti per cambiare e memorizzare le frequenze, il display lcd che visualizza la frequenza sintonizzata e di un amplificatore BF a guadagno regolabile ( basato sull’integrato LM 386 ) che comanda un piccolo altoparlante da 2 Watt.

 

Arduino radio FM

La funzione dei pulsanti invece è la seguente :

Ch+ / Ch- : servono per la sintonia manuale o la selezione delle stazioni memorizzate in memoria

Memorizzazione : serve per memorizzare la stazione sulla quale ci si trova sintonizzati

Mode : serve per selezionare le seguenti funzioni :

Radio : la frequenza di sintonizzazione viene cambiata tramite i pulsanti Ch+ e Ch- con passi di 0.1 Mhz

Memoria : sempre tramite i pulsanti Ch+ e Ch- si selezionano le emittenti radio memorizzate sulla EEPROM

Reset : premendo il pulsante Ch+ o Ch- si cancellano tutte le stazioni radio precedentemente memorizzate

Audio OFF

Audio ON

 

Per default la radio si trova impostata sulla funzione di sintonia manuale e il cambio di frequenza si effettua tramite i pulsanti Ch+ e Ch-,questo viene indicato sul display da un’icona in basso a destra a forma di radio con antenna. Premendo il pulsante memorizz. si va a scrivere sulla EEPROM la frequenza della stazione corrente,avendone conferma tramite un breve messaggio sul display. Per scorrere le frequenze memorizzate,facendo sempre uso dei suddetti pulsanti, bisogna premere il tasto Mode finchè in basso a destra sul display compare un’icona formata da tre piccoli quadrati. Selezionando la funzione Reset sul display compare un’icona a forma di punto esclamativo e premendo successivamente uno dei pulsanti Ch+ o Ch-  si cancella la EEPROM e si riavvia la Radio. Infine, si può attivare o disattivare l’audio in uscita con la relativa icona a forma di altoparlante che rimane rispettivamente fissa o lampeggiante.

 

Lo Sketch

Nello sketch riportato qui in basso si possono notare le librerie necessarie per far funzionare la radio, cioè quella per il modulo TEA5767 ( TEA5767.h ), quella per permettere lo scambio di informazioni attraverso il bus I2C ( Wire.h ), quella per pilotare il display LCD ( LiquidCrystal.h ) ed infine le librerie per gestire la memoria interna di Arduino  ( EEPROMVar.h e EEPROMex.h ).Vediamo poi la definizione dei pulsanti e la loro assegnazione alle entrate 8-9-13-3, le variabili per tener traccia della frequenza sintonizzata ( frequenza e frSint ) e quelle necessarie per leggere e scrivere sulla EEPROM  ( indiceLettura e indiceScrittura ). Particolarmente importante risulta la variabile “radio” attraverso la quale possiamo eseguire tutte le operazioni necessarie per la sintonizzazione e per ottenere alcune informazioni utili, come la modalità di ricezione mono o stereo, l’intensità del segnale ( questa funzione non è usata in questo progetto ), etc.

 

#include <EEPROMVar.h>
#include <EEPROMex.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#include <TEA5767.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;


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)
  {
    frequenza += 0.1;
    aggiornaFrequenza();
    scalaGrad();
    delay(200);
  }

  while (digitalRead(btn2) == LOW)
  {
    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);

  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()
{


  t = millis();

  if (radio.isMuted() == false) {
    lcd.setCursor(15, 0);
    lcd.write(5);
  } else {

    if ( t > t1 + 1000) {
      lcd.setCursor(15, 0);
      lcd.print(" ");
    }
    if ( t > t1 + 2000 ) {
      lcd.setCursor(15, 0);
      lcd.write(5);
      t1 = millis();
    }
  }

  /*
      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 :
      lcd.setCursor(15, 1);
      lcd.write(6);
      ricerca();
      break;

    case 1:
      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;
  }
}
















 

Come detto, per impostazione predefinita il modulo radio si trova sintonizzato sulla frequenza di 91.1 Mhz ( che corrisponde ad una delle stazioni ricevibili nella mia città ) e impostata sulla funzione “Radio”, cioè quando uno dei due pulsanti Ch+ o Ch- passa da livello logico 1 a 0 viene richiamata la routine ricerca() che provvede ad incrementare o decrementare il valore della frequenza del modulo TEA5767. Contemporaneamente vengono eseguite le routine aggiornaFrequenza() e scalaGrad() che servono rispettivamente ad aggiornare sul display la frequenza corrente e a ridisegnare l’indice sulla scala graduata. La routine memorizzaSuEeprom() viene eseguita invece quando si preme il pulsante collegato all’entrata 13la quale avvia la procedura per scrivere sulla memoria attraverso la libreria EEPROMex.h menzionata prima.

Infatti, grazie ad essa è possibile memorizzare diversi tipi di variabili sulla EEPROM dell’ ATmega328 ( che in questo caso è di 1 Kb = 1024 byte ) cosa che invece sarebbe impossibile usando le funzioni standard. Per questo  motivo i primi due byte della memoria ( indirizzi 0 e 1 ) vengono usati per leggere o scrivere il numero delle emittenti attraverso una variabile Int ( che non a caso occupa appunto 2 byte ), dall’indirizzo 3 in poi vengono invece memorizzate le frequenze attraverso una variabile float ( che come risaputo occupa 4 byte ). Il codice non dovrebbe presentare difficoltà di lettura, visti anche i commenti riportati che ne descrivono in maniera abbastanza chiara il funzionamento.

 

 

Arduino radio FM display LCD
Montaggio su breadboard

 

Amplificatore BF basato sull’integrato LM386. Amplifica il segnale in entrata per un massimo di 20 volte con potenza di uscita intorno ad 1 Watt

 

 

Lista Materiale

ComponenteQuantità
Arduino UNO1
Modulo TEA57671
Display LCD 16 x 21
Amplificatore BF LM 3861
Altoparlante 8 Ohm1
Pulsanti N.Ax 4
Resistenza4 x 10 Kohm
1 x 270 Ohm
1 x 10 Kohm Trimmer

 

Qui sotto è possibile scaricare i file del progetto

ProgrammaRadioFMTEAE5767

Schema Elettrico.png

TEA5767

TEA5767-master

EEPROMEx-9.1