SI5351 ile VFO

 

Silicon Labs'ın ürettiği Si5351 saat osilatörü devresi çok popüler oldu. Bunun sebebi, birkaç kHz'den 200 MHz'e kadar çok geniş bir aralık içinde 3 ayrı saat işareti üretebilmesi. Çıkışı kare dalga da olsa, sunduğu imkânlar ve temininin görece kolay olması karşısında bu tümdevre pek çok uygulama alanı buldu. Hazır osilatör devresi yanında bir de 3v3-5v seviye uyarlayıcı özelliği ile bu tümdevreye bir mikrokontrolcü ile kumanda etmek oldukça kolay bir hâle geldi. Hele hele Arduino kütüphaneleri bu işi -âdeta- çocuk oyuncağına çevirdi. Şimdilerde bu saat osilatörü tümdevresi ile kurulmuş modüller bir çok amatör telsiz uygulamasında kullanılıyor.

Adafruit tarafından üretilmiş bir Si5351 modülü

Daha önce Si473X tümdevresi için hazırladığı radyo uygulamasından bahsettiğim CesarSound takma isimli kullanıcının Si5351'e kumanda etmek üzere hazırlanmış bir uygulamasını gördüm. (Orijinal devreyi https://www.hackster.io/CesarSound/10khz-to-120mhz-vfo-rf-generator-with-si5351-and-arduino-3a7cad adresinde bulabilirsiniz.) Devre, 0.96 inch'lik bir OLED ekran kullanıyor. Benim gibi gözleri bu kadar ufak yazıları görmekte zorlananları düşünerek, devreyi LCD'li hâle getirmeye karar verdim. I2C'li dönüştürücü modülü olan LCD'lere sâdece 2 bağlantı hattı ile veri göndermek mümkün. Si5351 de I2C protokolü ile çalıştığından, LCD ile bu modül aynı hatta paralel bağlanıyor. Bir döner kodlayıcı (rotary encoder) ile arduinoya ve uygulamaya kumanda edilebiliyor.

Orijinal uygulamada benim yaptığım değişiklikler şunlar:

1) 0.96 inch'lik küçük OLED gösterge yerine 2 satırlık bir I2C LCD kullanılmıştır.
2) Devreye ikinci bir frekans çıkışı eklenmiştir. Bu özellik, çift çevrimli bir alıcı tasarlarken gereklidir.
3) Devrenin bir sinyal üreteci olarak kullanılabileceği düşünülerek, adım sayısı atrrırılmıştır. Devre, 1Hz, 10 Hz,
1 kHz, 5 kHz, 10 kHz, 100 kHz, 1 MHz ve 10 MHz'lik adımlarla çalışabilmektedir.
4) Devrenin frekans aralığı genişletilmiştir.
Devrede, 5V'la çalışan bir arduino kullanılmıştır. Arduino uno, nano ve mini pro 5v versiyonları ile
devre çalıştırılabilir.

Aşağıda görüldüğü üzere devre şaması oldukça basittir.

Devrenin kalibrasyonu

Si5351 devresinde referans olarak kullanılan saat osilatörü - ki çoğunlukla 25 MHz'dir- tabiidir ki tam olarak 25.000.000 Hz'de titreşen ideal bir osilatör değildir. Üretim sürecinden gelen kaymalar söz konusudur. Saat osilatörünün değerinden kaynaklanan bu hatayı gidermek için Si5351!in çıkışını ölçmek ve tam doğru bir değer elde edene kadar

#define XT_CAL_F 81050

satırındaki değeri değiştirmk gerekmektedir. Bunun için

1) Doğruluğuna emin olduğunuz bir frekans sayıcıyı Si5351'in CLK0 girişine bağlayın.

2) Aşağıdaki kodlarda,

#define IF +45000

satırındaki +45000'i silerek 0 yazın. (#define IF 0)

