Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2015:si4703-radio

FM rádio s Si4703

Zadání

  • Vytvořte rozhraní pro ovládání modulu FM rádia Si4703 s pomocí vhodného zobrazovacího média
  • Zobrazte informaci o aktuální naladěné stanici pomocí RDS
  • Použijte vývojový kit FRDM-KL25Z

Integrované rádiové moduly

Většina mobilních telefonů a MP3 přehrávačů mají v sobě automaticky radiový přijímač. Není se čemu divit, výrobci je integrovali do velmi malých pouzder a při jejich masové výrobě je cena příznivá. Všechny potřebné funkce mají již v sobě (RDS, potlačení šumu, AGC, automatické vyhledávání stanic, atd.), takže stačí pouze přidat výstupní zesilovač nebo využít digitálních audio výstupů. Nejvíce mě zaujala nabídka Silicon Labs. Nabízí mimo přijímačů i vysílače nebo kombinace obojího. Vysílače umožňují velmi jednoduše spojit MP3 přehrávač nebo mobilní telefon přímo s autorádiem. (pozn.: Česká legislativa něco takového neumožňuje)

Hardware

Vybral jsem si modul FM rádia Si4703. Ten má v sobě zabudovaný i RDS procesor a další funkce. Zapsáním hodnoty do příslušného registru ovládáme VCO (oscilátor řízený napětím), s pomocí kterého obvod naladí frekvenci. Modul již má audiozesilovač, takže stačí jen připojit sluchátka, které slouží zároveň i jako anténa.

s-l300.jpg

Jako zobrazovací médium nám poslouží kompaktní OLED displej s řadičem SSD1306, rozlišením 128×64 pixelů a úhlopříčkou 0.96 palce. Komunikace probíhá pomocí sběrnice i2c.

Budeme ho ovládat pomocí vývojového kitu FRDM-KL25Z.

Software

Vývojové prostředí www.mbed.org umožňuje vyhledat a importovat knihovny, které vytvořili ostatní uživatelé. Takto se podařilo získat knihovny pro FM modul i displej. Následující vytvořený kód má za úkol zobrazit hlavní obrazovku, na které bude zobrazena aktuálně naladěná frekvence, možnost manuálního i automatického ladění, nastavení hlasitosti a dat z RDS.


Velký počet proměnných, které jsou třeba například pro uložení nastavení mně pomohly zpřehlednit struktury

/*
+-----------------------------------------------------+
|                                                     |
|                                                     |
|                FM radio s Si4703                    |
|                                                     |
|                                                     |
+-----------------------------------------------------+
 */
// Autor: Adam Stepanek
// Vytvoreno v ramci projektu MPOA 2016
 
 
// Inkluze knihoven
#include "mbed.h"
#include "SparkFun-Si4703.h"
#include "SSD1306.h"
#include "millis.h"
 
// Definice pro tlacitka
#define LEFT    0x01
#define CENTER  0x02
#define RIGHT   0x03
 
// Definice pro displej
#define MAIN    0x01
#define MENU    0x02
#define ONOFF   0x04
#define VOLUME  0x05
 
// Konstruktory
Serial pc(USBTX, USBRX); // tx, rx
Si4703_Breakout radio(I2C_SDA, I2C_SCL, PTA1, &pc);
 
// Nastaveni I/O
DigitalIn btn_left(PTA5);
DigitalIn btn_center(PTC8);
DigitalIn btn_right(PTC9);
 
// Definice funkci
int button_pressed(void);
void show_frequency(void);
void show_screen(int screen, int position);
 
// Prostor pro ulozeni nastaveni
typedef struct{
    bool rds;
    int volume;
    bool tuning;
}Menu_Setup;
 
Menu_Setup setup;
 
// Prostor pro ulozeni aktualni frekvence
typedef struct{
    int current;
    int high;
    int low;
}Frequency_Info;
 
Frequency_Info frequency;
 
// Nezbytne promenne
char rds[8];                // Zde se uklada vysledek cteni RDS
char volume_char[2];        // Aktualni hlasitost prevedena na text
char channel_char[4];       // Aktualni frekvence prevedena na text
int btn_pressed = false;    // Bylo v minulosti zmacknuto tlacitko?
bool exit_menu = false;     // Navrat z menu
bool exit_submenu = false;  // Navrat z menu druhe urovne
int menu_position = 0;      // Ulozeni aktualni pozice sipky v menu
int submenu_position = 0;   // Ulozeni aktualni pozice sipky v submenu

Hlavní funkce programu

