//****************************************************************************** // si5351+PIC12F1480 PLL-VFO HF の製作 // CYTEC 2018-04-13    製作:JE1AHW/内田恵介 // 開発ソフト: mikroC PRO Ver7.1 // // VFO発振範囲:1.5MHz〜63MHz // --------------------------------------------------------------------------- // 2018-04-13 ソフト開発始める // 2018-04-14 VFOとして動作する。 // 2018-04-15 Clockを32MHzにする。 // 2018-04-24 1chメモリ−機能を付ける。 // 2018-04-29 出力レベル選択ができるようにする // //****************************************************************************** // ■■■ 周波数設定 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ #define pll_frq_lo 16000000 //PLL出力周波数下限 Hz #define pll_frq_hi 16500000 //PLL出力周波数上限 Hz BW=500KHz #define pll_start_frq 16100000 //PLL出力スタ−ト時周波数Hz // ■■■ オフセット(IF)周波数設定 ■■■■■■■■■■■■■■■■■■■ // IF周波数(フィルタ−センタ−周波数) #define Ofset_Frq 9000000 //運用周波数用オフセット周波数(Hz) // ■■■ オフセット加減算設定 ■■■■■■■■■■■■■■■■■■■■■■■ // 引き算   表示周波数=VFO周波数−オフセット周波数 // 足し算   表示周波数=VFO周波数+オフセット周波数 #define off_set_flag 0 // off_set_flag 0=引き算 1=足し算 // ■■■ 運用周波数と表示周波数を合わせる 補正値設定 ■■■■■■■■■■■ // Hyouji_Hosei = ずれている量(Hz) #define Hyouji_Hosei 1800 //表示補正量 Hz 補正しない場合は0を設定 // ■■■ 運用周波数と表示周波数を合わせる 補正方法設定 ■■■■■■■■■■ #define off_set Ofset_Frq + Hyouji_Hosei // プラス補正 // #define off_set Ofset_Frq - Hyouji_Hosei // マイナス補正 // ■■■ 出力レベル設定 ■■■■■■■■■■■■■■■■■■■■■■■■■■■ // 矩形波, 種は数=14MHzにて #define OUT_Level 3 // 1=1dBm,2=5dBm,3=10dBm,4=12dBm およその目安 //■■■ 関数宣言 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ void main(); void interrupt(); void PIC12F1840_set(); void await(unsigned long ct); void wr_Byte(unsigned char x); void cmd_si5351(unsigned char reg_No, unsigned char x); void set_freq(unsigned long freq); void si5351_init(void); void step_set(); void LCD_hyouji (); void cmd_LCD(unsigned char x); void data_LCD(unsigned char c); void LCD_ini(); void start(); void stop(); void LCD_Pos(unsigned char GY,unsigned char KT); void MEM_W(); void MEM_R(); void MEM_SW_Check(); //■■■グロ−バル変数設定 ■■■■■■■■■■■■■■■■■■■ ■■■■■■ static unsigned long count=0; //メインカウンタ− static unsigned long step; //エンコ−ダ ステップ周波数Hz static unsigned char RE; //エンコ−ダ用変数その1 static unsigned char RE_TMP; //エンコ−ダ用変数その2 static unsigned char sw_flag; //ステップ数変更のスイッチ状態を保管 static unsigned char oldstate; //スイッチ状態取り込みようフラグ static unsigned char vfo_nr_flag; //正VFO,逆VFO選択フラグ //■■■ ピンアサイン ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ #define SCL PORTA.B1 //I2C Clock #define SDA PORTA.B2 //I2C Data //■■■ PIC12F1840 初期化 ■■■■■■■■■■■■■■■■■■■■ void PIC12F1840_set() { OSCSTAT = 0b01011000 ; //PLLを使う場合 Clock=32MHz OSCCON = 0b11110000 ; // 内部クロックは8MHzとする 4xPLL // OPTION_REG = 0b00000000 ; // デジタルI/Oに内部プルアップ抵抗を使用する // WPUA = 0b00000000 ; // プルアップ抵抗設定 使用=1 未使用=0 ANSELA = 0b00000000 ; // A/D入力ピン設定 入力=1 TRISA = 0b00111001; // 入出力設定 0=OUTPUT 1=INPUT PORTA = 0b00000000 ; // 出力ピンの初期化(全てLOWにする) //---- Timer0の設定 --------------------------------------------------- OPTION_REG.PSA = 1; //プリスケ−ラを使わない OPTION_REG.TMR0CS = 0; //内臓クロック使用 INTCON.T0IF = 0; //オバ−フロ−フラグ・クリア− TMR0 = 0x80; //TIMER0インタ−バル周期設定 INTCON.T0IE = 1; //Timer0オバ−フロ−割り込み設定。 } //■■■ 割り込み処理 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ void interrupt() { INTCON.T0IF = 0; //割り込みフラグ・クリア TMR0 = 0x80; //割り込み周期調整定数 //エンコ−ダ−回転方向取得 RE <<= 2 ; //エンコ−ダ−の状態を保存する RE &= 0b00001100; RE_TMP = PORTA; //現在のエンコ−ダ−の状態を読み込む RE_TMP >>=4; RE_TMP &= 0b00000011; //マスク処理 RE = RE | RE_TMP; //旧デ−タと新デ−タを足す // UP処理 if(RE == 1) { count = count + step; //カウントUP if(count >= pll_frq_hi) //周波数上限リミット { count = pll_frq_hi; } } //Down処理 if(RE == 4) { count = count - step; //カウントDown if(count <= pll_frq_lo ) //周波数下限リミット { count = pll_frq_lo; } } } //■■■ Wate Timer ■■■■■■■■■■■■■■■■■■■■ void await(unsigned long ct) { while(ct>0) ct--; } //■■■ I2C Start ■■■■■■■■■■■■■■■■■■■■ void start() { SCL = 1; // start condition await(3); SDA = 1; await(3); SDA = 0; await(3); SCL = 0; await(3); } //■■■ I2C Stop ■■■■■■■■■■■■■■■■■■■■ void stop() { await(3); SCL = 1; // stop condition await(3); SDA = 0; await(3); SDA = 1; await(3); SCL = 0; await(3); } //■■■ I2C 8bit Data 書き込み ■■■■■■■■■■■■■■■■■■■■ void wr_Byte(unsigned char x) { unsigned int k; for(k=0;k<8;k++){ if(x & 0x80) SDA = 1; else SDA = 0; await(3); SCL = 1; await(3); SCL = 0; await(3); SDA = 0; x <<= 1; } SCL = 1; await(3); SCL = 0; } //■■■ I2C cmd 書き込み ■■■■■■■■■■■■■■■■■■■■ void cmd_si5351(unsigned char reg_No, unsigned char x) { start(); wr_Byte(0xC0); // アドレス 0b11000000(0xC0) wr_Byte(reg_No); wr_Byte(x); stop(); } //■■■ si5351 初期化 ■■■■■■■■■■■■■■■■■■■■ void si5351_init(void){ SDA=1; SCL=1; await(200); cmd_si5351(183,0b10010010); // Bit7:6,01=6pF,10=8pF,11=10pF cmd_si5351(16,0x80); // Disable CLK0 cmd_si5351(17,0x80); // Disable CLK cmd_si5351(177,0xA0); // Reset PLL_A //   Enable CLK0 (MS0=Integer Mode, Source=PLL_A) switch (OUT_Level) { //出力レベル設定 case 1:cmd_si5351(16,0x4C);break; case 2:cmd_si5351(16,0x4D);break; case 3:cmd_si5351(16,0x4E);break; case 4:cmd_si5351(16,0x4F);break; default:cmd_si5351(16,0x4E);break; } // CLK1からも出力する // cmd_si5351(17,0x4F); // Enable CLK1 (MS1=Integer Mode, Source=PLL_A) } //■■■ si5351 Dataセット ■■■■■■■■■■■■■■■■■■■■ void set_freq(unsigned long freq) // freq [Hz] // // fvco= fxtal*(a+b/c) ( a:15 -- 90, b:0 -- 1048575, c:1 -- 1048575 ) // freq= fvco /(a+b/c) ( a:4, 6--1800, b:0 -- 1048575, c:1 -- 1048575 ) // // P1= 128*a + floor(128*b/c) - 512 // P2= 128*b - c*floor(128*b/c) // P3= c // { unsigned long M; unsigned int R; unsigned long c; unsigned long a; unsigned long b; unsigned long dd; unsigned long P1; unsigned long P2; unsigned long P3; if(freq<1500) freq=1500; else if(freq>280000000) freq=280000000; // VFO発振周波数は、1.5MHz〜63MHzまで if(freq>=63000000){M=6; R=0;} else if(freq>=27500000){M=14; R=0;} else if(freq>=13000000){M=30; R=0;} else if(freq>= 6500000){M=62; R=0;} else if(freq>= 3000000){M=126; R=0;} else if(freq>= 1500000){M=280; R=0;} /* else if(freq>= 700000){M=600; R=0;} else if(freq>= 330000){M=1280; R=0;} else if(freq>= 150000){M=1300; R=1;} else if(freq>= 67000){M=1500; R=2;} else if(freq>= 30300){M=1600; R=3;} else if(freq>= 14000){M=1800; R=4;} else if(freq>= 7000){M=1800; R=5;} else if(freq>= 3500){M=1800; R=6;} else{M=1800; R=7;} */ freq*=M; freq<<=R; c=0xFFFFF; a=freq/25000000; b=(long)((double)(freq-a*25000000)*(double)c/(double)25000000); dd=(128*b)/c; P1=128*a+dd-512; P2=128*b-c*dd; P3=c; //Set fvco of PLL_A cmd_si5351(26,(P3>>8)&0xFF); //MSNA_P3[15:8] cmd_si5351(27,P3&0xFF); //MSNA_P3[7:0] cmd_si5351(28,(P1>>16)&0x03); //MSNA_P1[17:16] cmd_si5351(29,(P1>>8)&0xFF); //MSNA_P1[15:8] cmd_si5351(30,P1&0xFF); //MSNA_P1[7:0] cmd_si5351(31,(P3>>12)&0xF0|(P2>>16)&0x0F);//MSNA_P3[19:16], MSNA_P2[19:16] cmd_si5351(32,(P2>>8)&0xFF); //MSNA_P2[15:8] cmd_si5351(33,P2&0xFF); //MSNA_P2[7:0] // Set MS0, MS1 // a=M, b=0, c=1 ---> P1=128*M-512, P2=0, P3=1 if(M==4){ P1=0; cmd_si5351(42,0); //MS0_P3[15:8] cmd_si5351(43,1); //MS0_P3[7:0] cmd_si5351(44,0b00001100); //0,R0_DIV[2:0],MS0_DIVBY4[1:0],MS0_P1[17:16] cmd_si5351(45,0); //MS0_P1[15:8] cmd_si5351(46,0); //MS0_P1[7:0] cmd_si5351(47,0); //MS0_P3[19:16], MS0_P2[19:16] cmd_si5351(48,0); //MS0_P2[15:8] cmd_si5351(49,0); //MS0_P2[7:0] cmd_si5351(50,0); //MS1_P3[15:8] cmd_si5351(51,1); //MS1_P3[7:0] cmd_si5351(52,0b00001100); //0,R1_DIV[2:0],MS1_DIVBY4[1:0],MS1_P1[17:16] cmd_si5351(53,0); //MS1_P1[15:8] cmd_si5351(54,0); //MS1_P1[7:0] cmd_si5351(55,0); //MS1_P3[19:16], MS0_P2[19:16] cmd_si5351(56,0); //MS1_P2[15:8] cmd_si5351(57,0); //MS1_P2[7:0] }else{ P1=128*M-512; cmd_si5351(42,0); //MS0_P3[15:8] cmd_si5351(43,1); //MS0_P3[7:0] cmd_si5351(44,(R<<4)&0x70|(P1>>16)&0x03);//0,R0_DIV[2:0],MS0_DIVBY4[1:0],MS0_P1[17:16] cmd_si5351(45,(P1>>8)&0xFF); //MS0_P1[15:8] cmd_si5351(46,P1&0xFF); //MS0_P1[7:0] cmd_si5351(47,0); //MS0_P3[19:16], MS0_P2[19:16] cmd_si5351(48,0); //MS0_P2[15:8] cmd_si5351(49,0); //MS0_P2[7:0] cmd_si5351(50,0); //MS1_P3[15:8] cmd_si5351(51,1); //MS1_P3[7:0] cmd_si5351(52,(R<<4)&0x70|(P1>>16)&0x03);//0,R1_DIV[2:0],MS1_DIVBY4[1:0],MS1_P1[17:16] cmd_si5351(53,(P1>>8)&0xFF); //MS1_P1[15:8] cmd_si5351(54,P1&0xFF); //MS1_P1[7:0] cmd_si5351(55,0); //MS1_P3[19:16], MS0_P2[19:16] cmd_si5351(56,0); //MS1_P2[15:8] cmd_si5351(57,0); //MS1_P2[7:0] } // cmd_si5351(165,0); //Phase Offset Clock0 // cmd_si5351(166,0); //Phase Offset Clock1 } // ■■■ ステップ周波数選択 ■■■■■■■■■■■■■■■■■■■■■■■■ // ステップは、100,10Hzとする。 //スイッチは、PORTA,bit0の接続 void step_set() { unsigned char f10[]={"10"}; unsigned char f100[]={"100"}; unsigned char i; if(Button(&PORTA,0,5,1)) oldstate = 1; if(oldstate && Button(&PORTA,0,5,0)){ sw_flag -=1; // スイッチフラグに加算する。 sw_flag &= 0b00000111; if(sw_flag == 0) sw_flag = 0x02; //フラグ値が3になったら1にする。 oldstate = 0; } if(sw_flag == 0x01){ //ステップ=10Hz設定 step = 10; LCD_Pos(1,14); data_LCD(0b00100000); //ヌル表示 LCD_Pos(1,15); //表示場所指定 for(i=0;i<2;i++) //標準表示方法 { data_LCD(f10[i]); } } if(sw_flag == 0x02){ //ステップ=100Hz設定 step = 100; LCD_Pos(1,14); //表示場所指定 for(i=0;i<3;i++) //標準表示方法 { data_LCD(f100[i]); } count =(count/100)*100; //下2桁ゼロクリア } } //■■■ 運用周波数LCD表示 ■■■■■■■■■■■■■■■■■■■■■■■■ void LCD_hyouji () { unsigned char buf[12]; unsigned char buf1[12]; //表示入れ替え作業用配列 unsigned long frq_hyouji; //運用周波数表示用変数 unsigned char i; //IF周波数補正  表示を運用周波数にする。 if(vfo_nr_flag == 0) //正VFO処理 { if(off_set_flag == 1){ frq_hyouji = count + off_set; //正VFO プラス処理 } if(off_set_flag == 0){ frq_hyouji = count - off_set; //正VFO マイナス処理 } } if(vfo_nr_flag == 1) { frq_hyouji = off_set - count ; // 逆VFO処理(簡易型) } LongToStr(frq_hyouji,buf); //運用周波数をBCDに変換する。 buf1[0] = 0x20; //表示内容を入れ替え、小数点を入れる。 buf1[1] = buf[3]; buf1[2] = buf[4]; buf1[3] = 0x2e; //小数点 buf1[4] = buf[5]; buf1[5] = buf[6]; buf1[6] = buf[7]; buf1[7] = 0x2e; buf1[8] = buf[8]; buf1[9] = buf[9]; buf1[10] =buf[10]; LCD_Pos(2,1); //表示場所指定 for(i=0;i<11;i++) //標準表示方法 { data_LCD(buf1[i]); } } //■■■ LCD cmd 書き込み ■■■■■■■■■■■■■■■■■■■■ void cmd_LCD(unsigned char x) { start(); wr_Byte(0xa0); //LCDアドレス 固定 10100000 wr_Byte(0x00); //RS Flag Cmd Write wr_Byte(x); stop(); } //■■■ LCD Data 書き込み ■■■■■■■■■■■■■■■■■■■■ //**************************************************************** //* == LCDへの表示方法 == * //* LCD_Pos(2,3); //表示場所指定 * //* * //* for(i=0;i<13;i++) //標準表示方法 * //* { * //* data_LCD(table[i]); * //* } * //* * //* data_LCD(0b00111000); //数字の8 一文字表示方法 * //**************************************************************** void data_LCD(unsigned char c) { start(); wr_Byte(0xa0); //LCDアドレス10100000 wr_Byte(0x80); //RS Flag Data Write wr_Byte (c); stop(); } //■■■ LCD 初期化 ■■■■■■■■■■■■■■■■■■■■■■■■ void LCD_ini() { unsigned char rogo[]={"CYTEC"}; char i; //----- ACM1602N1 --------------------------------------------------- cmd_LCD(0x38); //機能制御:8bitモ−ド、2ライン、5x8ドット await(10); cmd_LCD(0x0C); //ディスプレ−ON、カ−ソルOFF,ブリンクOFF await(10); cmd_LCD(0x06); //カ−ソル移動、スクロ−ルOFF await(10); LCD_Pos(1,7); for(i=0;i<5;i++) { data_LCD(rogo[i]); // CYTEC表示 } Delay_ms(800); cmd_LCD(0x01); // Clear LCD } //■■■ LCD 表示ポジション ■■■■■■■■■■■■■■■■■■■■■ void LCD_Pos(unsigned char GY,unsigned char KT) { unsigned char n,u; if(GY==1) n=127; // 表示アドレス設定 1行目 128+桁数 if(GY==2) n=191; //          2行目 192+桁数 u=n+KT; // 表示位置計算 cmd_LCD(u); // LCDコマンド送信 } //■■■ メモリ−スイッチ チェック ■■■■■■■■■■■■■■■■■■■■■ void MEM_SW_Check() { unsigned char K=0; if(Button(&PORTA,3,5,1)) oldstate = 1; if(oldstate && Button(&PORTA,3,5,0)) { while(1){ if(PORTA.B3 != 0) break; K =++K; //SW押された時間をカウントする。 Delay_ms(20); } if(K<=20) MEM_W(); //メモリ−書き込み if(K>=21) MEM_R(); //メモリ−読み込み oldstate=0; } } //■■■ メモリ−書き込み ■■■■■■■■■■■■■■■■■■■■■ //EEPROM書き込みアドレス 10、11,12,13 void MEM_W() { unsigned char i; unsigned char MW[]={"MW"}; unsigned char null[]={" "}; Eeprom_Write(10,(count & 0xFF)); //メモリ−に書き込む。 Delay_ms(20); Eeprom_Write(11,((count>>8) & 0xFF)); Delay_ms(20); Eeprom_Write(12,((count>>16) & 0xFF)); Delay_ms(20); Eeprom_Write(13,((count>>24) & 0xFF)); Delay_ms(20); LCD_Pos(1,10); for(i=0;i<2;i++) { data_LCD(MW[i]); // } Delay_ms(700); LCD_Pos(1,10); for(i=0;i<2;i++) { data_LCD(null[i]); // } } //■■■ メモリ−読み込み ■■■■■■■■■■■■■■■■■■■■■ //EEPROM書き込みアドレス 10、11,12,13 void MEM_R() { unsigned char i; unsigned char MR[]={"MR"}; unsigned char null[]={" "}; count = Eeprom_Read(13); //メモリ−を読み出す。 count = count << 8; count = count | Eeprom_Read(12); count = count << 8; count = count | Eeprom_Read(11); count = count << 8; count = count | Eeprom_Read(10); LCD_Pos(1,10); for(i=0;i<2;i++) { data_LCD(MR[i]); // } Delay_ms(700); LCD_Pos(1,10); for(i=0;i<2;i++) { data_LCD(null[i]); // } } //■■■ メイン関数 ■■■■■■■■■■■■■■■■■■■■■■■■■■■ void main() { //表示用デ−タ unsigned char i; unsigned char MHz[]={"MHz"}; unsigned char call[]={"JE1AHW"}; //---------- 初期設定 ----------------------------------------------- PIC12F1840_set(); //PIC設定 si5351_init(); //si5351設定 LCD_ini(); //LCD設定 count = pll_start_frq; //スタ−ト周波数 sw_flag = 0x02; //ステップは、100Hzから vfo_nr_flag = 0; //正方向VFO処理 RE = PORTA; //エンコ−ダ−の一番最初の状態取得 RE >>=4; RE &= 0b00000011; LCD_Pos(1,2); //表示場所指定 for(i=0;i<6;i++) { data_LCD(call[i]); //コ−ルサイン表示 } LCD_Pos(2,14); //表示場所指定 for(i=0;i<3;i++) { data_LCD(MHz[i]); //MHz表示 } INTCON.GIE = 1; //割り込み、すべて許可。(動作開始) while(1) { LCD_hyouji (); // LCD表示ル−チン step_set(); // ステップ周波数設定ル−チン set_freq(count); // PLLデ−タ設定ル−チン MEM_SW_Check(); //メモリ−スイッチのチェック } }