Last active
May 7, 2024 11:23
-
-
Save la3pna/1d7776801df77e5174fd to your computer and use it in GitHub Desktop.
Si5351 VFO with I2C display
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
VFO program for Si5351 | |
Using I2C LCD from: | |
http://www.amazon.com/Huhushop-TM-Serial-Display-Arduino/dp/B00JM88A94/ | |
Si5351 library from NT7S. | |
Uses the updated version of the library (master). | |
Display library is avaible from: | |
https://code.google.com/p/u8glib/ | |
UNO and 328 boards: Encoder on pin 2 and 3. Center pin to GND. | |
Leonardo: Encoder on pin 0 and 1. Center pin to GND. | |
100nF from each of the encoder pins to gnd is used to debounce | |
The pushbutton goes to pin 6 to set the tuning rate. | |
Pin 7 is the RX/TX pin. Put this pin LOW for RX, open or high for TX. | |
Single transistor switch to +RX will work. | |
VFO will NOT tune in TX. | |
In serial monitor, you can send "F"+frequency to set frequency. Ex: "F7063000" | |
IF frequency is positive for sum product (IF = RF + LO) and negative for diff (IF = RF - LO) | |
VFO signal output on CLK0, BFO signal on CLK2 | |
TODO: | |
* Write own OLED i2c library with optimizing for text to reduce size of compiled program. | |
*Add variable tuning resolution | |
*/ | |
volatile unsigned long frequency = 144100000; // This will be the frequency it always starts on. | |
long freqstep[] = {50, 100, 500, 1000, 5000, 10000}; // set this to your wanted tuning rate in Hz. | |
int corr = 120; // this is the correction factor for the Si5351, use calibration sketch to find value. | |
long iffreq = 0; // set the IF frequency in Hz. | |
#include "U8glib.h" | |
U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE); // I2C / TWI | |
String str; | |
char b[8]; | |
int inData; | |
boolean A_set = false; | |
boolean B_set = false; | |
unsigned int lastReportedPos = 1; // change management | |
static boolean rotating = false; // debounce management | |
#include <si5351.h> | |
#include "Wire.h" | |
Si5351 si5351; | |
// int encoderPinA ; | |
//int encoderPinB; | |
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) | |
int encoderPinA = 0; | |
int encoderPinB = 1; | |
#endif | |
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) | |
int encoderPinA = 2; | |
int encoderPinB = 3; | |
#endif | |
bool tx; | |
int txpin = 7; | |
int freqsteps = 1; | |
int bandbutton = 6; | |
#define arraylength (sizeof(freqstep) / sizeof(freqstep[0])) | |
void draw(void) { | |
// graphic commands to redraw the complete screen should be placed here | |
u8g.setFont(u8g_font_unifont); | |
// u8g.setFont(u8g_font_osb21); | |
u8g.drawStr( 0, 20, ltoa(frequency, b, 10)); | |
if (tx) | |
{ | |
u8g.drawStr( 100, 20, "TX" ); | |
} | |
} | |
void setup() | |
{ | |
// set the encoder to inputs | |
pinMode(encoderPinA, INPUT); | |
pinMode(encoderPinB, INPUT); | |
pinMode(txpin, INPUT); | |
pinMode(bandbutton, INPUT); | |
// turn on pullup resistors | |
digitalWrite(encoderPinA, HIGH); | |
digitalWrite(encoderPinB, HIGH); | |
digitalWrite(txpin, HIGH); | |
digitalWrite(bandbutton, HIGH ); | |
Serial.begin(9600); | |
// Initialize the Si5351 | |
// Change the 2nd parameter in init if using a ref osc other | |
// than 25 MHz | |
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0); | |
si5351.set_correction(corr); | |
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_4MA); | |
si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_4MA); | |
// assign default color value | |
if ( u8g.getMode() == U8G_MODE_R3G3B2 ) { | |
u8g.setColorIndex(255); // white | |
} | |
else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) { | |
u8g.setColorIndex(3); // max intensity | |
} | |
else if ( u8g.getMode() == U8G_MODE_BW ) { | |
u8g.setColorIndex(1); // pixel on | |
} | |
else if ( u8g.getMode() == U8G_MODE_HICOLOR ) { | |
u8g.setHiColorByRGB(255, 255, 255); | |
} | |
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) | |
encoderPinA = 0; | |
encoderPinB = 1; | |
//Code in here will only be compiled if an Arduino Leonardo is used. | |
// encoder pin on interrupt 2 (pin 0) | |
attachInterrupt(2, doEncoderA, CHANGE); | |
// encoder pin on interrupt 3 (pin 1) | |
attachInterrupt(3, doEncoderB, CHANGE); | |
#endif | |
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) | |
encoderPinA = 2; | |
encoderPinB = 3; | |
//Code in here will only be compiled if an Arduino Uno (or older) is used. | |
attachInterrupt(0, doEncoderA, CHANGE); | |
// encoder pin on interrupt 1 (pin 1) | |
attachInterrupt(1, doEncoderB, CHANGE); | |
#endif | |
} | |
void loop() | |
{ | |
tx = digitalRead(txpin); | |
rotating = true; // reset the debouncer | |
if ( lastReportedPos != frequency) { | |
lastReportedPos = frequency; | |
// Serial.print(frequency); // unncomment this to output frequency on change. | |
si5351.set_freq((frequency + iffreq) * 100ULL, 0, SI5351_CLK0); | |
} | |
if (digitalRead(bandbutton) == LOW ) { | |
delay(150); // delay to debounce | |
if (digitalRead(bandbutton) == LOW ) { | |
freqsteps = freqsteps + 1; | |
if (freqsteps > arraylength -1 ) { | |
freqsteps = 0; | |
} | |
delay(1000); //delay to avoid many steps at one | |
} | |
} | |
u8g.firstPage(); | |
do { | |
draw(); | |
} while ( u8g.nextPage() ); | |
// rebuild the picture after some delay | |
delay(50); | |
if (Serial.available() > 0) // see if incoming serial data: | |
{ | |
inData = Serial.read(); // read oldest byte in serial buffer: | |
} | |
if (inData == 'F') { | |
frequency = Serial.parseInt(); | |
inData = 0; | |
} | |
} | |
// Interrupt on A changing state | |
void doEncoderA() { | |
// debounce | |
if ( rotating ) delay (1); // wait a little until the bouncing is done | |
// Test transition, did things really change? | |
if ( digitalRead(encoderPinA) != A_set ) { // debounce once more | |
A_set = !A_set; | |
// adjust counter + if A leads B | |
if ( A_set && !B_set ) { | |
if (!tx) { | |
frequency += freqstep[freqsteps]; // hehre is the amount to increase the freq | |
} | |
rotating = false; // no more debouncing until loop() hits again | |
} | |
} | |
} | |
// Interrupt on B changing state, same as A above | |
void doEncoderB() { | |
if ( rotating ) delay (1); | |
if ( digitalRead(encoderPinB) != B_set ) { | |
B_set = !B_set; | |
// adjust counter - 1 if B leads A | |
if ( B_set && !A_set ) { | |
if (!tx) { | |
frequency -= freqstep[freqsteps]; // here is the amount to decrease the freq | |
} | |
rotating = false; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment