Skip to content

Instantly share code, notes, and snippets.

@peterbmarks
Created March 10, 2023 05:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peterbmarks/facebaa392e479db44e1bbb391418ed2 to your computer and use it in GitHub Desktop.
Save peterbmarks/facebaa392e479db44e1bbb391418ed2 to your computer and use it in GitHub Desktop.
Minimal VFO using Si5351
/*
Simple VFO for a direct conversion receiver.
Si5351 controlled by a rotary encoder.
Based on code from Paul, VK3HN
https://github.com/prt459/Arduino_si5351_VFO_Controller_Keyer
*/
const unsigned long int FREQ_DEFAULT = 7100000ULL;
#define ENCODER_A 3 // DT
#define ENCODER_B 2 // CLK
#include <RotaryEncoder.h> // by Maattias Hertel http://www.mathertel.de/Arduino/RotaryEncoderLibrary.aspx
#include <si5351.h> // Etherkit Si3531 library Jason Mildrum, V2.1.4
// https://github.com/etherkit/Si5351Arduino
#include <Wire.h> // built in
Si5351 si5351; // I2C address defaults to x60 in the NT7S lib
RotaryEncoder gEncoder = RotaryEncoder(ENCODER_A, ENCODER_B, RotaryEncoder::LatchMode::FOUR3);
long gEncoderPosition = 0;
unsigned long int gFrequency = FREQ_DEFAULT;
unsigned long int gStep = 100;
void setup() {
Serial.begin(115200);
Wire.begin();
gFrequency = FREQ_DEFAULT;
setupOscillator();
setupRotaryEncoder();
delay(500);
si5351.set_freq(FREQ_DEFAULT * SI5351_FREQ_MULT, SI5351_CLK0);
si5351.output_enable(SI5351_CLK0, 1);
}
void loop() {
// check for change in the rotary encoder
gEncoder.tick();
long newEncoderPosition = gEncoder.getPosition();
if(newEncoderPosition != gEncoderPosition) {
long encoderDifference = newEncoderPosition - gEncoderPosition;
gEncoderPosition = newEncoderPosition;
Serial.println(encoderDifference);
frequencyAdjust(encoderDifference);
}
}
void setupRotaryEncoder() {
attachInterrupt(digitalPinToInterrupt(ENCODER_A), checkPosition, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENCODER_B), checkPosition, CHANGE);
}
// This interrupt routine will be called on any change of one of the input signals
void checkPosition() {
gEncoder.tick(); // just call tick() to check the state.
}
void frequencyAdjust(int delta) {
Serial.print("Adjust: ");
Serial.println(delta);
gFrequency += (delta * gStep);
setVfoFrequency(gFrequency);
}
void setVfoFrequency(unsigned long int frequency) {
si5351.set_freq(frequency * SI5351_FREQ_MULT, SI5351_CLK0); //
Serial.print("set frequency: ");
Serial.println(frequency);
}
void setupOscillator() {
bool i2c_found = si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
Serial.print("si5351: ");
Serial.println(i2c_found ? "Found" : "Missing");
si5351.set_correction(135000, SI5351_PLL_INPUT_XO); // Library update 26/4/2020: requires destination register address ... si5351.set_correction(19100, SI5351_PLL_INPUT_XO);
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
si5351.set_freq(500000000ULL, SI5351_CLK0);
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_4MA);
si5351.output_enable(SI5351_CLK0, 1); // turn VFO on
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment