//****************************************************************************** // Libra7000受信機用モノバンドVFO ACM1602-Type の製作 // CYTEC 2020-07-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-05-12 メモリ−を使い前回周波数で立がるようにする。 // 2018-05-28 LCD表示方法を、ポインタ仕様に変更する Ver2 // 2018-05-31 LCD表示器にAQM1602を使う。 // 2019-03-31 オ−トステップに改造 // 2020-06 オ−トステップを上保さん方式にする // 2020-07-013 Orion型受信機用モノバンドVFOに改造する // 使用LCDを I2C ACM1602に変更する // // 2022-01-28 Libra7000用VFO 作成開始 //****************************************************************************** // LCD表示器 = ACM1602(0xA0) I2c LCD //   HZBタイプ スマ-トダイアル使用 //****************************************************************************** // ■■■ 周波数設定 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ // VFO set //****************************************************************************** #define pll_start_frq 16100000 //DDS出力スタ−ト周波数Hz //------------- #define freq_Lo 16000000 // 発振最低周波数 #define freq_Hi 16500000 // 発振最高周波数 //---------------------------------- #define Xtal 25000000 //si5351A クロック周波数 //周波数ずれは、この値で調整する。 // ■■■ オフセット(IF)周波数設定 ■■■■■■■■■■■■■■■■■■■ // IF周波数(フィルタ−センタ−周波数) #define Ofset_Frq 9000000 //運用周波数用オフセット周波数(Hz) // ■■■ オフセット加減算設定 ■■■■■■■■■■■■■■■■■■■■■■■ // 引き算   表示周波数=VFO周波数−オフセット周波数  設定=0 // 足し算   表示周波数=VFO周波数+オフセット周波数 設定=1 #define off_set_flag 0 // off_set_flag 0=引き算 1=足し算 // ■■■ 出力レベル設定 ■■■■■■■■■■■■■■■■■■■■■■■■■■■ // 矩形波, 周波数=14MHzにて #define OUT_Level 4 // 1=1dBm,2=5dBm,3=10dBm,4=12dBm およその目安 // ■■■ タイトル表示 ■■■■■■■■■■■■■■■■■■■■■■■■■■■ #define word "Libra7000" // #define word "CYTEC" //■■■ 関数宣言 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 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 LCD_hyouji (); void cmd_LCD(unsigned char x); void LCD_str(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(); void auto_step(); //■■■グロ−バル変数設定 ■■■■■■■■■■■■■■■■■■■ ■■■■■■ static unsigned long count = 0; //メインカウンタ− static unsigned long fmax = freq_Hi; static unsigned long fmin = freq_Lo; static unsigned long old_count = 0; static unsigned char RE = 0; //エンコ−ダ用変数その1 static unsigned char RE_TMP = 0; //エンコ−ダ用変数その2 static unsigned char oldstate = 0; //スイッチ状態取り込みようフラグ static unsigned char vfo_nr_flag; //正VFO,逆VFO選択フラグ static unsigned char MEM_Chek_Flag=0; static int EncoPalus = 0; static int RE_count = 0; //エンコ−ダ−回転数 static float L = 0; static long afstp = 0; static unsigned int MaxL=1000.0; //■■■ ピンアサイン ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ #define SCL PORTA.B1 //I2C Clock #define SDA PORTA.B2 //I2C Data //■■■ 割り込み処理 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ void interrupt() { INTCON.T0IF = 0; //割り込みフラグ・クリア TMR0 = 0x80; //割り込み周期調整定数 //エンコ−ダ−回転方向取得 RE <<= 2 ; //エンコ−ダ−の状態を保存する RE &= 0b00001100; RE_TMP = PORTA; //現在のエンコ−ダ−の状態を読み込む RE_TMP >>=4; RE_TMP &= 0b00000011; //マスク処理 RE = RE | RE_TMP; //旧デ−タと新デ−タを足す //------------------------------------------------------------------------- if(RE == 1) { EncoPalus += 1; //加算 } if(RE == 4) { EncoPalus -= 1; //減算 } } //■■■ AutoStep Main  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ void auto_step() { RE_count = EncoPalus; EncoPalus = 0; if(RE_count!=0) { afstp=(long)((float)(RE_count)*((float)10 + 0.001*L*L) ); //main if(abs(RE_count)>=3){ L += 2*(float)(abs(RE_count)*2); //vth スレッショルド if (L>MaxL) L=MaxL; } else { L -= 50;; //減速 if(L<0) L=0; } if(afstp!=0) { count += afstp; if(count > fmax) count = fmax; if(count < fmin) count = fmin; } } afstp = 0; } //■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ //■■■ メイン関数 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ //■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ void main() { //---------- 初期設定 ----------------------------------------------- PIC12F1840_set(); //PIC設定 si5351_init(); //si5351設定 LCD_ini(); //LCD設定 afstp = 0; //増減変数クリア vfo_nr_flag = 0; //正方向VFO処理 逆VFO=1 RE = PORTA; //エンコ−ダ−の一番最初の状態取得 RE >>=4; RE &= 0b00000011; LCD_Pos(1,2); //表示場所指定 LCD_str(word); LCD_Pos(2,14); //表示場所指定 LCD_str("MHz"); MEM_R(); //メモリ−読み込み set_freq(count); old_count = count; // INTCON.GIE = 1; //割り込み、すべて許可。(動作開始) while(1) { LCD_hyouji (); // LCD表示ル−チン if(count != old_count) { set_freq(count); old_count = count; } auto_step(); MEM_SW_Check(); //メモリ−スイッチのチェック } } //****************************************************************************** //■■■ PIC12F1840 初期化 ■■■■■■■■■■■■■■■■■■■■■■■■■ //****************************************************************************** void PIC12F1840_set() //PullUP使用 { OSCSTAT = 0b01011000 ; //PLLを使う場合 Clock=32MHz OSCCON = 0b11110000 ; // 内部クロックは8MHzとする 4xPLL OPTION_REG = 0b00001000 ; //内部プルアップ抵抗を使用する Bit7=0 WPUA = 0b00111111 ; // プルアップ抵抗設定 使用=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オバ−フロ−割り込み設定。 } //****************************************************************************** //■■■ Wate Timer ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ //****************************************************************************** void await(unsigned long ct) { while(ct>0) ct--; } //****************************************************************************** //■■■ I2C Start ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ //****************************************************************************** // I2C LCD ACM1602 void start() { SCL = 1; // start condition await(3); SDA = 1; await(3); SDA = 0; await(3); SCL = 0; await(3); } //****************************************************************************** //■■■ I2C Stop ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ //****************************************************************************** // I2C LCD ACM1602 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; } //****************************************************************************** //■■■ Si5351 Cmd 書き込み ■■■■■■■■■■■■■■■■■■■■ // si5351A Add=0xC0 //****************************************************************************** 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,0b01010010); // Bit7:6,01=6pF,10=8pF,11=10pF cmd_si5351(16,0x80); // Disable CLK0 cmd_si5351(17,0x80); // Disable CLK1 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; } // cmd_si5351(17,0xCA); // CLK1 OUT cmd_si5351(3, 0xFE); // (OUT:CLK0=0xFE, OUT:CLK0 and CLK1 = 0xFC) } //■■■ si5351 Dataセット ■■■■■■■■■■■■■■■■■■■■ void set_freq(unsigned long freq) { 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; // 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;} freq*=M; freq<<=R; c=0xFFFFF; a=freq/Xtal; b=(long)((double)(freq-a*Xtal)*(double)c/(double)Xtal); 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 // a=M, b=0, c=1 ---> P1=128*M-512, P2=0, P3=1 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] } //***************************************************************************** //■■■ 運用周波数LCD表示 ■■■■■■■■■■■■■■■■■■■■■■■■ //***************************************************************************** void LCD_hyouji () { unsigned char buf[12]; unsigned char buf1[12]; //表示入れ替え作業用配列 unsigned long frq_hyouji; //運用周波数表示用変数 unsigned long LCD_count; //表示を100Hzからにするための作業変数 LCD_count = count; //10Hz以下の表示をなくすため。 LCD_count = LCD_count/100*100; //IF周波数補正  表示を運用周波数にする。 if(vfo_nr_flag == 0) //正VFO処理 { if(off_set_flag == 1){ frq_hyouji = LCD_count + Ofset_Frq; //正VFO プラス処理 } if(off_set_flag == 0){ frq_hyouji = LCD_count - Ofset_Frq; //正VFO マイナス処理 } } if(vfo_nr_flag == 1) { frq_hyouji = Ofset_Frq - LCD_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]; buf1[11]=0; //0がないとダメ。 LCD_Pos(2,2); //表示場所指定 LCD_str(buf1); //LCDに周波数表示 } //***************************************************************************** //■■■ LCD cmd 書き込み ■■■■■■■■■■■■■■■■■■■■■■■ // ACM1602 Add=0xA0 //***************************************************************************** void cmd_LCD(unsigned char x) { start(); wr_Byte(0xa0); //LCDアドレス 0xa0 wr_Byte(0x00); //RS Flag Cmd Write (0x00000000) wr_Byte(x); stop(); } //****************************************************************************** //■■■ LCD Data 表示 「文字列」 ■■■■■■■■■■■■■■■■■■■ // LCD_str関数の使い方 // LCD_str(call); 配列の表示 unsigned char call[]={"JE1AHW"}; // LCD_str("JE1AHW Kuki"); 文字指定表示 //****************************************************************************** void LCD_str(unsigned char *s) { while(*s) { start(); wr_Byte(0xa0); //LCDアドレス 0xa0 wr_Byte(0b10000000); //コマンドデ−タ 0b10000000 0x80 wr_Byte(*s); //文字表示する。 *s++; stop(); } } //***************************************************************************** //■■■ LCD 表示ポジション ■■■■■■■■■■■■■■■■■■■■■■■■ // 表示アドレス 8moji // 0x00,0x01,0x02-0x07,--,0x0A,0x0B,--0x0F 16moji // 0x40,0x41,0x42-0x47,--,0x4A,0x4B,--0x4F //****************************************************************************** void LCD_Pos(unsigned char keta,unsigned char gyou) { unsigned char tmp; if(keta == 1) tmp=0; if(keta == 2) tmp = 0x40; tmp = tmp+(gyou-1); tmp=tmp|0x80; cmd_LCD(tmp); } //****************************************************************************** //■■■ LCD 初期化(No2) ■■■■■■■■■■■■■■■■■■■■■■■ //*** 使用LCD  ACM1602N1(i2C) ********************** // BL=ホワイト  大型LCD //****************************************************************************** void LCD_ini() { cmd_LCD(0x38); //機能制御:8bitモ−ド、2ライン、5x8ドット await(10); cmd_LCD(0x0C); //ディスプレ−ON、カ−ソルOFF,ブリンクOFF await(10); cmd_LCD(0x06); //カ−ソル移動、スクロ−ルOFF await(10); } //■■■ メモリ−スイッチ チェック ■■■■■■■■■■■■■■■■■■■■■ 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_R(); // メモリ−読み込み(短押し) if(K>=21) MEM_W(); // メモリ−書き込み(長押し) oldstate=0; } } //■■■ メモリ−書き込み ■■■■■■■■■■■■■■■■■■■■■ //EEPROM書き込みアドレス 10、11,12,13 void MEM_W() { 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); // メモリ−に書き込みがあるかどうかをチェックするためのフラグを保存 // EEEPROM_ADD = 9 MEM_Chek_Flag = 1; Eeprom_Write(9,MEM_Chek_Flag); Delay_ms(20); LCD_Pos(1,13); LCD_str("MW"); Delay_ms(700); LCD_Pos(1,13); LCD_str(" "); } //■■■ メモリ−読み込み ■■■■■■■■■■■■■■■■■■■■■ //EEPROM読み込みアドレス 10、11,12,13 void MEM_R() { MEM_Chek_Flag = Eeprom_Read(9); //メモリ−書き込み確認フラグ Delay_ms(20); if(MEM_Chek_Flag == 1) { 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,13); LCD_str("MR"); Delay_ms(700); LCD_Pos(1,13); LCD_str(" "); }else{ count = pll_start_frq; //スタ−ト周波数 } } //****** END ****************************************************************