======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 [[http://developer.mbed.org/platforms/KL25Z/|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 [[http://www.silabs.com/products/audio/Pages/default.aspx|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 [[https://www.sparkfun.com/datasheets/BreakoutBoards/Si4702-03-C19-1.pdf|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. {{http://i.ebayimg.com/images/a/T2eC16d,!)sE9swm,vE2BQWsmQfquw~~/s-l300.jpg}} Jako zobrazovací médium nám poslouží kompaktní OLED displej s řadičem SSD1306, rozlišením 128x64 pixelů a úhlopříčkou 0.96 palce. Komunikace probíhá pomocí sběrnice i2c. Budeme ho ovládat pomocí vývojového kitu [[http://www.nxp.com/products/software-and-tools/hardware-development-tools/freedom-development-boards/freedom-development-platform-for-kinetis-kl14-kl15-kl24-kl25-mcus:FRDM-KL25Z|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í** {{ :2015:si4703-radio:dsc4343.jpg?direct500 |}} ---- **Ukázka funkčnosti** {{ youtube>JFyNm8yF5Js?medium }} =====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 [[https://learn.adafruit.com/adafruit-si4713-fm-radio-transmitter-with-rds-rdbs-support/overview|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 [[http://www.silabs.com/products/audio/fm-am-receiver/Pages/si4707.aspx|​Si4707]] pro příjem zpráv o počasí. Celý zdrojový kód je uveřejněný na stránkách mbed.org: [[https://developer.mbed.org/users/vodavprasku/code/projekt_Si4703/| Projekt MPOA Si4703 ]].