marți, 25 iunie 2013

Radio FM cu TEA5767 si... Arduino

   Modulul de radio FM, echipat cu TEA5767 se gaseste la un pret f. bun pe ebay si poate fi controlat de un microcontroler...
   O prezentare foarte detaliata se gaseste in fisa de catalog (datasheet) si in materialul producatorului, AN10133 - Low voltage FM stereo radio with TEA5767/68
   Sunt cateva articole bune, care trateaza acest modul:
TEA5767 (+ ATmega8) FM radio de pe site-ul http://tomeko.net/
- Making an FM radio-Part 1; the TEA5767 de pe http://ssihla.wordpress.com/ 
Arduino FM receiver with TEA5767 de la electronicsblog.net (unde este detaliat si explicat un cod/sketch)

   Fara a avea modulul radio conectat, am compilat codul de pe site si am gasit erori, in sensul ca s-au schimbat instructiunile din Wire.send in Wire.write... 

asa ca am inlocuit termenii, iar noul sketch ar trebui sa arate asa:
/// Arduino FM receiver with TEA5767 http://www.electronicsblog.net
#include <Wire.h>
#include <LiquidCrystal.h>

unsigned char search_mode=0;

int b=0;
int c=0;

#define Button_next 30
#define Button_prev 31

unsigned char frequencyH=0;
unsigned char frequencyL=0;

unsigned int frequencyB;
double frequency=0;

double freq_available=0; 

LiquidCrystal lcd(12, 11, 5, 4, 3, 2); 

void setup()   { 

  Wire.begin();
  lcd.begin(16, 2);

  /// buttons  

  pinMode(Button_next, INPUT);
  digitalWrite(Button_next, HIGH); //pull up resistor

  pinMode(Button_prev, INPUT);
  digitalWrite(Button_prev, HIGH); //pull up resistor

  frequency=87.5; //starting frequency

  frequencyB=4*(frequency*1000000+225000)/32768; //calculating PLL word

  frequencyH=frequencyB>>8;

  frequencyL=frequencyB&0XFF;

  delay(100);

  Wire.beginTransmission(0x60);   //writing TEA5767

  Wire.write(frequencyH);
  Wire.write(frequencyL);
  Wire.write(0xB0);
  Wire.write(0x10);
  Wire.write(0x00);
  Wire.endTransmission();

  delay(100);

}

void loop()
{

  unsigned char buffer[5];

  lcd.setCursor(0, 0);

  Wire.requestFrom(0x60,5); //reading TEA5767

  if (Wire.available()) 

  {
    for (int i=0; i<5; i++) {

      buffer[i]= Wire.read();
    }

    freq_available=(((buffer[0]&0x3F)<<8)+buffer[1])*32768/4-225000;

    lcd.print("FM ");

    lcd.print((freq_available/1000000));

    frequencyH=((buffer[0]&0x3F));

    frequencyL=buffer[1];

    if (search_mode) {

      if(buffer[0]&0x80) search_mode=0;

    }

    if (search_mode==1) lcd.print(" SCAN");
    else {
      lcd.print("       ");
    }

    lcd.setCursor(0, 1);

    lcd.print("Level: ");
    lcd.print((buffer[3]>>4));
    lcd.print("/16 ");

    if (buffer[2]&0x80) lcd.print("STEREO   ");
    else lcd.print("MONO   ");

  }

  ///// buttons read

  //////////// button_next////////// 
  if (!digitalRead(Button_next)&&!b) {

    frequency=(freq_available/1000000)+0.05;

    frequencyB=4*(frequency*1000000+225000)/32768+1;

    frequencyH=frequencyB>>8;
    frequencyL=frequencyB&0XFF;   

    Wire.beginTransmission(0x60);   

    Wire.write(frequencyH);
    Wire.write(frequencyL);
    Wire.write(0xB0);
    Wire.write(0x1F);
    Wire.write(0x00); 

    Wire.endTransmission(); 

    //////////////////////

    b=100;

  };

  if (!digitalRead(Button_next)&&b==1) {

    ///scannnn UP

    search_mode=1;

    Wire.beginTransmission(0x60);   

    Wire.write(frequencyH+0x40);
    Wire.write(frequencyL);
    Wire.write(0xD0);
    Wire.write(0x1F);
    Wire.write(0x00); 

    Wire.endTransmission();

    /////////////////

    b=100;

  };    

  if (!b==0) b--;

  //////////// button_prev////////// 
  if (!digitalRead(Button_prev)&&!c) {

    frequency=(freq_available/1000000)-0.05;

    frequencyB=4*(frequency*1000000+225000)/32768+1;

    frequencyH=frequencyB>>8;
    frequencyL=frequencyB&0XFF;

    Wire.beginTransmission(0x60);   

    Wire.write(frequencyH);
    Wire.write(frequencyL);
    Wire.write(0xB0);
    Wire.write(0x1F);
    Wire.write(0x00); 

    Wire.endTransmission(); 

    c=100;

  };

  if (!digitalRead(Button_prev)&&c==1) {

    ///scannnn DOWN

    search_mode=1;

    Wire.beginTransmission(0x60);   

    Wire.write(frequencyH+0x40);
    Wire.write(frequencyL); 

    Wire.write(0x50);
    Wire.write(0x1F);
    Wire.write(0x00);
    Wire.endTransmission();   

    c=100;

  };          

  if (!c==0) c--;

  ////////////////////

}

   PS: in articol este folosit un Arduino Mega, asa ca pinii de inainte si inapoi trebuie redefiniti...

   Am realizat si eu o varianta de montaj, cu o mufa pentru jack stereo:
