Link to VHF_VFO.ino
I can tune up to 160Mhz. Output with default current setting is about -10dbm.
/*
I can tune up to 160Mhz. Output with default current setting is about -10dbm.
/*
This entire program is taken from Jason Mildrum, NT7S and Przemek Sadowski, SQ9NJE and Ben Buxton.
***The following code has been modified to use the updated library of NT7S.
As of this date, the library is still undergoing changes so be aware of that.
This code was tested on an Arduino Uno ONLY and it works if you setup your
hardware as seen here http://ak2b.blogspot.com/search/label/si5351%20uno%20layout
Equally important is that you make sure that Jason's new library REPLACES any existing
Si5351 libraries in places that the Arduino IDE will look for it. Remove the existing Si5351 folder in the "Arduino/Libraries" folder and put it in another folder for safe keeping in case you need to use it again. I made a folder called Lib_Temp to put user libraries not in use. If you get errors
it will most likely be for this reason. Please spend the time to resolve this problem.
MAKE SURE THE ARDUINO IDE IS CLOSED WHEN MAKEING CHANGES TO THE LIBRARY.
For help on the proper place to put libraries look here:
Jason's new library will break existing code using his older library.
*/
#include <Rotary.h>
#include <si5351.h>
#include "Wire.h"
#include <LiquidCrystal.h>
#define OLED_RESET 4
#define ENCODER_A 3 // Encoder pin A
#define ENCODER_B 2 // Encoder pin B
#define ENCODER_BTN 11
#define LCD_RS 5
#define LCD_E 6
#define LCD_D4 7
#define LCD_D5 8
#define LCD_D6 9
#define LCD_D7 10
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7); // LCD - pin assignement in
Si5351 si5351;
Rotary r = Rotary(ENCODER_A, ENCODER_B);
volatile uint32_t frequency0 = 1000000000L / SI5351_FREQ_MULT; //10Mhz - change to suit your needs
//just take care to count the right number of zeros.
// volatile uint32_t frequency1 = 9000000L;
// volatile uint32_t frequency2 = 10000000L;
volatile uint32_t radix = 100;
boolean changed_f = 0;
/**************************************/
/* Interrupt service routine for */
/* encoder frequency change */
/**************************************/
ISR(PCINT2_vect) {
unsigned char result = r.process();
if (result == DIR_CW)
set_frequency(1);
else if (result == DIR_CCW)
set_frequency(-1);
}
/**************************************/
/* Change the frequency */
/* dir = 1 Increment */
/* dir = -1 Decrement */
/**************************************/
void set_frequency(short dir)
{
if(dir == 1)
frequency0 += radix;
if(dir == -1)
frequency0 -= radix;
changed_f = 1;
}
/**************************************/
/* Read the button with debouncing */
/**************************************/
boolean get_button()
{
if(!digitalRead(ENCODER_BTN))
{
delay(20);
if(!digitalRead(ENCODER_BTN))
{
while(!digitalRead(ENCODER_BTN));
return 1;
}
}
return 0;
}
/**************************************/
/* Displays the frequency */
/**************************************/
void display_frequency()
{
uint16_t f, g;
lcd.setCursor(3, 0);
f = frequency0 / 1000000;
if(f<10)
lcd.print(' ');
lcd.print(f);
lcd.print('.');
f = (frequency0 % 1000000)/1000;
if(f<100)
lcd.print('0');
if(f<10)
lcd.print('0');
lcd.print(f);
lcd.print('.');
f = frequency0 % 1000;
if(f<100)
lcd.print('0');
if(f<10)
lcd.print('0');
lcd.print(f);
lcd.print("Hz");
}
/**************************************/
/* Displays the frequency change step */
/**************************************/
void display_radix()
{
lcd.setCursor(10, 1);
switch(radix)
{
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.print("100k");
break;
case 1000000:
lcd.setCursor(9, 1);
lcd.print("1000k"); //1MHz increments
break;
}
lcd.print("Hz");
}
void setup()
{
lcd.begin(16, 2); // Initialize and clear the LCD
lcd.clear();
Wire.begin();
// Start serial and initialize the Si5351 with load capacitance and crystal freq
//0 will provide default freq of 25Mhz. If you have a 27MHz crystal put in 27000000
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0); //you could measure your crystal and put it here to correct for errors.
// Set CLK0 to output 10 MHz with a fixed PLL frequency
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
//set frequency with 1 Hz resolution
si5351.set_freq(frequency0 * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
pinMode(ENCODER_BTN, INPUT_PULLUP);
PCICR |= (1 << PCIE2); // Enable pin change interrupt for the encoder
PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
sei();
display_frequency(); // Update the display
display_radix();
}
void loop()
{
// Update the display if the frequency has been changed
if(changed_f)
{
display_frequency();
si5351.set_freq(frequency0 * SI5351_FREQ_MULT, 0, SI5351_CLK0);
changed_f = 0;
}
// Button press changes the frequency change step
if(get_button())
{
switch(radix)
{
case 10:
radix = 100;
break;
case 100:
radix = 1000;
break;
case 1000:
radix = 10000;
break;
case 10000:
radix = 100000;
break;
case 100000: //change these lines to tune in 1MHz increments
radix = 1000000;
break;
case 1000000:
radix = 10;
break;
}
display_radix();
}
}
This comment has been removed by the author.
ReplyDeleteHello Tom.
ReplyDeleteThank you for sharing your brilliant idea and your explanation that helped me a lot.
I would like some help to modify your design for LSB, USB and AM through two arduino port. example: H L = LSB.
L H = USB
H H = AM.
I am designing a receiver for amateur radio with a IF at 455 Khz
I'm grateful if you can help me.
neriosaewo Beth Johnson https://wakelet.com/wake/eT9bH3XFwdit7rzdqwR6v
ReplyDeletelamerere