Obsługa radia FM - TEA 5767
Posted: 17 May 2016, 20:46 - Tue
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$:
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:
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:
TEA5767Demo.py:
Życzę dobrego odbioru!
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#
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) + ")"
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)"