27.06.2013
   Primul pas, dupa conectare la o placa Arduino, a fost sa vad ce adresa de comunicare are pe i2c si aceasta este, ca in documentatia Philips/NXP, 0x60:
   Am folosit metoda descrisa in articolul Interfata i2c la LCD pentru Arduino (i2c scanner).
   Am conectat si afisajul cu cristale lichide pe 16 coloane a 2 randuri cu interfata i2c si am regasit adresa 0x20:

   Dupa mici modificari ale sketch-ului dinainte pentru Arduino Uno in loc de Arduino Mega si folosirea unui afisaj LCD16x2 cu interfata i2c in locul celei clasice (paralele) am obtinut:


// Arduino FM receiver with TEA5767 http://www.electronicsblog.net
// using LCD16x2 with i2c interface, http://nicuflorica.blogspot.ro
// adapted skech by niq_ro 
// version 1.1

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x20,16,2); // adress is 0x20 for LCD16x2
unsigned char search_mode=0;

int b=0;
int c=0;

#define Button_next 11
#define Button_prev 12

unsigned char frequencyH=0;
unsigned char frequencyL=0;

unsigned int frequencyB;
double frequency=0;

double freq_available=0; 



void setup()   { 

  Wire.begin();
  lcd.init(); 
  lcd.backlight(); //backlight is now ON
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
   
  /// buttons  

  pinMode(Button_next, INPUT);
  digitalWrite(Button_next, HIGH); //pull up resistor

  pinMode(Button_prev, INPUT);
  digitalWrite(Button_prev, HIGH); //pull up resistor

  frequency=104.5; //starting frequency

  frequencyB=4*(frequency*1000000+225000)/32768; //calculating PLL word

  frequencyH=frequencyB>>8;

  frequencyL=frequencyB&0XFF;

  delay(100);

  Wire.beginTransmission(0x60);   //writing TEA5767

  Wire.write(frequencyH);
  Wire.write(frequencyL);
  Wire.write(0xB0);
  Wire.write(0x10);
  Wire.write(0x00);
  Wire.endTransmission();

  delay(100);

}

