/********************************************************************************************** * DSP RADIO M6951 * * DSP MODULE:aitendo M6951 * LCD:SC1602BS * * <主な動作仕様> * (1) 受信バンド:FM/AM * (2) 音量:受信局・受信バンドは EEPROM に保存されるので電源をOFFしても、 *    その設定は保存され、次に電源をONとした時、前の状態が再現される。 * (3) 選局を長押しすると、ホーム局 stHome に戻る。 * (4) タクトSW により、音量の増減、受信局の変更、受信バンドの変更が可能。 * (5) 液晶に、受信局・受信周波数・音量[23〜63]・受信感度[dBuV]を表示。 * * PIC18F14K50トレーニング基板使用(VCC=5Vで試す) * * <クロック・コンディション(Fosc= 16MHz(Fcy=4MHz)は誤記でした下記に修正しました:180809) * Fosc= 4MHz * Fcy= 4MHz/4= 1MHz(Tcy= 1uS) * ------------------------------------------------------------------------------------------- * 2018/7/11 N.Ishii **********************************************************************************************/ #include #include "akc6951_lib.h" #include "LCD_Lib_xc8.h" ///////////////////////// コンフィグレーション ///////////////////////// #pragma config FOSC = IRC // 内部クロック #pragma config USBDIV = OFF, CPUDIV = NOCLKDIV #pragma config IESO = OFF, FCMEN = OFF, PLLEN = ON #pragma config BORV = 30, BOREN = OFF, PWRTEN = OFF #pragma config WDTPS = 32768, WDTEN = OFF #pragma config HFOFST = OFF, MCLRE = ON, XINST = OFF #pragma config BBSIZ = OFF, LVP = OFF, STVREN = ON #pragma config CP1 = OFF, CP0 = OFF, CPD = OFF, CPB = OFF #pragma config WRT1 = OFF, WRT0 = OFF, WRTB = OFF, WRTC = OFF #pragma config EBTR1 = OFF, EBTR0 = OFF, EBTRB = OFF #define presetFreq_FM 76100,77100,79500,80000,81300,82500,84700,0 // FM #define presetFreq_AM 594,693,810,954,1134,1242,1422,0 // AM #define long_ms 1000 // 長押し時間 ms #define homeSt 3 // 長押しで選局する局番号 #define SWs (PORTB | 0b01011111) // SW の状態:RB5:バンド切替・RB7:選局SWのみ接続されている #define station !PORTBbits.RB7 // SW 選局 #define band !PORTBbits.RB5 // SW バンド:押す毎に、AM/FMモードを切り替える。 #define VolUp !PORTAbits.RA4 // SW 音量 大 #define Voldn !PORTAbits.RA5 // SW 音量 小 #define LED LATCbits.LATC2 /// メッセージ・テーブル char MsgStart[] = "DSP RADIO M6951"; char MsgVer[] = "Ver.1"; char MsgOK[] = "TUNE OK"; char MsgSIGlevel[]= "xxxdBuV"; char MsgVol[]= "V:xx"; char MsgNHK_1[]= "NHK-1"; char Msg595k[]= "594kHz"; char MsgNHK_2[]= "NHK-2"; char Msg693k[]= "693kHz"; char MsgAFN[]= "AFN"; char Msg810k[]= "810kHz"; char MsgTBS[]= "TBS"; char Msg954k[]= "954kHz"; char MsgBUNKA[]= "ブンカホウソウ"; char Msg1134k[]= "1134kHz"; char MsgNIPPON[]= "NIPPONホウソウ"; char Msg1242k[]= "1242kHz"; char MsgRADIO[]= "ラジオNIPPON"; char Msg1422k[]= "1422kHz"; char MsgINTER[]= "Inter-FM"; char Msg76_1M[]= "76.1MHz"; char MsgHOUSOU[]= "Housou_D"; char Msg77_1M[]= "77.1MHz"; char MsgNACK5[]= "NACK5"; char Msg79_5M[]= "79.5MHz"; char MsgTOKYO[]= "TOKYO-FM"; char Msg80_0M[]= "80.0MHz"; char MsgJ_WAVE[]= "J-WAVE"; char Msg81_3M[]= "81.3MHz"; char MsgNHK_FM[]= "NHK-FM"; char Msg82_5M[]= "82.5MHz"; char MsgYOKOHAMA[]= "Yokohama-FM"; char Msg84_7M[]= "84.7MHz"; char SIG_LEVEL; int res; //******************* プロトタイプ *********************************** void ltostring(char digit, unsigned long data, char *buffer); void Disp_Station(char st_num, char bn_num); /// EEROM に設定する 初期周波数番号 __EEPROM_DATA(3,55,0,0,0,0,0,0); //0番地:局、1番地:音量 2番地:バンド ///////////////////////// main /////////////////////////////////////////// void main() { signed long FM_FREQ[] = {presetFreq_FM}; signed long AM_FREQ[] = {presetFreq_AM}; char st; // 受信中の局番号 char bn; // 受信中のバンド番号 unsigned char vol; // 音量 int SwTime; // SW を押している時間 char n= 0; // 受信感度表示周期を決めるメイン周期の倍数n OSCCON = 0b01010010; // 内部クロック4Mhz UCONbits.USBEN = 0 ; // USBは使用しない PORTA = 0x00; PORTB = 0x00; PORTC = 0x00; TRISA = 0xFF; TRISB = 0xFF; // ポートA,Bは入力 TRISC = 0; // LCD関連出力 ANSEL = 0x00; ANSELH = 0x00; //すべてデジタル WPUA = 0xFF; WPUB = 0xAF; // RB4:SDAと、RB6:SCL以外(外部でプルアップ)、弱プルアップ指定 INTCON2bits.nRABPU = 0; // 弱プルアップ有効 /// 液晶初期化 lcd_init(); // LCD初期化 lcd_str(MsgStart); lcd_posyx(1,10); lcd_str(MsgVer); lcd_cg_ram_user_set(); // ユーザーキャラクタセット lcd_cmd(DDRAM_START_ADDRESS_SET); //change CGRAM -> DDRAM LED = 1; // Green LED ON delay_ms(1000); LED = 0; // Green LED OFF lcd_clear(); /// I2C初期化 SCLK=100KHz ------------------------------------------ i2cintl(); /// EEPROMより局番・音量・バンド読込み st = eeprom_read(0); // 最初の起動時受信局番号 3(これはバンドで共通にした) vol = eeprom_read(1); // 最初の起動時音量:55 bn = eeprom_read(2); // 最初の起動時バンド:0 /// DSPモジュール初期化 akc6951_initialize(); /// ここで受信周波数等セット if(bn) res = akc6951_FM_tunning(FM_FREQ[st]); // 指定するFM局の周波数をセット else res = akc6951_AM_tunning(AM_FREQ[st]); // 指定するAM局の周波数をセット if(res != 0){ LED = 1; // Red LED ON(チュウニング・エラー) while(1); } lcd_str(MsgOK); delay_ms(1000); lcd_clear(); akc6951_VOL_setting(vol); // 音量設定 akc6951_SelectSpeaker(0); // シングルsp Disp_Station(st,bn); // 放送局名+周波数表示 while(1){ delay_ms(5); // チャタリング防止 if(station){ // -------- 局を変更 ------------------------ st++; // 局番号を更新する if(bn != 0){ /// バンド:FM if(FM_FREQ[st]==0)st=0; // 局番号の範囲確認 res = akc6951_FM_tunning(FM_FREQ[st]); // 指定する局の周波数をセット if(res != 0){ LED = 1; // Red LED ON(チュウニング・エラー) while(1); } } else{ /// バンド:AM if(AM_FREQ[st]==0)st=0; // 局番号の範囲確認 res = akc6951_AM_tunning(AM_FREQ[st]); // 指定する局の周波数をセット if(res != 0){ LED = 1; // Red LED ON(チュウニング・エラー) while(1); } } Disp_Station(st,bn); // 放送局名+周波数表示 eeprom_write(0, st); // EEPROM 0番地 書込み } if(band){ // -------- バンドを変更(トグル動作) ------------------------ bn++; if(bn==2)bn=0; // bn:'0'AM・'1'FM if(bn != 0){ /// バンド:FMへ切替え if(FM_FREQ[st]==0)st=0; // 局番号の範囲確認 res = akc6951_FM_tunning(FM_FREQ[st]); // 指定する局の周波数をセット if(res != 0){ LED = 1; // Red LED ON(チュウニング・エラー) while(1); } } else{ /// バンド:AMへ切替え if(AM_FREQ[st]==0)st=0; // 局番号の範囲確認 res = akc6951_AM_tunning(AM_FREQ[st]); // 指定する局の周波数をセット if(res != 0){ LED = 1; // Red LED ON(チュウニング・エラー) while(1); } } Disp_Station(st,bn); // 放送局名+周波数表示 eeprom_write(2, bn); // EEPROM 2番地 書込み } if(VolUp){ // -------- 音量 大 ------------------------ vol++; // 音量を上げる if(vol > 63)vol = 63; // 上限の確認 akc6951_VOL_setting(vol); // 音量をセット eeprom_write(1, vol); // EEPROM 1番地 書込み } while(VolUp); // SWリリース時のチャッタ回避 if(Voldn){ // -------- 音量 小 ---------------- vol--; // 音量を下げる if(vol < 23) vol = 23; // 下限の確認(0から23はミュート状態で、最小24から最大63が、可変範囲) akc6951_VOL_setting(vol); // 音量をセット eeprom_write(1, vol); // EEPROM 1番地 書込み } while(Voldn); // SWリリース時のチャッタ回避 /// 音量表示 lcd_posyx(0,12); ltostring(2, vol, MsgVol+2); lcd_str(MsgVol); SwTime = 0; while(SWs != 0xFF){ // SW が押されているなら delay_ms(1); // 離れるのを待つ if(!station)continue; // 選局 SW なら以下を実施 if(SwTime < long_ms){ // 長押しより 短いなら SwTime++; // 長押し時間を増やす }else if(SwTime == long_ms){ // 長押し指定時間なら SwTime++; // 長押し時間を増やし st = homeSt; // ホーム局を選局する if(bn){ /// バンド:FM res = akc6951_FM_tunning(FM_FREQ[homeSt]); // 指定する局の周波数をセット if(res != 0){ LED = 1; // Red LED ON(チュウニング・エラー) while(1); } } else{ /// バンド:AM res = akc6951_AM_tunning(AM_FREQ[homeSt]); // 指定する局の周波数をセット if(res != 0){ LED = 1; // Red LED ON(チュウニング・エラー) while(1); } } Disp_Station(st,bn); // 放送局名+周波数表示 eeprom_write(0, st); // EEPROM 0番地 書込み } // SW が離れるのを待つ } delay_ms(5); // チャタリング防止 /// 受信感度(dBuV換算) RegVal[24] = akc6951_read_byte(24); // Reg24リードオンリーをバイト読み、PGALEVEL_RF[7:5]とPGALEVEL_IF[4:2]の情報を得る。 RegVal[27] = akc6951_read_byte(27); // Reg27リードオンリーをバイト読み。RSSI[6:0]の情報を得る。 if(bn){ /// バンド:FM SIG_LEVEL= 103-RSSI-(6*PGALEVEL_RF)-(6*PGALEVEL_IF); // FM dBuV換算 } else{ /// バンド:AM SIG_LEVEL= 123-RSSI-(6*PGALEVEL_RF)-(6*PGALEVEL_IF); // AM dBuV換算 } /// dBuV換算値を表示 ++n; if(n == 20){ // 約10ms x 20= 200ms周期で表示 n= 0; if(((SIG_LEVEL >> 7) & 0x01) == 1){ // サインビットをチェック lcd_posyx(1,8); lcd_data(0x2D); // "-"表示 SIG_LEVEL= ~SIG_LEVEL+1; // 2の補数表現を復元 } else{ lcd_posyx(1,8); lcd_data(0x20); // "-"表示をクリア } lcd_posyx(1,9); ltostring(3, SIG_LEVEL, MsgSIGlevel+0); lcd_str(MsgSIGlevel); // dBuV換算値を表示 } } } /***************************************************************** * 受信周波数と、放送局名を、液晶に表示 * 引数は、st_num, bn_num *****************************************************************/ void Disp_Station(char st_num, char bn_num){ lcd_clear(); if(!bn_num){ switch(st_num){ case 0: lcd_str(MsgNHK_1); lcd_posyx(1,0); lcd_str(Msg595k); break; case 1: lcd_str(MsgNHK_2); lcd_posyx(1,0); lcd_str(Msg693k); break; case 2: lcd_str(MsgAFN); lcd_posyx(1,0); lcd_str(Msg810k); break; case 3: lcd_str(MsgTBS); lcd_posyx(1,0); lcd_str(Msg954k); break; case 4: lcd_str(MsgBUNKA); lcd_posyx(1,0); lcd_str(Msg1134k); break; case 5: lcd_str(MsgNIPPON); lcd_posyx(1,0); lcd_str(Msg1242k); break; case 6: lcd_str(MsgRADIO); lcd_posyx(1,0); lcd_str(Msg1422k); break; default: break; } } else{ switch(st_num){ case 0: lcd_str(MsgINTER); lcd_posyx(1,0); lcd_str(Msg76_1M); break; case 1: lcd_str(MsgHOUSOU); lcd_posyx(1,0); lcd_str(Msg77_1M); break; case 2: lcd_str(MsgNACK5); lcd_posyx(1,0); lcd_str(Msg79_5M); break; case 3: lcd_str(MsgTOKYO); lcd_posyx(1,0); lcd_str(Msg80_0M); break; case 4: lcd_str(MsgJ_WAVE); lcd_posyx(1,0); lcd_str(Msg81_3M); break; case 5: lcd_str(MsgNHK_FM); lcd_posyx(1,0); lcd_str(Msg82_5M); break; case 6: lcd_str(MsgYOKOHAMA); lcd_posyx(1,0); lcd_str(Msg84_7M); break; default: break; } } } /******************************************************** * Numerical Value-> Ascci Convert *********************************************************/ void ltostring(char digit, unsigned long data, char *buffer) { char i; buffer += digit; // To Last of Strings for(i=digit; i>0; i--) { // From LS. Digit To MS. Digit buffer--; *buffer = (data % 10) + '0'; // This Digit Value-> Ascii Convert ('0'=0x30)-> Store Buffer data = data / 10; // Digit-1 } /// ブランキング処理 i = 0; // buffer++; while((i < digit-1)&&(*buffer == '0')) // 上位桁が0の間 { *buffer = ' '; // ブランクに変換 buffer++; i++; } }