0% found this document useful (0 votes)
25 views

Vfo Bfo Code

This Arduino code defines functions for an LCD display and rotary encoder to control a Si5351 frequency generator. It allows tuning a VFO frequency and optional BFO frequency. Different output modes can be selected including IF offset, direct conversion, and multiplying the output frequency.

Uploaded by

c.bhuvaneswaran
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
25 views

Vfo Bfo Code

This Arduino code defines functions for an LCD display and rotary encoder to control a Si5351 frequency generator. It allows tuning a VFO frequency and optional BFO frequency. Different output modes can be selected including IF offset, direct conversion, and multiplying the output frequency.

Uploaded by

c.bhuvaneswaran
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 7

#include <rotary.

h> // Ben Buxton's Rotary Library


#include <si5351.h> // Etherkit - NT7S Library
#include <Wire.h>
#include <LiquidCrystal.h>

#define F_MIN 100000000UL // Lower


frequency limit
#define F_MAX 5000000000UL

#define ENCODER_A 3 // Encoder pin A on Mega - others


D2
#define ENCODER_B 2 // Encoder pin B on Mega - others
D3
#define ENCODER_BTN 12 // button to change step size
and to edit BFO (long press > 1s)

#define LCD_RS 9
#define LCD_E 8
#define LCD_D4 4
#define LCD_D5 5
#define LCD_D6 6
#define LCD_D7 7

LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6,


LCD_D7); // LCD - pin assignement
Si5351 si5351;
Rotary r = Rotary(ENCODER_A, ENCODER_B);

volatile uint32_t LSB = 9996000UL; // BFO values


tune once and change these for your rig
volatile uint32_t USB = 9994000UL;
volatile uint32_t bfo = 9996000UL;
//These USB/LSB frequencies are added to or subtracted from
the vfo frequency in the "Loop()"
//In this example my start frequency will be 7.050MHz Minus
9.994Mhz BFO on clk0, suits my BITX-multibander for 40m
volatile uint32_t vfo = 7050000UL ; //start freq - change to
suit
volatile uint32_t opfreq=0LL; // Operating freq to be
generated by Si5351 feeding to VFO input
volatile uint32_t radix = 1000; //starting step size -
change to suit
boolean changed_f = 0;
String tbfo = "";

boolean setbfo = false; // long press of switch to tune bfo


int enc_cnt = 0; //encoder count

//------------------------------- Set Optional Features here


--------------------------------------
//Remove comment (//) from the option you want to use. Pick
only one
#define IF_Offset //Output is the display plus or minus the
bfo frequency
//#define Direct_conversion //What you see on display is what
you get
//#define FreqX4 //output is four times the display frequency
//------------------------------------------------------------
--------------------------------------

/**************************************/
/* Interrupt service routine for */
/* encoder frequency change */
/**************************************/
ISR(PCINT2_vect) {
unsigned char result = r.process();
if (result == DIR_CW)
enc_cnt = +1;
else if (result == DIR_CCW)
enc_cnt = -1;

if (setbfo)
set_bfo_freq();
else
set_frequency();
//enc_cnt=0;
}

/**************************************/
/* Change the frequencies */
/**************************************/

void set_frequency()
{
vfo += enc_cnt * radix;
enc_cnt =0;
changed_f = 1;
}

void set_bfo_freq()
{
bfo += enc_cnt * radix;
enc_cnt = 0;
changed_f = 1;
}

/**************************************/
/* Read the button with debouncing */
/**************************************/

boolean get_button()
{
if (!digitalRead(ENCODER_BTN))
{
delay(20);
if (!digitalRead(ENCODER_BTN))
{
long strttime=millis();
while (!digitalRead(ENCODER_BTN));
if((millis() - strttime) > 1000) // check if it was a
long press
{
setbfo = !setbfo; // flip-flop between set and not
set bfo on long press
changed_f = 1;
return 0;
}
else
return 1;
}
}
return 0;
}

/**************************************/
/* Displays the frequency */
/**************************************/
void display_frequency()
{
uint16_t f, g;

lcd.setCursor(3, 0);
f = vfo / 1000000; //variable is now vfo instead of
'frequency'
if (f < 10)
lcd.print(' ');
lcd.print(f);
lcd.print('.');
f = (vfo % 1000000) / 1000;
if (f < 100)
lcd.print('0');
if (f < 10)
lcd.print('0');
lcd.print(f);
lcd.print('.');
f = vfo % 1000;
if (f < 100)
lcd.print('0');
if (f < 10)
lcd.print('0');
lcd.print(f);
lcd.print("Hz");

// if bfo needs tuning only then display it on second line


if(setbfo)
{
lcd.setCursor(0,1);
// lcd.print("B:");
f = bfo / 1000000; //variable is now bfo instead of
'frequency'
if (f < 10)
lcd.print(' ');
lcd.print(f);
lcd.print('.');
f = (bfo % 1000000) / 1000;
if (f < 100)
lcd.print('0');
if (f < 10)
lcd.print('0');
lcd.print(f);
lcd.print('.');
f = bfo % 1000;
if (f < 100)
lcd.print('0');
if (f < 10)
lcd.print('0');
lcd.print(f);
}
else
{
lcd.setCursor(0, 1);
lcd.print(tbfo);
lcd.print(" ");
}
}

