Si5251Aの実験その4(7MHz VFOの試作)

2016年12月28日  JH7UBC


3CH クロックジェネレータSi5351Aのコントロール方法が分かりましたので、
シンプルな7MHzのVFOを作ってみます。
リグへの組み込みを考慮して、Arduino NANOを使います。
表示は、NOKIA 5110を使ってみました。
Si5351A,NOKIA5110ともに3.3Vを供給しますので、3端子レギュレータを使います。
回路図です。

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の位相制御

inserted by FC2 system