3) Arduino kodlarını arduinonuza yükleyerek devreyi çalıştırın ve döner kodlayıcı ile frekans çıkışını tam 10.000.000 Hz'e getirin.

4) Eğer üretilen değer 10.000.000'den büyükse, #define XT_CAL_F 81050 satırındaki 81050 sayısını büyütün. Eğer çıkış 10.000.000 Hz'den düşük ise bu sayıyı azaltın. 10.000.000 Hz elde edene kadar bu işlemi yapın.

Kalibrasyondan sonra frekans ölçümü 

Bu devre ile neler yapılabilir?

1) Devre, bir sinyal üreteci olarak kullanılabilir. Bu durumda, IF değerini 0 olarak girmelisiniz. Böylece 10 kHz ile 200 MHz arasında 1 Hz'lik adımlarla çalışan bir sinyal üreteciniz olur. Silabs, maksimum çıkış frekansını 200 MHz olarak belirtiyor. Bazı uygulamacılari 225 MHz'e kadar çıkış aldıklarını belirtiyorlarsa da, güvenli çalışma açısından burada üst sınır 180 MHz olarak seçilmiştir.

2) Bu devreyi bir alıcının lokal osilatörü olarak kullanabilirsiniz. Eğer tek çevirmeli bir alıcı kullanıyorsanız, alıcınızın ara frekans değerini kHz cinsinden IF değerinin olduğu satıra girin. Diyelim ki alıcınız 19.7 Mhz'lik bir IF değerine sahip ve üstten çevrim yapıyor, bu durumda IF değerini;

#define IF +10700

olarak girmelisiniz. Böylece osilatör, ekranda görülen değerin 10.7 MHz üzerinde çalışacaktır.

Tek çevirmeli bir alıcı kullanıyorsanız, aşağıdaki kodlarda şu değişiklikleri yapın:


si5351.output_enable(SI5351_CLK1, 1); // Bu satırdaki 1'i 0 yapın. si5351.output_enable(SI5351_CLK1, 0)

si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_2MA); // bu satırı silin ya da başına // işareti getirin.
si5351.set_ms_source(SI5351_CLK1, SI5351_PLLB); // bu satırı silin ya da başına // işareti getirin.
si5351.set_freq(mixFreq, SI5351_CLK1 ); // bu satırı silin ya da başına // işareti getirin.

 

Eğer çifte çevirmeli bir alıcı kullanıyorsanız

Diyelim ki çift çevirmeli bir alıcınız var. Birinci IF 45 MHz, ikinci IF 455 kHz. Bu durumda,

#define IF +45000

olacaktır.

İkinci IF'i elde edebilmek için ikinci karşıtırıcı için gereken frekans, 45000-455=44545 kHz'dir. 44.545 Mhz'i elde edebilmek için, ikinci saat çıkışı için gerekli satırlar aynen kalacaktır. Ayrıca,

unsigned long long mixFreq = 2000000000ULL;

satırı,

unsigned long long mixFreq = 4454500000ULL;

olarak değiştirilecektir.

Şimdi CLK0 çıkışından, alış frekansının 45 MHz üstü, CLK1 çıkışından ise 44.545 MHz çıkış alınacaktır.

Bu değerleri kendi sisteminize kolayca uyarlayabilirsiniz. Tabii gerekli RF seviyelerini de uyarlayarak.

Birinci IF 45 MHz olarak ayarlandığında, gösterge 10 MHz'i gösterirken çıkış frekansı 55 MHz'dir.

 


Devrenin şeması

Arduino kodları şöyledir:

/********************************************************************************************************
J. CesarSound'un OLED göstergeler için hazırladığı VFO devresinde değişiklikler yapılmıştır. Bu değişiklikler şunlardır:
1) 0.96 inch'lik küçük OLED gösterge yerine 2 satırlık bir I2C LCD kullanılmıştır.
2) Devreye ikinci bir frekans çıkışı eklenmiştir. Bu özellik, çift çevrimli bir alıcı tasarlarken gereklidir.
3) Devrenin bir sinyal üreteci olarak kullanılabileceği düşünülerek, adım sayısı arttırılmıştır. Devre, 1Hz, 10 Hz,
1 kHz, 5 kHz, 10 kHz, 100 kHz, 1 MHz ve 10 MHz'lik adımlarla çalışabilmektedir.
4) Devrenin frekans aralığı genişletilmiştir.
Devrede, 5V'la çalışan bir arduino kullanılmıştır. Arduino uno, nano ve mini pro 5v versiyonları ile
devre çalıştırılabilir.
Bağlantılar:
Arduino Si5351 I2C LCD
-----------------------------------
A4 SDA SDA SDA
A5 SCL SCL SCL
ENcoder bağlantıları:
2 A
3 B
A2 SW
Eğer devreyi bir sinyal üreteci olarak kullanacaksanız, aşağıdaki #define IF'in karşısına 0 yazın.

OLED'li orijinal devreyi https://www.hackster.io/CesarSound/10khz-to-120mhz-vfo-rf-generator-with-si5351-and-arduino-3a7cad adresinde bulabilirsiniz.
*********************************************************************************************************/

// *********************
//Kütüphaneler
#include <Wire.h> //IDE Standard
#include <Rotary.h> //Ben Buxton https://github.com/brianlow/Rotary
#include <si5351.h> //Etherkit https://github.com/etherkit/Si5351Arduino
#include <LiquidCrystal_I2C.h>

//Kullanıcı tercihleri
//------------------------------------------------------------------------------------------------------------
#define IF +45000 //Ara frekans değeri. +455 kHz için +455, -455 kHz için -455 girin. 0 yazarsanız, göstergedeki frekans üretilir.
#define FREQ_INIT 7000000 //Başlangıç frekansı, 7000000 = 7MHz, 10000000 = 10MHz.
#define XT_CAL_F 81050 //Si5351 kalibrasyon faktörü. Rakam büyüdükçe çıkış frekansı azalır.
#define tunestep A2 //Encoder'in anahtar bağlantısı.
//------------------------------------------------------------------------------------------------------------

Rotary r = Rotary(3, 2); // Eğer encoderin yönünü değiştirmek isterseniz 3 ve 2 yi yer değiştirin.
Si5351 si5351;
LiquidCrystal_I2C lcd(0x27,16,2); // I2C LCD'nin adresini, sütün ve satır sayısını girin.
unsigned long freq = FREQ_INIT;
unsigned long freqold, fstep;
long interfreq = IF;
long cal = XT_CAL_F;
unsigned long long pll_freq = 90000000000ULL;
byte encoder = 1;
byte stp;
unsigned int period = 100; //millis display active
unsigned long time_now = 0; //millis display active
unsigned long long mixFreq = 2000000000ULL; //İkinci mikser için frekans değeri ( Burada 20 MHZ)

ISR(PCINT2_vect) {
char result = r.process();
if (result == DIR_CW) set_frequency(1);
else if (result == DIR_CCW) set_frequency(-1);
}

void set_frequency(short dir) {
if (encoder == 1) { // Up/Down frequency
if (dir == 1) freq = freq + fstep; // Eğer encoder ileri yönde dönmüşse frekansı fstep kadar arttır
if (freq >= 180000000) freq = 180000000; // Eğer frekans 180 MHz'den büyükse, 180MHz'de sabitle
if (dir == -1) freq = freq - fstep; //Eğer encoder geri yönde dönmüşse frekansı fstep kadar azalt
if (fstep == 1000000 && freq <= 1000000) freq = 1000000;
else if (freq < 10000) freq = 10000;
}
}