// HLAVNI FUNKCE
int main() {
    init();                         // Inicializace displeje SSD1306
    cls();                          // Smazani obrazovky
    startMillis();                  // Zapnuti pocitani milisekund
    radio.powerOn();                // Zapnuti radia
    setup.volume = 2;
    radio.setVolume(setup.volume);  // Nastaveni vychozi hlasitosti
    frequency.current = 760;        // Naladeni vychozi frekvence
    radio.setChannel(frequency.current);
 
    show_screen(MAIN, 0);           // Zobrazeni hlavni obrazovky
    show_frequency();               // Zobrazeni aktualni frekvence
 
 
   // HLAVNI SMYCKA 
   while(true){        
        if(setup.rds){                  // Cti RDS pokud je tato funkce zapnuta
            radio.readRDS(rds, 1500);   // Cteni RDS s timeoutem 1.5 sekundy
            OLED_ShowStr(50, 5, rds, 1);// Zobrazeni vysledku RDS, pokud byla prijata
        }
 
        switch(button_pressed()){       // Ceka, dokud nebude zmacknuto tlacitko
            case LEFT:                                      // Zmacknuto leve tlacitko
                if(setup.tuning)                            // Je zapnuto manualni ladeni?
                    radio.setChannel(--frequency.current);  // Manualni ladeni
                else
                    frequency.current = radio.seekDown();   // Automaticke ladeni
                if(frequency.current < 760){                // Pokud dosahneme pod minimalni frekvenci,
                    frequency.current = 1080;               // bude naladena nejvyssi
                    radio.setChannel(frequency.current);
                    }                    
                show_frequency();
            break;
 
            case RIGHT:                                     // Zmacknuto prave tlacitko
                if(setup.tuning)                            // Je zapnuto manualni ladeni?
                    radio.setChannel(++frequency.current);  // Manualni ladeni
                else
                    frequency.current = radio.seekUp();     // Automaticke ladeni
                if(frequency.current < 760)                 // Ochrana proti naladeni neplatne frekvence
                    frequency.current = radio.seekUp(); 
                show_frequency();            
            break;
 
 
 
            case CENTER:                                    // Vstup do MENU
                while(!exit_menu){
 
                    show_screen(MENU, menu_position+2);     // Ukaze sipku v menu
 
                    switch(button_pressed()){               // Ceka dokud nebude zmacknuto tlacitko
 
                        case LEFT:                                      // Zmacknuto leve tlacitko,
                            if(menu_position == 0)                      // provede se posunuti sipky
                                menu_position = 3;
                            else
                                menu_position--;
                        break;
 
                        case RIGHT:                                      // Zmacknuto leve tlacitko,
                            if(menu_position == 3)                       // provede se posunuti sipky
                                menu_position = 0;
                            else
                                menu_position++;
                        break;
 
                        case CENTER:                    // Vstup do dalsi urovne MENU
                            exit_submenu = false;
                            switch(menu_position){
                                case 0:                 // SUBMENU Nastaveni Hlasitosti
                                    exit_submenu = false;
                                    while(!exit_submenu){
                                        radio.setVolume(setup.volume);
                                        show_screen(VOLUME, 0);
                                        switch(button_pressed()){   // Pridat volume
                                            case LEFT:
                                                if(setup.volume == 0);
                                                else
                                                    setup.volume--;
                                            break;
                                            case RIGHT:             // Ubrat volume
                                                if(setup.volume == 15);
                                                else
                                                    setup.volume++;
                                            break;
                                            case CENTER:            // Navrat do hlavniho menu
                                                exit_submenu = true;
                                            break;
                                        }
                                    }
 
                                break;
                                case 1:     // SUBMENU Manualni ladeni
                                    exit_submenu = false;
                                    while(!exit_submenu){
                                        cls();
                                        show_screen(ONOFF, setup.tuning+3);
                                        if(button_pressed() == CENTER)
                                            exit_submenu = true;
                                        else
                                            setup.tuning = !setup.tuning;       // Zapnuti nebo vypnuti
                                    }                                           // manualniho ladeni
                                break;
                                case 2:     // SUBMENU Nastaveni RDS
                                    exit_submenu = false;
                                    while(!exit_submenu){
                                        cls();
                                        show_screen(ONOFF, setup.rds+3);
                                        if(button_pressed() == CENTER)
                                            exit_submenu = true;
                                        else
                                            setup.rds = !setup.rds;             // Zapnuti nebo vypnuti RDS
                                    }
                                break;
                                case 3:     // Navrat z menu
                                    show_screen(MAIN, 0);
                                    show_frequency();
                                    exit_menu = true;
                                break;
                            }
 
                        break;
                    }
                }
            break;
        }
        exit_menu = false;
        menu_position = 0;
 
        OLED_ShowStr(0, 5, "Staince:             ", 1);         // Smazani informaci z RDS, pokud dojde k preladeni
        }    
}

