/* * Source : FMRadio10.c * Date : 2011/04/24 * Update : 2011/05/08 * Auther : Pharaoh */ #include // FM-TEA5767インターフェース #define TEA_BUSMODE LATBbits.LATB7 #define TEA_RW LATBbits.LATB6 #define TEA_CLK LATBbits.LATB8 #define TEA_DATA LATBbits.LATB9 #define STEREO_LED LATBbits.LATB12 // ステレオLED オン・オフ設定 #define OUTPUT_STATUS PORTBbits.RB13 // 出力先取得 1=jack 0=speaker #define WAIT_CHATTERING 100000L // FRCのとき //#define WAIT_CHATTERING 100L // LPRCのとき // ↑試行錯誤で決めた _CONFIG1(JTAGEN_OFF & GCP_OFF & GWRP_OFF & BKBUG_OFF & COE_OFF & ICS_PGx1 & FWDTEN_OFF) // FNOSC_FRC : Fast RC Oscillator (8MHz) // FNOSC_LPRC : Low Power RC Oscillator (31KHz) // FCKSM_CSDCMD : Clock switching and clock monitor : disabled // OSCIOFNC_OFF : // IOL1WAY_OFF : // I2C1SEL_PRI : Use Primary I2C1 pins (PIN 17 & 18) // POSCMOD_NONE : Primary Oscillator disabled // ↓FRC _CONFIG2(IESO_OFF & FNOSC_FRC & FCKSM_CSDCMD & OSCIOFNC_OFF & IOL1WAY_OFF & I2C1SEL_PRI & POSCMOD_NONE) // ↓LPRC //_CONFIG2(IESO_OFF & FNOSC_LPRC & FCKSM_CSDCMD & OSCIOFNC_OFF & IOL1WAY_OFF & I2C1SEL_PRI & POSCMOD_NONE) void SendDataTo3Wire(unsigned char data); void SelectStation(unsigned int freq, int stereo, int mute_right, int mute_left, int hcc); void Wait(unsigned long t); int Sta[] = {778, 800, 807, 825, 836}; // ZIP-FM, FM岐阜, FM愛知, NHK名古屋, NHK岐阜 int Hcc[] = {0, 1, 0, 0, 1}; // 局ごとにHCC適用を指定 int NumSta = (sizeof(Sta) / sizeof(Sta[0])); // 局数 int ChangeSta; // 局選択変更イベント int ChangeStereo; // ステレオ・モノラル変更イベント int IntrFlag; // 割り込み発生 int main(void) { int cursta; // 現在選択中の局 (0 ... NumSta-1) int stereo; // 1=stereo, 0=mono int output_status; // 1=speaker, 0=jack int right_mute; // 1=right channel mute on, 0=off int hcc; // 1=HCC on, 0=off // I Oの初期設定 AD1PCFG = 0xFFFF; // すべてデジタル CLKDIV = 0; // TRISA = 0xFFFF; // RA0-4=すべて入力 TRISB = 0xE003; // RB2,3,4,5,6,7,8,910,11,12=出力(使うのは8,9,12) CNPU1 = 0x3830; // CN4,5,11,12,13=Pull Up CNPU2 = 0; // CN16〜=Pull Upなし CNEN1 = 0x3800; // CN11,12,13=割り込み許可 IPC4bits.CNIP = 5; IEC1bits.CNIE = 1; TEA_BUSMODE = 1; // Bus Mode = 1 : TEA_RW = 0; TEA_CLK = 0; TEA_DATA = 0; // 初期状態 cursta = 3; // 焼き付けでNHK名古屋 stereo = 0; // Mono STEREO_LED = stereo; output_status = OUTPUT_STATUS; right_mute = (output_status==0 ? 1 : 0); hcc = 0; SelectStation(Sta[cursta], stereo, right_mute, 0, Hcc[cursta]); Sleep(); while (1){ if (ChangeSta == 1){ if (cursta < (NumSta-1)) cursta++; else cursta = 0; SelectStation(Sta[cursta], stereo, right_mute, 0, Hcc[cursta]); Wait(WAIT_CHATTERING); // チャッタリングをやり過ごす ChangeSta = 0; IntrFlag = 0; Sleep(); } if (ChangeStereo == 1){ if (output_status == 1){ /* ジャック出力のときだけ変更可能 */ if (stereo == 1) stereo = 0; else stereo = 1; STEREO_LED = stereo; // HCCの効果確認テスト /** if (hcc == 1) hcc = 0; else hcc = 1; STEREO_LED = hcc; SelectStation(Sta[cursta], stereo, right_mute, 0, hcc); **/ SelectStation(Sta[cursta], stereo, right_mute, 0, Hcc[cursta]); } Wait(WAIT_CHATTERING); ChangeStereo = 0; IntrFlag = 0; Sleep(); } if (IntrFlag == 1 && ChangeSta == 0 && ChangeStereo == 0){ int os; unsigned long n; for (n=0; nspeaker の切替においても最初からos==0とは限らない。 // したがって、forループで所定の時間の間だけosが変化するのを待つ if (output_status != os){ // SW3がトグルされた output_status = os; right_mute = (output_status==0 ? 1 : 0); if (output_status == 0){ // 出力先=speakerとなった stereo = 0; // speaker出力時はmono固定 STEREO_LED = stereo; } SelectStation(Sta[cursta], stereo, right_mute, 0, Hcc[cursta]); break; } } Wait(WAIT_CHATTERING); IntrFlag = 0; Sleep(); } } return (0); } /* * 1バイトデータ転送 */ void SendDataTo3Wire(unsigned char data) { int i; for (i=0; i<8; i++){ if ((data & 0x80) == 0x80){ TEA_DATA = 1; } else { TEA_DATA = 0; } data <<= 1; // CLK TEA_CLK = 1; Wait(100); TEA_CLK = 0; } } /* * FM局選択 * freq : 周波数 0.1MHz単位 * stereo : 1=stereo, 0=mono * mute_right : 1= Right channel mute * mute_left: 1= Left channel mute * hcc : 1=High cut control on, 0=off */ void SelectStation(unsigned int freq, int stereo, int mute_right, int mute_left, int hcc) { unsigned long pll; unsigned char d1, d2, d3, d4, d5; pll = 4000*(((unsigned long)freq)*100L + 225) / 32768; d1 = ((pll >> 8) & 0x3F); // 1st byte : mute off, SM off d2 = (pll & 0xFF); // 2nd byte d3 = 0x10; // 3rd byte : High side injection, stereo, right mute off, left mute off if (stereo == 0) d3 |= 0x08; // mono if (mute_right == 1) d3 |= 0x04; // right mute if (mute_left == 1) d3 |= 0x02; // left mute //d4 = 0x36; // 4th byte : Japanese FM band, 32.768kHz, high cut on, Stereo noise cancel on d4 = 0x32; // 4th byte : Japanese FM band, 32.768kHz, high cut off, Stereo noise cancel on if (hcc == 1) d4 |= 0x04; // high cut on d5 = 0x00; // 5th byte : 32.768kHz, de-emphasis 50μS TEA_RW = 0; TEA_CLK = 0; TEA_DATA = 0; TEA_RW = 1; SendDataTo3Wire(d1); SendDataTo3Wire(d2); SendDataTo3Wire(d3); SendDataTo3Wire(d4); SendDataTo3Wire(d5); TEA_RW = 0; TEA_CLK = 0; TEA_DATA = 0; } /* * 待ち */ void Wait(unsigned long t) { while (t > 0){ asm("nop"); t--; } } /* * 割り込みハンドラ */ void __attribute__((interrupt, no_auto_psv)) _CNInterrupt() { IFS1bits.CNIF = 0; // 割り込みフラグクリア if (PORTBbits.RB15 == 0){ // SW1 ChangeSta = 1; } if (PORTBbits.RB14 == 0){ // SW2 ChangeStereo = 1; } IntrFlag = 1; // SW3のトグルを検出したい }