void setup() {
Wire.begin();
lcd.init(); // LCD sıfırlanıyor
lcd.init();
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(tunestep, INPUT_PULLUP);


statup_text();

si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, cal);
si5351.output_enable(SI5351_CLK0, 1); //1 - etkinleştir / 0 - kapat
si5351.output_enable(SI5351_CLK1, 1); // ikinci frekans çıkışına ihtiyacınız yoksa bu satırdaki 1'i 0 yapın.
si5351.output_enable(SI5351_CLK2, 0);
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_2MA); //Çıkış akımı 2MA, 4MA, 6MA or 8MA
si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_2MA); //Çıkış akımı 2MA, 4MA, 6MA or 8MA
si5351.set_ms_source(SI5351_CLK1, SI5351_PLLB); // ikinci frekans çıkışına ihtiyacınız yoksa bu satırı silin.
si5351.set_freq(mixFreq, SI5351_CLK1 ); // ikinci frekans çıkışına ihtiyacınız yoksa bu satırı silin.


PCICR |= (1 << PCIE2);
PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
sei();

stp = 3;
setstep();
displayfreq();
}
// setup sonu
// *** ANA DÖNGÜ ***********************************************************
void loop() {

if (freqold != freq) {
time_now = millis();
tunegen();
lcd.clear();
freqold = freq;
}

if (digitalRead(tunestep) == LOW) {
time_now = (millis() + 300);
setstep();
delay(300);
}

if ((time_now + period) > millis()) {
displayfreq();
}
}
// *** Ana Döngünün sonu *************************************************
// *** Frekans üretme yordamı **********************************************************************
void tunegen() {
si5351.set_freq_manual((freq + (interfreq * 1000ULL)) * 100ULL, pll_freq, SI5351_CLK0);
}
//***Frekans üretme yordamı sonu ********************************************************************

// *** Bilgileri gösterme yordamı *******************************************************************
void displayfreq() {
lcd.backlight();
unsigned int m = freq / 1000000;
unsigned int k = (freq % 1000000) / 1000;
unsigned int h = (freq % 1000) / 1;


char buffer[15] = "";
if (m < 1) {
lcd.setCursor(6, 0); sprintf(buffer, "%003d.%003d", k, h);
}
else if (m < 100) {
lcd.setCursor(3, 0); sprintf(buffer, "%2d.%003d.%003d", m, k, h);
}
else if (m >= 100) {
unsigned int h = (freq % 1000) / 10;
lcd.setCursor(2, 0); sprintf(buffer, "%2d.%003d.%003d", m, k, h);
}
lcd.print(buffer);
lcd.setCursor(14,0);
lcd.print("Hz");
lcd.setCursor(0,1);
lcd.print("ADIM: ");
if (stp == 2) lcd.print("1 Hz "); if (stp == 3) lcd.print("10 Hz "); if (stp == 4) lcd.print("1 kHz ");if (stp == 5) lcd.print("5 kHz ");
if (stp == 6) lcd.print("10 kHz "); if (stp == 7) lcd.print("100 kHz");if (stp == 8) lcd.print("1 MHz ");if (stp == 1) lcd.print("10 MHz ");
}
// *** Bilgileri gösterme yordamı sonu ***************************************************************

//****************************************************************************
void setstep() {
switch (stp) {
case 1:
stp = 2;
fstep = 1;
break;
case 2:
stp = 3;
fstep = 10;
break;
case 3:
stp = 4;
fstep = 1000;
break;
case 4:
stp = 5;
fstep = 5000;
break;
case 5:
stp = 6;
fstep = 10000;
break;
case 6:
stp = 7;
fstep = 100000;
break;
case 7:
stp = 8;
fstep = 1000000;
break;
case 8:
stp = 1;
fstep = 10000000;
break;
}
}

// BAŞLANGIÇ EKRANI *****kendinize göre değiştirebilirsiniz.*******************************************
void statup_text() {
lcd.backlight();
lcd.setCursor(3,0);
lcd.print("T A 2 E I");
lcd.setCursor(2,1);
lcd.print("Si5351 VFO");
delay (1000);
lcd.clear();
}

//********************************************************************************************************************