/**************************************/
/* Displays the frequency change step */
/**************************************/

void display_radix()
{
lcd.setCursor(12, 1);
switch (radix)
{
case 1:
lcd.print(" 1");
break;
case 10:
lcd.print(" 10");
break;
case 100:
lcd.print(" 100");
break;
case 1000:
lcd.print(" 1k");
break;
case 10000:
lcd.print(" 10k");
break;
case 100000:
//lcd.setCursor(10, 1);
lcd.print("100k");
break;
case 1000000:
// lcd.setCursor(9, 1);
lcd.print(" 1M"); //1MHz increments needed when bands
need to be changed
break;
}
//lcd.print("Hz"); // no space on second line so skip
}

void setup()
{
//Serial.begin(19200); // for test
lcd.begin(16, 2); // Initialize and clear the LCD
lcd.clear();
Wire.begin();

si5351.set_correction(140); //**mine. There is a calibration


sketch in File/Examples/si5351Arduino-Jason
//where you can determine the correction by using the serial
monitor.

//initialize the Si5351


si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0); //If you're using a
27Mhz crystal, put in 27000000 instead of 0
// 0 is the default crystal frequency of 25Mhz.

si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
// Set CLK0 to output the starting "vfo" frequency as set
above by vfo = ?

// First VFO generation


#ifdef IF_Offset
if (vfo > 10000000UL)
opfreq=vfo - bfo; // USB
else
opfreq= bfo - vfo ; // LSB

si5351.set_freq(opfreq, 0, SI5351_CLK0); //
SI5351_PLL_FIXED did not give any output so 0
volatile uint32_t vfoT = opfreq;
tbfo = "LSB";
// Now produce BFO
// Use CLK2 output to generate bfo frequency
si5351.set_freq( bfo, 0, SI5351_CLK2); // spb

// if needed use one of these


//si5351.drive_strength(SI5351_CLK0,SI5351_DRIVE_2MA); //you
can set this to 2MA, 4MA, 6MA or 8MA
//si5351.drive_strength(SI5351_CLK1,SI5351_DRIVE_2MA); //be
careful though - measure into 50ohms
//si5351.drive_strength(SI5351_CLK2,SI5351_DRIVE_2MA); //
#endif

// Options for making a sig gen


#ifdef Direct_conversion
si5351.set_freq((vfo * SI5351_FREQ_MULT), SI5351_PLL_FIXED,
SI5351_CLK0);
#endif

#ifdef FreqX4
si5351.set_freq((vfo * SI5351_FREQ_MULT) * 4,
SI5351_PLL_FIXED, SI5351_CLK0);
#endif

pinMode(ENCODER_BTN, INPUT_PULLUP);
// In Mega PCINT 18/19 are A10, A11
PCMSK2 |= (1 << PCINT18)| (1 << PCINT19); // Change
interrupts 18 and 19 correspond to A10,A11 on Mega
// on ATMega386
these are D2 and D3
PCICR |= (1 << PCIE2); // Enable pin
change interrupt for the encoder
sei();
display_frequency(); // Update the display
display_radix();
}

void loop()
{
// Update the display if the frequency has been changed
if (changed_f)
{
display_frequency();

#ifdef IF_Offset
if (vfo > 10000000UL)
opfreq= vfo - bfo; // USB
else
opfreq= bfo - vfo; // LSB

// VFO
si5351.set_freq(opfreq, 0, SI5351_CLK0); //
SI5351_PLL_FIXED was not OK on 7MHz
// BFO
si5351.set_freq( bfo , 0, SI5351_CLK2); // spb

//OR you can also add the bfo to suit your needs

if (vfo >= 10000000UL & tbfo != "USB") // when the


freq is tuned BFO changes to USB above 10MHz
{
bfo = USB;
tbfo = "USB";
si5351.set_freq( bfo , 0, SI5351_CLK2);
}
else if (vfo < 10000000UL & tbfo != "LSB") // and to LSB
below 10MHz ( Digital modes need USB, perhaps!)
{
bfo = LSB;
tbfo = "LSB";
si5351.set_freq( bfo , 0, SI5351_CLK2);
}
#endif

// Sig gen features


#ifdef Direct_conversion
si5351.set_freq((vfo * SI5351_FREQ_MULT),
SI5351_PLL_FIXED, SI5351_CLK0);
tbfo = "";
#endif
opfreq= opfreq *(-1ULL);

#ifdef FreqX4
si5351.set_freq((vfo * SI5351_FREQ_MULT) * 4,
SI5351_PLL_FIXED, SI5351_CLK0);
tbfo = "";
#endif

changed_f = 0;
}

// Button press changes the frequency change step for 1 Hz


steps
if (get_button())
{
switch (radix)
{
case 1:
radix = 10;
break;
case 10:
radix = 100;
break;
case 100:
radix = 1000;
break;
case 1000:
radix = 10000;
break;
case 10000:
radix = 100000;
break;
case 100000:
radix = 1000000;
break;
case 1000000:
radix = 1;
break;
}
display_radix();
}
}

You might also like