Obsługa radia FM - TEA 5767

Moderator: bbiernat

Post Reply
User avatar
pancio
Administrator
Posts: 67
Joined: 18 September 2013, 23:02 - Wed
Location: SILESIA

Obsługa radia FM - TEA 5767

Post by pancio »

Dzisiaj zapraszam do zapoznania się z tutorialem, który pozwoli nam używać radia FM sterowanego z wykorzystaniem ulubionej magistrali I2C. Moduł, który wykorzystamy wyposażony jest w układ TEA 5767 oraz w przedwzmacniacz słuchawkowy. Prostota sterowania pozwala zastosować go praktycznie z każdym systemem mikroprocesorowym jak również z naszym Linuxem na Cubietruck-u. Masz układ dostępny jest pod adresem: 0x60. Na potrzeby tego tutoriala wykorzystałem moduł deweloperski z kompletem gniazd, pinów sterujących i antenką teleskopową. Cena na znanym portalu waha się w granicach 4$:
TEA5767 z antenką
TEA5767 z antenką
tea5767.jpg (19.19 KiB) Viewed 29916 times
Układ zasilany jest napięciem 3,3V więc nie wymagana jest żadna konwersja napięć i można bezpośrednio podpiąć układ do naszego CT.
Wykrywanie układu:

Code: Select all

root@ctdev:~/TEA5767# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: 60 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         
root@ctdev:~/TEA5767# 
Czas na uruchomienie... z racji, że w sieci znajdziemy wiele przykładów demonstrujących sterowanie naszego radyjka nie będę silił się na pisanie własnego softu. Na potrzeby tego artykułu posłużę się programem kolegi Milana Krúpa i jego serwisu http://www.astromik.org/malymenu/menu7.htm. (Artykuł: TEA5767 - FM rádio ovládané přes I2C - http://www.astromik.org/raspi/38.htm):

oprogramowanie oryginalnie przygotowane dla RPi bez większych przeróbek może być uruchomione na CB, CT...

scanner.py:

Code: Select all

#!/usr/bin/python
# -*- encoding: utf-8 -*-

import smbus
import time

bus = smbus.SMBus(1)  # novejsi varianta RasPi (512MB)
#bus = smbus.SMBus(0)  # starsi varianta RasPi (256MB)


adc_limit = 6       # minimalni hodnota sily signalu, pri ktere bude frekvence zobrazena
print "Zobrazuji frekvence, ktere maji silu signalu alespon " + str(adc_limit)

freq = 87.5          # prohledavani pasma zacina od 87.5MHz
while (freq <= 108):
  freq= freq + 0.1   # v kazdem pruchodu smyckou while... se frekvence zvetsi o 100kHz
 
  # prevod frekvence na dva bajty (podle kat.listu)
  freq14bit = int(4 * (freq * 1000000 + 225000)/32768)
  freqH = int(freq14bit / 256 )
  freqL = freq14bit & 0xFF

                               # popisy jednotlivych bitu v bajtech - viz. katalogovy list
  bajt0 = 0x60                 # I2C adresa obvodu
  bajt1 = freqH                # 1.bajt (MUTE bit ; frekvence H)
  bajt2 = freqL                # 2.bajt (frekvence L)
  bajt3 = 0b10110000           # 3.bajt (SUD  ;  SSL1,SSL2  ;  HLSI  ;  MS,MR,ML  ;  SWP1)
  bajt4 = 0b00010000           # 4.bajt (SWP2 ; STBY ;  BL ; XTAL ; SMUTE ; HCC ; SNC ; SI)
  bajt5 = 0b00000000           # 5.bajt (PLREFF  ;  DTC  ;  0;0;0;0;0;0)
  blokdat=[ bajt2 , bajt3 , bajt4 , bajt5 ]

  # preladeni na novou frekvenci
  bus.write_i2c_block_data( bajt0 , bajt1 , blokdat )

  time.sleep(0.05)  # mezi jednotlivymi frekvencemi chvili pockej, nez se vyhodnoti sila signalu

  # precteni obsahu obvodu
  bajt1r = bus.read_byte(bajt0)                       # prvni bajt se musi cist samostatne 
  data = bus.read_i2c_block_data( bajt0 , bajt1 )     # nacteni vsech bajtu z obvodu
  data[0] = bajt1r                                    # prvni bajt se nahradi samostatne nactenou hodnotou

  sila = data[3] >> 4       # v nejvyssich 4 bitech ctvrteho baju (data[3]) je pri cteni registru sila signalu
 
  if (sila >= adc_limit):   # porovnani sily signalu na aktualni frekvenci s pozadovanym limitem
    print "f= " + str(freq) + "MHz" , "\tDATA:" + str(data[0:5]) + "\t(Sila signalu: " + str(sila) + ")"

Działanie skanera
Działanie skanera

TEA5767Demo.py:

Code: Select all

#!/usr/bin/python
# -*- encoding: utf-8 -*-

# 
# 

import smbus               
import time                
import sys                 

bus = smbus.SMBus(1)       # bus number


# ================================================
# podprogram pro prime nastaveni pozadovane frekvence
def nastav_f(freq):

  if (freq >= 87.5 and freq <= 108):  # kdyz je frekvence v pripustnych mezich, zapise se do obvodu

    # prepocet frekvence na dva bajty (podle aplikacnich pokynu)
    freq14bit = int(4 * (freq * 1000000 + 225000)/32768)
    freqH = int(freq14bit / 256 )
    freqL = freq14bit & 0xFF

                                 # popisy jednotlivych bitu v bajtech - viz. katalogovy list
    bajt0 = 0x60                 # I2C adresa obvodu
    bajt1 = freqH                # 1.bajt (MUTE bit ; frekvence H)
    bajt2 = freqL                # 2.bajt (frekvence L)
    bajt3 = 0b10110000           # 3.bajt (SUD  ;  SSL1,SSL2  ;  HLSI  ;  MS,MR,ML  ;  SWP1)
    bajt4 = 0b00010000           # 4.bajt (SWP2 ; STBY ;  BL ; XTAL ; SMUTE ; HCC ; SNC ; SI)
    bajt5 = 0b00000000           # 5.bajt (PLREFF  ;  DTC  ;  0;0;0;0;0;0)

    blokdat=[ bajt2 , bajt3 , bajt4 , bajt5 ]
    bus.write_i2c_block_data( bajt0 , bajt1 , blokdat )   # nastaveni nove frekvence do obvodu

    time.sleep(0.1)                 # chvili pockej, nez se vyhodnoti sila signalu

    bajt1r = bus.read_byte(bajt0)   # nacist prvni bajt (musi se cist samostatne)
    data = bus.read_i2c_block_data( bajt0 , bajt1 )     # precteni dat z obvodu pro zjisteni urovne signalu 
    data[0] = bajt1r                # nahradit prvni precteny bajt samostatne nactenou hodnotou

    print "frekvence= " + str(freq) + "MHz" , "\tDATA: " + str(data[0:5]) + "\t(Sila signalu:" + str(data[3]>>4) + ")"

  return(freq)

# ================================================
# podprogram pro vyhledavani nejblizsi stanice od zadane frekvence
def sken(freq , smer):

  if (sys.argv[1] == "-v"):             # kdyz se vypisuji VSECHNY silne frekvence ...
    jen_1_freq = False                  #     nehleda se jen jedna frekvence
    try:
      adc_limit = int(sys.argv[2])      # zjisti parametr minimalni urovne AD prevodniku pro autosken
    except:
      adc_limit=7                       # kdyz chybi, nastavi se automaticky na 7

  elif (sys.argv[1] == "-t"):           # v rezimu hledani pomoci tlacitek
    jen_1_freq = True                   #    se hleda jen jedna frekvence
    try:
      adc_limit = int(sys.argv[2])      # zjisti parametr minimalni urovne AD prevodniku pro autosken
    except:
      adc_limit=7                       # kdyz chybi, nastavi se automaticky na 7

  else:                                 # kdyz je nastaveno vyhledani POUZE PRVNI silne frekvence ...
    jen_1_freq = True                   #    hleda se jen jedna frekvence
    try:
      adc_limit = int(sys.argv[3])      # zjisti parametr minimalni urovne AD prevodniku pro autosken
    except:
      adc_limit=7                       # kdyz chybi, nastavi se automaticky na 7
  
  
  if (adc_limit > 15 or adc_limit < 0): # vyhodnoceni, jestli je zadany limit v mezi 0 az 15
    adc_limit = 7                       # kdyz je mimo, nastavi se automaticky na 7 

  if (sys.argv[1] == "-v"):             # pri funkci automatickeho prohledani celeho pasma vytiskne info
    print "Zobrazuji frekvence, ktere maji silu signalu alespon " + str(adc_limit)


  # hlavni smycka s kontrolou, jestli je frekvence v pripustnych mezich
  while (freq >= 87.5 and freq <= 108):  # kdyz je frekvence mimo povoleny rozsah, smycka se ukonci

    if(smer == True):    # podle smeru skenovani se bud pridava nebo ubira 100kHz
      freq= freq + 0.1
    else:
      freq= freq - 0.1

    # prepocet frekvence na dva bajty (podle aplikacnich pokynu)
    freq14bit = int(4 * (freq * 1000000 + 225000)/32768)
    freqH = int(freq14bit / 256 )
    freqL = freq14bit & 0xFF

    mutebit = 0b00000000         # pri vyhledavani zapnout zvuk (huci/sumi/piska jako normalni radio pri ladeni)
#    mutebit = 0b10000000        # pri vyhledavani vypnout hlasitost

                                 # popisy jednotlivych bitu v bajtech - viz. katalogovy list
    bajt0 = 0x60                 # I2C adresa obvodu
    bajt1 = freqH | mutebit      # 1.bajt (MUTE bit ; frekvence H)
    bajt2 = freqL                # 2.bajt (frekvence L)
    bajt3 = 0b10110000           # 3.bajt (SUD  ;  SSL1,SSL2  ;  HLSI  ;  MS,MR,ML  ;  SWP1)
    bajt4 = 0b00010000           # 4.bajt (SWP2 ; STBY ;  BL ; XTAL ; SMUTE ; HCC ; SNC ; SI)
    bajt5 = 0b00000000           # 5.bajt (PLREFF  ;  DTC  ;  0;0;0;0;0;0)

    blokdat=[ bajt2 , bajt3 , bajt4 , bajt5 ]

    # preladeni na novou frekvenci
    bus.write_i2c_block_data( bajt0 , bajt1 , blokdat )

    time.sleep(0.05)  # mezi jednotlivymi frekvencemi chvili pockej, nez se vyhodnoti sila signalu

    # precteni obsahu vsech registru
    bajt1r = bus.read_byte(bajt0)                       # prvni bajt se musi cist samostatne 
    data = bus.read_i2c_block_data( bajt0 , bajt1 )     # nacteni vsech bajtu z obvodu
    data[0] = bajt1r                                    # prvni bajt se nahradi samostatne nactenou hodnotou


    sila = data[3] >> 4   # v nejvyssich 4 bitech ctvrteho baju (data[3]) je pri cteni registru uroven signalu
 
    if (sila >= adc_limit):   # minimalni sila signalu, ktera bude povazovan za naladenou stanici (0 az 15)
      print "f= " + str(freq) + "MHz" , "\tDATA:" + str(data[0:5]) + "\t(Sila signalu: " + str(sila) + ")"

      if (mutebit == 0b10000000):   # zruseni pripadneho MUTE bitu po nalezeni stanice
        bajt1 = bajt1 & 0b01111111
        bus.write_i2c_block_data( bajt0 , bajt1  , blokdat )
      
      if (jen_1_freq == True):  # kdyz se hleda jen jedna nejblizsi frekvence, tak se po nalezeni ukonci smycka while
        break

  if (freq > 108):                      # kdyz prejede pres horni konec pasma ...
    freq=108                            # ... tak se na ten konec vrati ...
    print "dosazen horni konec pasma"   # a zahlasi, ze je na konci
  if (freq < 87.5):                     # kdyz prejede pod spodni konec pasma ...
    freq=87.5                           # ... tak se na ten konec vrati ...
    print "dosazen spodni konec pasma"  # a zahlasi, ze je na konci
  return (freq)