void loop()
{

  unsigned char buffer[5];

  lcd.setCursor(0, 0);

  Wire.requestFrom(0x60,5); //reading TEA5767

  if (Wire.available()) 

  {
    for (int i=0; i<5; i++) {

      buffer[i]= Wire.read();
    }

    freq_available=(((buffer[0]&0x3F)<<8)+buffer[1])*32768/4-225000;

    lcd.print("FM ");

    lcd.print((freq_available/1000000));

    frequencyH=((buffer[0]&0x3F));

    frequencyL=buffer[1];

    if (search_mode) {

      if(buffer[0]&0x80) search_mode=0;

    }

    if (search_mode==1) lcd.print(" SCAN");
    else {
      lcd.print("       ");
    }

    lcd.setCursor(0, 1);

    lcd.print("Level: ");
    lcd.print((buffer[3]>>4));
    lcd.print("/16 ");

    if (buffer[2]&0x80) lcd.print("STEREO   ");
    else lcd.print("MONO   ");

  }

  ///// buttons read

  //////////// button_next////////// 
  if (!digitalRead(Button_next)&&!b) {

    frequency=(freq_available/1000000)+0.05;

    frequencyB=4*(frequency*1000000+225000)/32768+1;

    frequencyH=frequencyB>>8;
    frequencyL=frequencyB&0XFF;   

    Wire.beginTransmission(0x60);   

    Wire.write(frequencyH);
    Wire.write(frequencyL);
    Wire.write(0xB0);
    Wire.write(0x1F);
    Wire.write(0x00); 

    Wire.endTransmission(); 

    //////////////////////

    b=5;
    delay(10);

  };

  if (!digitalRead(Button_next)&&b==1) {

    ///scannnn UP

    search_mode=1;

    Wire.beginTransmission(0x60);   

    Wire.write(frequencyH+0x40);
    Wire.write(frequencyL);
    Wire.write(0xD0);
    Wire.write(0x1F);
    Wire.write(0x00); 

    Wire.endTransmission();

    /////////////////

    b=50;

  };    

  if (!b==0) b--;

  //////////// button_prev////////// 
  if (!digitalRead(Button_prev)&&!c) {

    frequency=(freq_available/1000000)-0.05;

    frequencyB=4*(frequency*1000000+225000)/32768+1;

    frequencyH=frequencyB>>8;
    frequencyL=frequencyB&0XFF;

    Wire.beginTransmission(0x60);   

    Wire.write(frequencyH);
    Wire.write(frequencyL);
    Wire.write(0xB0);
    Wire.write(0x1F);
    Wire.write(0x00); 

    Wire.endTransmission(); 

    c=5;
    delay(10);

  };

  if (!digitalRead(Button_prev)&&c==1) {

    ///scannnn DOWN

    search_mode=1;

    Wire.beginTransmission(0x60);   

    Wire.write(frequencyH+0x40);
    Wire.write(frequencyL); 

    Wire.write(0x50);
    Wire.write(0x1F);
    Wire.write(0x00);
    Wire.endTransmission();   

    c=10;

  };          

  if (!c==0) c--;

  ////////////////////

}

   Deoarece nu am fost multumit de modul de scanare (nu reactioneaza cum trebuie la apasarea tastelor), am cautat pe net si am descoperit chiar o librarie TEA5767 cu exemplu, care mai necesita o librarie Button.
   Am modificat un pic exemplul pentru afisajul meu cu interfata i2c si am obtinut:
   Mai e "de lucrat" la exemplu asta deoarece nu are decat scanare inainte si inapoi, fara a opri sunetul in perioada cautarii (activare functie MUTE), dar ca exemplu de urmat e ok:
#include <TEA5767.h>
#include <Wire.h>
#include <Button.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x20,16,2); // adress is 0x20 for LCD16x2
// adapted sketch by niq_ro from http://nicuflorica.blogspot.ro
// version 2.0

TEA5767 Radio;
double old_frequency;
double frequency;
int search_mode = 0;
int search_direction;
unsigned long last_pressed;

Button btn_forward(11, PULLUP);
Button btn_backward(12, PULLUP);

void setup() {  
  Wire.begin();
  Radio.init();
  Radio.set_frequency(104.5); 
  Serial.begin(9600);
  lcd.init();
  lcd.backlight(); //backlight is now ON
  lcd.begin(16,2);
  lcd.clear();
}

