Si5251Aの実験その4(7MHz VFOの試作)
2016年12月28日 JH7UBC
VFOとして動作させるためには、ロータリーエンコーダを利用し、周波数をアップダウンさせます。
その方法は、ロータリーエンコーダの実験の記事を見てください。(割り込みを利用しています。)
スケッチです。スケッチサイズは約8KBです。
ロータリーエンコーダを右に回した時に周波数をSTEP周波数分だけ増加させ、左に回した時には減少させます。
STEP周波数は、スイッチを押すたびに、1000Hz→100Hz→10Hz→1000Hzと循環させます。
このスケッチで使用しているライブラリLCD5110_Basic.hは、Rinky-Drink Electronicsというサイトから
rotary.hは、BuxtronixというWebサイトからダウンロードできます。
なお、JA2GQP局のダウンロードサイトからもそれぞれダウンロードすることができます。
/* * Si5351A 7MHz VFO * 2016.12.27 * JH7UBC Keiji Hata */ #include <LCD5110_Basic.h> #include <rotary.h> #include <Wire.h> //Si5351A関係の定義 #define Si5351A_ADDR 0x60 #define MSNA_ADDR 26 #define MSNB_ADDR 34 #define MS0_ADDR 42 #define MS1_ADDR 50 #define MS2_ADDR 58 #define CLK0_CTRL 16 #define CLK1_CTRL 17 #define CLK2_CTRL 18 #define OUTPUT_CTRL 3 #define XTAL_LOAD_C 183 #define PLL_RESET 177 uint32_t XtalFreq = 25000000; uint32_t divider; uint32_t PllFreq; uint8_t mult; uint32_t num; uint32_t denom; uint32_t l; float f; uint32_t P1; uint32_t P2; uint32_t P3; char PLL; uint8_t PLL_ADDR; uint8_t MS_ADDR; //各定数の定義 //Rotary Encoder #define ENC_A 2 //Rotary encoder A #define ENC_B 3 //Rotary encoder B //周波数STEP #define SW_STEP 4 //Frequency Change Step const long LOW_FREQ = 7000000; //下限周波数 const long HI_FREQ = 7200000; //上限周波数 unsigned long FREQ = 7000000; //VFO周波数初期値 unsigned long FREQ_OLD = FREQ; //周波数の前の値 int STEP = 1000; //STEP 初期値 LCD5110 myGLCD(9,10,11,12,13); // SCK,MOSI,DC,RST,CS extern uint8_t SmallFont[]; extern uint8_t MediumNumbers[]; Rotary r = Rotary(ENC_A,ENC_B); //ENC_A=2,ENC_B=3 void setup() { Wire.begin(); //Arduino is Master Si5351_init(); //Si5351Aの初期化 PLL_Set('A',FREQ); //VFO周波数初期値セット MS_Set(0); myGLCD.InitLCD(); //nokia5110の初期化 pinMode(SW_STEP,INPUT_PULLUP); //STEP SW 入力に設定しプルアップ //ピン変化割り込みの設定 PCICR |= (1 << PCIE2); PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); sei(); //割り込み許可 //初期画面表示 myGLCD.setFont(SmallFont); myGLCD.print("STEP",12,32); myGLCD.print(".",12,16); myGLCD.print(".",54,16); Fnc_Freq_Disp(); //周波数表示 Fnc_Step_Disp(); //STEP表示 } //Main program void loop() { if(digitalRead(SW_STEP) == LOW){Fnc_Stp();} //STEP SWが押されたら、周波数STEPを変更 if(FREQ != FREQ_OLD){ //周波数FREQが変わったら、Si5351Aの周波数を変更 PLL_Set('A',FREQ); MS_Set(0); Fnc_Freq_Disp(); //表示する。 FREQ_OLD = FREQ; //変更された周波数を保存 } delay(10); } //ロータリーエンコーダ処理(ISR=割り込みサービスルーチン) ISR(PCINT2_vect) { unsigned char result = r.process(); if(result){ if(result == DIR_CW){ FREQ = FREQ + STEP; }else{ FREQ = FREQ - STEP; } } FREQ = constrain(FREQ,LOW_FREQ,HI_FREQ); //VFOの下限と上限を超えないように } //STEPボタンが押された時の処理 void Fnc_Stp(){ if(STEP == 10){ STEP = 1000; } else{ STEP= STEP / 10; } delay(10); Fnc_Step_Disp(); while(digitalRead(SW_STEP) == LOW){ delay(10); } } //周波数表示 void Fnc_Freq_Disp(){ myGLCD.setFont(MediumNumbers); long freqH = FREQ / 1000000; myGLCD.printNumI(freqH,0,8); long freqL = FREQ - freqH * 1000000; long fM = freqL /1000; int fL = (freqL - fM * 1000) / 10; myGLCD.printNumI(fM,18,8,3,'0'); myGLCD.printNumI(fL,60,8,2,'0'); } //STEP表示 void Fnc_Step_Disp(){ myGLCD.setFont(SmallFont); myGLCD.printNumI(STEP,12,40,4,' '); } //レジスタに1バイトデータを書き込む。 void Si5351_write(byte Reg , byte Data){ Wire.beginTransmission(Si5351A_ADDR); Wire.write(Reg); Wire.write(Data); Wire.endTransmission(); } //Si5351Aの初期化 void Si5351_init(){ Si5351_write(OUTPUT_CTRL,0xFF); //Disable Output Si5351_write(CLK0_CTRL,0x80); //CLOCK0 Power down Si5351_write(CLK1_CTRL,0x80); //CLOCK1 Power down Si5351_write(CLK2_CTRL,0x80); //CLOCK2 Power down Si5351_write(XTAL_LOAD_C,0x92); //Crystal Load Capasitance=8pF Si5351_write(PLL_RESET,0xA0); //Reset PLLA and PLLB Si5351_write(CLK0_CTRL,0x4F); //CLOCK0 Power up Si5351_write(CLK1_CTRL,0x4F); //CLOCK1 Power up Si5351_write(CLK2_CTRL,0x4F); //CLOCK2 Power up Si5351_write(OUTPUT_CTRL,0xFE); //Enable CLOCK0 } //PLLの設定 void PLL_Set(char Pll,uint32_t Frequency) { divider = 900000000 / Frequency; if (divider % 2) divider--; PllFreq = divider * Frequency; mult = PllFreq / XtalFreq; l = PllFreq % XtalFreq; f = l; f *= 1048575; f /= XtalFreq; num = f; denom = 1048575; P1 = (uint32_t)(128 * ((float)num /(float)denom)); P1 = (uint32_t)(128 * (uint32_t)(mult) + P1 - 512); P2 = (uint32_t)(128 * ((float)num / (float)denom)); P2 = (uint32_t)(128 * num -denom * P2); P3=denom; if (Pll == 'A') { PLL_ADDR = MSNA_ADDR; }else { PLL_ADDR = MSNB_ADDR; } Parameter_write(PLL_ADDR,P1,P2,P3); } //MultiSynth(分周器)のセット void MS_Set(uint8_t MS_No){ P1 = 128 * divider - 512; P2 = 0; P3 = 1; switch(MS_No){ case 0: MS_ADDR = MS0_ADDR; break; case 1: MS_ADDR = MS1_ADDR; break; case 2: MS_ADDR = MS2_ADDR; break; default: MS_ADDR = MS0_ADDR; } Parameter_write(MS_ADDR,P1,P2,P3); } //レジスタにパラメータP1,P2,P3を書き込む。 void Parameter_write(uint8_t REG_ADDR,uint32_t Pa1,uint32_t Pa2,uint32_t Pa3) { Si5351_write(REG_ADDR + 0,(Pa3 & 0x0000FF00) >> 8); Si5351_write(REG_ADDR + 1,(Pa3 & 0x000000FF)); Si5351_write(REG_ADDR + 2,(Pa1 & 0x00030000) >> 16); Si5351_write(REG_ADDR + 3,(Pa1 & 0x0000FF00) >> 8); Si5351_write(REG_ADDR + 4,(Pa1 & 0x000000FF)); Si5351_write(REG_ADDR + 5,((Pa3 & 0x000F0000) >> 12) | ((Pa2 & 0X000F0000) >> 16)); Si5351_write(REG_ADDR + 6,(Pa2 & 0x0000FF00) >> 8); Si5351_write(REG_ADDR + 7,(Pa2 & 0x000000FF)); } |
ブレッドボードの様子です。
次は、Si5351Aの位相制御