# ================================================
# podprogram pro vyhledavani stanic pomoci tlacitek
def tlacitka():

  tl_minus = 0
  tl_plus  = 0
 
  print "... vyhledavani ->>->>->>"
  freq = sken(87.5, True)     # pri spusteni podprogramu se vyhleda prvni stanice zdola


  # hlavni smycka na testovani dvou rozpinacich tlacitek
  while ((tl_minus == 0) or (tl_plus == 0)):  # kdyz jsou obe stlacena, nebo kdyz chybi, smycka se ukonci

    tl_minus = GPIO.input(pin_tlm)            # cteni stavu tlacitek na GPIO pinech
    tl_plus  = GPIO.input(pin_tlp)

    if (tl_plus == 1):           # pri stisku PLUS tlacitka se hleda nejblizsi vyssi stanice
      print "... vyhledavani ->>->>->>"
      time.sleep(0.5)
      if (tl_minus == 0):        # kdyz neni stisknuto zaroven i MINUS tlacitko...
        freq = sken(freq, True)  # vyhledej nejblizsi vyssi frekvenci

    if (tl_minus == 1):          # pri stisku MINUS tlacitka se hleda nejblizsi nizsi stanice
      print "... vyhledavani <<-<<-<<-"
      time.sleep(0.5)
      if(tl_plus == 0):          # kdyz neni stisknuto zaroven i PLUS tlacitko...
        freq = sken(freq, False) # vyhledej nejblizsi nizsi frekvenci

    time.sleep(0.1)



# ================================================
# podprogram pro prepinani predvolenych stanic pomoci tlacitek
def prepinac():

  tl_minus = 0
  tl_plus  = 0


  # rucne vytvoreny seznam stanic a jejich frekvenci
  stanice = {}
  stanice[0] = [93.1  , "Radiozurnal"]
  stanice[1] = [94.1  , "Frekvence 1"]
  stanice[2] = [95    , "Blanik"]
  stanice[3] = [97.7  , "Kiss JC"]
  stanice[4] = [101.1 , "Radio Orlik"]
  stanice[5] = [103.2 , "CRo 2 - Praha"]
  stanice[6] = [105.5 , "Evropa 2"]
  stanice[7] = [106.4 , "CRo Ceske Budejovice"]

  #  v promenne "float(stanice[index][0])" je frekvence stanice s prislusnym indexem
  #  v promenne "stanice[index][1]" je jmeno stanice s prislusnym indexem  


  pocet_stanic = len(stanice)

  index = 0                      # Pri spusteni podprogramu nastav frekvenci na nultou stanici
  print stanice[index][1]      
  nastav_f(stanice[index][0])  

  # hlavni smycka na testovani dvou rozpinacich tlacitek
  while ((tl_minus == 0) or (tl_plus == 0)):  # kdyz jsou obe stlacena, nebo kdyz chybi, smycka se ukonci
    tl_minus = GPIO.input(pin_tlm)            # cteni stavu tlacitek na GPIO pinech
    tl_plus  = GPIO.input(pin_tlp)


    if (tl_plus == 1):           # pri stisku PLUS tlacitka se prepne na nasledujici stanici v seznamu
      time.sleep(0.5)
      if (tl_minus == 0):        # kdyz neni stisknuto zaroven i MINUS tlacitko...
        index = index + 1        # ... presune se index na nasledujici stanici
        if (index > (pocet_stanic-1)):  # kdyz je potom index vetsi, nez pocet stanic ...
          index = 0                     #   ... nastavi se index na zacatek seznamu
 
        print stanice[index][1]        
        nastav_f(stanice[index][0])  # nastav frekvenci aktualni stanice


    if (tl_minus == 1):          # pri stisku MINUS tlacitka se prepne na predchozi stanici v seznamu
      time.sleep(0.5)
      if (tl_plus == 0):         # kdyz neni stisknuto zaroven i PLUS tlacitko...
        index = index - 1        # ... presune se index na predchozi stanici
        if (index < 0):          # kdyz index "podleze" pod prvni stanici ...
          index = (pocet_stanic-1)  # ... nastavi se index na posledni stanici v seznamu

        print stanice[index][1]        
        nastav_f(stanice[index][0])  # nastav frekvenci aktualni stanice

    time.sleep(0.1)