Funkce pro zobrazováni na displeji

// FUNKCE
 
// Funkce pro zjisteni, ktere tlacitko bylo stisknuto
int button_pressed(void){   
    btn_pressed = false;
    while(!btn_pressed){
 
        if (btn_left)
            btn_pressed = LEFT;                     // Indikace zmacknuteho leveho tlacitka
 
        if (btn_center)
            btn_pressed = CENTER;                   // Indikace zmacknuteho prostredniho tlacitka
 
        if (btn_right)
            btn_pressed = RIGHT;                    // Indikace zmacknuteho praveho tlacitka
        }
    while(btn_left || btn_center || btn_right);     // Dokud je tlacitko zmacknute, ceka
    wait_ms(200);                                   // Jednoduche odstraneni zakmitu
    return btn_pressed;
}
 
// Funkce pro zobrazeni aktualni frekvence
void show_frequency(void){
                frequency.high = frequency.current / 10;
                frequency.low = frequency.current % 10;
                OLED_ShowStr(38, 2, "     ", 2);
                sprintf(channel_char, "%d.%d",frequency.high, frequency.low);
                OLED_ShowStr(38, 2, channel_char, 2);
}
 
//Funkce pro zobrazeni displeje (menu, hlavni obrazovka...)
void show_screen(int screen, int position){
    switch(screen){
 
        case MAIN:      // Zobrazeni hlavni obrazovky
            cls();
            locate(0, 0);
            OLED_ShowStr(0, 0, "   FM Radio", 2);
            OLED_ShowStr(0, 2, "<         MHz  >", 2);
            OLED_ShowStr(0, 5, "Staince:", 1);
            OLED_ShowStr(0, 7, "       [MENU]        ", 1);
            show_frequency(); 
        break;
 
        case MENU:      // Zobrazeni menu
            cls();
            OLED_ShowStr(0, 0, "    MENU", 2);
            OLED_ShowStr(0, 2, "   Hlasitost", 1);
            OLED_ShowStr(0, 3, "   Manualni ladeni", 1);
            OLED_ShowStr(0, 4, "   RDS", 1);
            OLED_ShowStr(0, 5, "   Zpet", 1);
            OLED_ShowStr(0, 7, "       [VYBRAT]      ", 1);
            OLED_ShowStr(0, position, "->", 1);         // Zobrazeni sipky na spravne pozici
        break;
 
        case ONOFF:     // Zobrazeni submenu volby On/Off
            cls();
            OLED_ShowStr(0, 3, "   Off", 1);
            OLED_ShowStr(0, 4, "   On", 1);
            OLED_ShowStr(0, position, "->", 1);         // Zobrazeni sipky na spravne pozici
            OLED_ShowStr(0, 7, "         [OK]        ", 1);
 
        break;
 
        case VOLUME:    // Volba hlasitosti
            cls();
            sprintf(volume_char, "%d",setup.volume);    // Zobrazeni aktualni hlasitosti
            OLED_ShowStr(60, 3, volume_char, 2);
        break;
    }
}

Zapojení


Ukázka funkčnosti

Závěr

Výsledkem projektu je vytvoření aplikace, které spojuje modul rádia, displeje a tři tlačítka v použitelný radiopřijímač. Kromě automatického ladění je možné frekvenci zadat i ručně, je zde i možnost ovládání hlasitosti. Pomocí dat z RDS se podařilo zobrazit jen název u jedné stanice, a to u EVROPY 2. Lepšího výsledku by šlo dosáhnout pouze s vlastní knihovnou pro ovládání FM modulu. Programování mi zpříjemňoval poslech částečně naprogramovaného rádia.

Kromě tohoto modulu FM přijímače mě zaujal i modul pro vysílání FM, například Si4713. Existují i integrované obvody, které slučují obě funkce (příjem i vysílání). Daly by se použít k bezdrátovému přenosu zvuku například z mp3 přehrávače nebo PC. Nebo k bezdrátovému přenosu dat, protože mají implementovanou funkci RDS. Dále modul ​Si4707 pro příjem zpráv o počasí.

Celý zdrojový kód je uveřejněný na stránkách mbed.org: Projekt MPOA Si4703 .

2015/si4703-radio.txt · Poslední úprava: 2016/01/17 16:07 autor: Adam Štěpánek