void loop() {

  unsigned char buf[5];
  int stereo;
  int signal_level;
  double current_freq;
  unsigned long current_millis = millis();
  
  if (Radio.read_status(buf) == 1) {
    current_freq =  floor (Radio.frequency_available (buf) / 100000 + .5) / 10;
    stereo = Radio.stereo(buf);
    signal_level = Radio.signal_level(buf);
    lcd.setCursor(0,0);
    lcd.print("FM: "); lcd.print(current_freq);
    lcd.print("MHz ");
    lcd.setCursor(0,1);
    if (stereo) lcd.print("STEREO "); else lcd.print("MONO ");
    lcd.print(signal_level);
    lcd.print("/15 ");
  }
  
  if (search_mode == 1) {
      if (Radio.process_search (buf, search_direction) == 1) {
          search_mode = 0;
      }
  }
  
  if (btn_forward.isPressed()) {
    last_pressed = current_millis;
    search_mode = 1;
    search_direction = TEA5767_SEARCH_DIR_UP;
    Radio.search_up(buf);
    delay(500);
  }
  
  if (btn_backward.isPressed()) {
    last_pressed = current_millis;
    search_mode = 1;
    search_direction = TEA5767_SEARCH_DIR_DOWN;
    Radio.search_down(buf);
    delay(500);
  } 
   delay(100);
}

   Am facut si un filmulet, numit FM radio FM with TEA5767 and Arduino:
   Am conectat si afisajul de tip Nokia 5110:


   Sketch-ul fiind:
/*********************************************************************
This is an example sketch for our Monochrome Nokia 5110 LCD Displays
  Pick one up today in the adafruit shop!
These displays use SPI to communicate, 4 or 5 pins are required to
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada  for Adafruit Industries.
BSD license, check license.txt for more information
All text above, and the splash screen must be included in any redistribution
*********************************************************************/

// Nokia 5110 LCD (PCD8544) from https://code.google.com/p/pcd8544/
/* niq_ro ( http://nicuflorica.blogspot.ro ) case for Nokia 5110 LCD (PCD8544) - LPH 7366:
 For module from China, you must connect like this:
* Pin 1 (RST) -> Arduino digital 6 (D6)
* Pin 2 (CE) -> Arduino digital 7 (D7)
* Pin 3 (DC) -> Arduino digital 5 (D5)
* Pin 4 (DIN) -> Arduino digital 4 (D4)
* Pin 5 (CLK) - Arduino digital 3 (D3)
* Pin 7 (LIGHT) -> +5V thru 56-100 ohms resistor (for permanent lights) or... other pin control
* Pin 8 (GND) -> GND1 or GND2 
*/

// adapted sketch by niq_ro from http://nicuflorica.blogspot.ro
// version 3.0

#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
// Adafruit_PCD8544 display = Adafruit_PCD8544(SCLK, DIN, DC, CS, RST);
Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 7, 6);

#include <TEA5767.h>
#include <Wire.h>
#include <Button.h>

// TEA5767 begin

TEA5767 Radio;
double old_frequency;
double frequency;
int search_mode = 0;
int search_direction;
unsigned long last_pressed;

Button btn_forward(11, PULLUP);
Button btn_backward(12, PULLUP);

// TEA5767 end


void setup () {

  Wire.begin();
  Radio.init();
  Radio.set_frequency(104.5); 
  Serial.begin(9600);

  display.begin();
  // init done

  // you can change the contrast around to adapt the display
  // for the best viewing!
  display.setContrast(100);
  display.clearDisplay();


  // Print a logo message to the LCD.
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.setCursor(0,0);
  display.println("tehnic.go.ro");
  display.setCursor(24, 8);
  display.print("& niq_ro");
  display.setCursor(1, 24);
  display.print("radio FM");  
  display.setCursor(0, 32);
  display.print("cu TEA5767");
  display.setCursor(0, 40);
  display.print("versiunea ");
  display.setTextColor(WHITE, BLACK);
  display.print("3.0");
  display.display();
  delay (5000);
  display.clearDisplay(); 

}

void loop () {

  unsigned char buf[5];
  int stereo;
  int signal_level;
  double current_freq;
  unsigned long current_millis = millis();
  
  if (Radio.read_status(buf) == 1) {
    current_freq =  floor (Radio.frequency_available (buf) / 100000 + .5) / 10;
    stereo = Radio.stereo(buf);
    signal_level = Radio.signal_level(buf);

   display.setTextSize(2);
   display.setTextColor(BLACK);
   display.setCursor(0,0);
   display.print(display.print(current_freq));
   display.setCursor(47,15);
   display.print("MHz");
   display.setCursor(0,20);
   display.setTextSize(1);
   display.setTextColor(BLACK);
   
   if (stereo) display.print("STEREO"); else display.print("MONO");
   // display level of FM signal..
   display.setCursor(0,35);
   display.setTextSize(1);
   display.setTextColor(WHITE, BLACK);
   display.print(signal_level);
   display.print("/15 ");
   
   display.display();
   delay (500);
display.clearDisplay(); 

// draw a signal level triangle...
   display.drawLine(80, 30, 80, 45, BLACK);
   display.drawLine(80, 45, 50, 45, BLACK);
   display.drawLine(50, 45, 80, 30, BLACK);

int sl = signal_level;
   for (int x = 0; x < sl; x++)
   { 
   display.drawLine(50+2*x, 45, 50+2*x, 45-x, BLACK);
   }


  }
  
  if (search_mode == 1) {
      if (Radio.process_search (buf, search_direction) == 1) {
          search_mode = 0;
      }
  }
  
  if (btn_forward.isPressed()) {
    last_pressed = current_millis;
    search_mode = 1;
    search_direction = TEA5767_SEARCH_DIR_UP;
    Radio.search_up(buf);
    delay(1000);
  }
    
  if (btn_backward.isPressed()) {
    last_pressed = current_millis;
    search_mode = 1;
    search_direction = TEA5767_SEARCH_DIR_DOWN;
    Radio.search_down(buf);
    delay(1000);
  } 
   delay(100);
}

   Filmul cu acest afisaj se numeste FM radio with TEA5767 and Arduino (II):