# ================================================
# zacatek programu - vyhodnoceni parametru prikazove radky
# ================================================


try:                        # pokud prvni parametr chybi, zobrazi se napoveda
  parametr=sys.argv[1]
except:
  parametr=""


if (parametr=="-n"):        # prime nastaveni konkretni frekvence
  try:
    freq= float(sys.argv[2])
  except:
    freq=0
  nastav_f(freq)


elif (parametr == "-sn"):    # automaticke skenovani "NAHORU" od zadane frekvence
  try:
    freq= float(sys.argv[2])
  except:
    freq=87.5                # kdyz parametr chybi, nebo je chybny, nastavi se dolni hranice pasma
  sken(freq, True)           # sken od zadane frekvence NAHORU



elif (parametr == "-sd"):    # automaticke skenovani "DOLU" od zadane frekvence
  try:
    freq= float(sys.argv[2])
  except:
    freq=108                 # kdyz parametr chybi, nebo je chybny, nastavi se horni hranice pasma
  sken(freq, False ) # sken od zadane frekvence DOLU



elif (parametr == "-v"):     # automaticke vypis vsech silnych frekvenci
  sken(87.5, True )          # sken od zacatku pasma NAHORU



elif (parametr == "-h0"):    # ztlumit hlasitost
  bajt1 = bus.read_byte( 0x60 )
  bajt1 = bajt1 | 0b10000000 
  bus.write_byte(0x60,bajt1)



elif (parametr == "-h1"):    # obnovit hlasitost
  bajt1 = bus.read_byte( 0x60 )
  bajt1 = bajt1 & 0b01111111 
  bus.write_byte(0x60,bajt1)



elif (parametr == "-t"):     # pouziti tlacitek na GPIO k automatickemu hledani nejblizsich stanic
  tlacitka()



elif (parametr == "-p"):     # pouziti tlacitek na GPIO k prepinani predvolenych stanic
  prepinac()



else:                        # pokud prvni parametr nevyhovuje zadne variante, zobrazi se napoveda
  print "pripustne parametry:"
  print "... -n fff.f       prime nastaveni frekvence"
  print "... -sn fff.f LL   nalezeni nejblizsi stanice nad zadanou frekvenci"
  print "... -sd fff.f LL   nalezeni nejblizsi stanice pod zadanou frekvenci"
  print "... -v LL          automaticky vypis vsech silnych frekvenci"
  print "... -h0            uplne ztlumit hlasitost (MUTE)"
  print "... -h1            obnovit hlasitost"
  print "... -t LL          hledani stanic pomoci tlacitek na GPIO portech"
  print "... -p             prepinani preddefinovanych stanic pomoci tlacitek"
  print ""
  print "  fff.f = frekvence v MHz. Pripustne hodnoty jsou mezi 87.5 a 108"
  print "  LL    = minimalni sila signalu (ADC_level), pri ktere je signal"
  print "           pri automatickem vyhledavani povazovany za stanici  (0 az 15)"
  
Życzę dobrego odbioru!

Post Reply