13 comentarii:

  1. partea cu rds cand apare

    RăspundețiȘtergere
  2. Cara voce é muito bom neste negocio de arduino. Um Abraço!!!

    RăspundețiȘtergere
  3. I'm so glad that I wrote was helpful for you

    RăspundețiȘtergere
  4. Salut!

    Foarte bine organizate articolele tale.
    Eu lucrez la un CarPC(http://www.engineering-diy.blogspot.ro/2013/08/car-pc-projectaugust-2013-update.html).
    In ultima vreme am adaugat suport pt radioFM cu un modul SI4703 de pe eBay, care s-a dovedit a fi foarte slab la receptie in masina. Pot prinde doar in orasele mari bine. Am gasit recent modulul TEA5757 si as avea cateva intrebari despre el:
    Prinde la fel de bine ca un radio analogic/digital?
    Ai incercat sa il folosesti in masina?
    Pinii de ROUT, LOUT pot fi conectati direct la un amplificator(eu folosesc intrarea de AUX de la cd-player-ul masinii)?

    Multumesc si succes cu proiectele!
    Andrei

    RăspundețiȘtergere
    Răspunsuri
    1. Salut,

      Stiu proiectul tau, felicitari...
      LEgat de TEA5767: nu l-am folosit decat in casa, cu o sarmulita pe post de antena, dar a prins tto ce era prin zonasi la semnal bun, e folosit la multe tefeoane, ca idee... posibil sa ai nevoie de un un preamplificator cu factor mic x5..x10 pentru semnalul de intrare in AUX, in 'boxele de calculator" nu au fost probleme...

      Ștergere
    2. Multumesc mult!
      Mi-l comand acum si eu.O sa testez sa vad cum merge in masina.

      Numai bine!

      Ștergere
  5. Buna ziua!
    Poate fi folosit mai simplut, adica fara microcontroller?

    RăspundețiȘtergere
  6. Buna ziua,
    Am facut si eu radioul prezentat mai sus cu arduino tea5767 si afisajul de nokia 511o, dar exista o mica problema ca nu retine postul frecventa la oprirea alimentarii. Se poate face cumva ca la schema initaiala de la care a porint toul cu potentiometru de 10k sa fie pusa si parte a de afisare cu afisorul de nokia 5110?

    RăspundețiȘtergere
    Răspunsuri
    1. am facut pentru afisaj alfanumeric 1602 cu interfata i2c... https://github.com/tehniq3/TEA5767---FM-radio/blob/master/TEA5767_eeprom_i2c_lcd1602_1m1a.ino

      Ștergere
  7. Buna ziua ma puteti ajuta putin cu codul acesta:

    #include
    #include
    #include
    Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 7, 6);
    #include
    #include


    unsigned char frequencyH = 0;
    unsigned char frequencyL = 0;

    unsigned int frequencyB;
    double frequency = 0;

    void setup()
    {
    Wire.begin();
    display.begin();
    frequency = 99.2; //starting frequency
    setFrequency();
    Serial.begin(9600);

    display.setContrast(80);
    display.clearDisplay();

    display.setTextSize(1);
    display.setTextColor(BLACK);
    display.setCursor(0,0);
    display.println("Marian");
    display.setCursor(24, 8);
    display.print("2015");
    display.setCursor(1, 24);
    display.print("radio FM");
    display.setCursor(0, 32);
    display.print("cu TEA5767");
    display.setCursor(0, 40);
    display.print("versiunea ");
    display.setTextColor(WHITE, BLACK);
    display.print("1.0");
    display.display();
    delay (5000);
    display.clearDisplay();

    }

    void loop()
    {
    int reading = analogRead(0);

    frequency = ((double)reading * (108.0 - 87.5)) / 1024.0 + 87.5;
    frequency = ((int)(frequency * 10)) / 10.0;
    setFrequency();
    Serial.println(frequency);

    display.setTextSize(2);
    display.setTextColor(BLACK);
    display.setCursor(0,0);
    display.print(display.print(frequency));
    display.setCursor(47,15);
    display.print("MHz");
    display.setCursor(0,20);
    display.setTextSize(1);
    display.setTextColor(BLACK);

    display.display();
    delay (500);
    display.clearDisplay();

    // draw a signal level triangle...
    display.drawLine(80, 30, 80, 45, BLACK);
    display.drawLine(80, 45, 50, 45, BLACK);
    display.drawLine(50, 45, 80, 30, BLACK);


    }

    void setFrequency()
    {
    frequencyB = 4 * (frequency * 1000000 + 225000) / 32768;
    frequencyH = frequencyB >> 8;
    frequencyL = frequencyB & 0XFF;
    delay(100);
    Wire.beginTransmission(0x60);
    Wire.write(frequencyH);
    Wire.write(frequencyL);
    Wire.write(0xB0);
    Wire.write(0x10);
    Wire.write((byte)0x00);
    Wire.endTransmission();
    delay(100);
    }

    Vreau sa imi arate si cat semnal am si nu am reusit sa il fac sa imi arate, eventual sa elimin ultimele 2 zecimale dupa virgula.

    RăspundețiȘtergere
  8. e un experiment destul de vechi si trebuie sa refac montajul, sa vad ce comenzi sunt, dar nu am timp acum..
    radio asta are mai continuari... poate gasesti in ele ce vrei..
    daca ai introduce si liniile astea:
    if (stereo) display.print("STEREO"); else display.print("MONO");
    // display level of FM signal..
    display.setCursor(0,35);
    display.setTextSize(1);
    display.setTextColor(WHITE, BLACK);
    display.print(signal_level);
    display.print("/15 ");
    poate ai avea noroc... poate....

    RăspundețiȘtergere
  9. I post enough info (schematic and sketches). I don't click on every link from everibody.. sorry

    RăspundețiȘtergere