See YouTube for video log.
BPF
Ant Amplifier
IF Amp
#include <Wire.h>
#include <SPI.h>
#include <TM1637Display.h>
#include <si5351.h>
#include "LowPower.h"
const uint32_t bandStart = 14000000; // start of 20m
const uint32_t bandEnd = 14350000; // end of 20m
const uint32_t bandInit = 14100000; // where to initially set the frequency
volatile long currentfreq = 0;
volatile long oldfreq = 0;
volatile int currentmode = 0;
volatile int oldmode = 0;
volatile uint32_t freq = bandInit ; // this is a variable (changes) - set it to the beginning of the band
volatile uint32_t radix = 1000; // how much to change the frequency by, clicking the rotary encoder will change this.
const uint32_t BFO_freq = 8998450; // 8998450 = high side injection. For low side injection use 9001350;
// Rotary encoder pins and other inputs
static const int rotBPin = 2;
static const int rotAPin = 3;
static const int pushPin = 4;
static const int PTTInput = 8;
static const int brightnessPin = A3;
static const int tunespeedLED = A2;
static const int gnd = 10;
static const int vcc = 11;
static const int DIO = 12;
static const int CLK = 13;
// Rotary encoder variables, used by interrupt routines
volatile int rotState = 0;
volatile int rotAval = 1;
volatile int rotBval = 1;
volatile long remainder = 0;
volatile long OnesHz = 0;
volatile long TensHz = 0;
volatile long HundredsHz = 0;
volatile long OneskHz = 0;
volatile long TenskHz = 0;
volatile long HundredskHz = 0;
volatile long OnesMHz = 0;
volatile long TensMHz = 0;
volatile int Brightness = 3;
volatile int batterySave = 0;
// Instantiate the Objects
TM1637Display display(CLK, DIO); // CLK, DIO
Si5351 si5351;
void setup()
{
// Set up frequency and radix switches
pinMode(rotAPin, INPUT);
pinMode(rotBPin, INPUT);
pinMode(pushPin, INPUT);
pinMode(brightnessPin, INPUT);
pinMode(gnd, OUTPUT);
pinMode(tunespeedLED, OUTPUT);
pinMode(vcc, OUTPUT);
pinMode(PTTInput, INPUT);
// Set up pull-up resistors on inputs
digitalWrite(rotAPin, HIGH);
digitalWrite(rotBPin, HIGH);
digitalWrite(pushPin, HIGH);
digitalWrite(brightnessPin, HIGH);
digitalWrite(gnd, LOW);
digitalWrite(vcc, HIGH);
digitalWrite(tunespeedLED, LOW);
digitalWrite(PTTInput, LOW);
// Set up interrupt pins
attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE);
attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE);
// Initialize the display
display.setBrightness(Brightness, true);
UpdateDisplay();
delay(1000);
// Initialize the DDS
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
si5351.set_correction(87000, SI5351_PLL_INPUT_XO); // Set to specific Si5351 calibration number
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_2MA);
si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_2MA);
si5351.set_freq((freq * 100ULL), SI5351_CLK0);
si5351.set_freq((BFO_freq * 100ULL), SI5351_CLK2);
}
void loop()
{
LowPower.idle(SLEEP_60MS, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_ON, SPI_OFF, USART0_OFF, TWI_OFF);
currentmode = digitalRead(PTTInput);
if (currentmode != oldmode)
{
SendFrequency();
oldmode = currentmode;
}
currentfreq = getfreq(); // Interrupt safe method to get the current frequency
if (currentfreq != oldfreq)
{
UpdateDisplay();
SendFrequency();
oldfreq = currentfreq;
}
if (digitalRead(brightnessPin) == LOW)
{
Brightness--;
display.setBrightness(Brightness, true);
if (Brightness == -1)
{
display.setBrightness(0, false);
digitalWrite(tunespeedLED, LOW);
batterySave = 1;
}
if (Brightness == -2)
{
Brightness = 3;
batterySave = 0;
}
UpdateDisplay();
delay(500);
}
if ((radix == 100) && (batterySave == 0))
digitalWrite(tunespeedLED, HIGH);
if (radix == 1000)
digitalWrite(tunespeedLED, LOW);
}
void wakeUp()
{
// Just a handler for the sleep pin interrupt.
}
long getfreq()
{
long temp_freq;
cli();
temp_freq = freq;
sei();
return temp_freq;
}
// Interrupt routines
void ISRrotAChange()
{
if (digitalRead(rotAPin))
{
rotAval = 1;
UpdateRot();
}
else
{
rotAval = 0;
UpdateRot();
}
}
void ISRrotBChange()
{
if (digitalRead(rotBPin))
{
rotBval = 1;
UpdateRot();
}
else
{
rotBval = 0;
UpdateRot();
}
}
void UpdateRot()
{
switch (rotState)
{
case 0: // Idle state, look for direction
if (!rotBval)
rotState = 1; // CW 1
if (!rotAval)
rotState = 11; // CCW 1
break;
case 1: // CW, wait for A low while B is low
if (!rotBval)
{
if (!rotAval)
{
// either increment radixindex or freq
if (digitalRead(pushPin) == LOW)
{
if (radix == 1000)
radix = 100;
else if (radix == 100)
radix = 1000;
}
else
{
freq = (freq + radix);
if (freq > bandEnd)
freq = bandEnd;
}
rotState = 2; // CW 2
}
}
else if (rotAval)
rotState = 0; // It was just a glitch on B, go back to start
break;
case 2: // CW, wait for B high
if (rotBval)
rotState = 3; // CW 3
break;
case 3: // CW, wait for A high
if (rotAval)
rotState = 0; // back to idle (detent) state
break;
case 11: // CCW, wait for B low while A is low
if (!rotAval)
{
if (!rotBval)
{
// either decrement radixindex or freq
if (digitalRead(pushPin) == LOW)
{
if (radix == 100)
radix = 1000;
else if (radix == 1000)
radix = 100;
}
else
{
freq = (freq - radix);
if (freq < bandStart)
freq = bandStart;
}
rotState = 12; // CCW 2
}
}
else if (rotBval)
rotState = 0; // It was just a glitch on A, go back to start
break;
case 12: // CCW, wait for A high
if (rotAval)
rotState = 13; // CCW 3
break;
case 13: // CCW, wait for B high
if (rotBval)
rotState = 0; // back to idle (detent) state
break;
}
}
void UpdateDisplay()
{
TensMHz = freq / 10000000; // TensMHz = 12345678 / 10000000 = 1
remainder = freq - (TensMHz * 10000000); // remainder = 12345678 - 10000000 = 2345678
OnesMHz = remainder / 1000000; // OnesMhz = 2345678 / 1000000 = 2
remainder = remainder - (OnesMHz * 1000000); // remainder = 2345678 - (2 * 1000000) = 345678
HundredskHz = remainder / 100000; // HundredskHz = 345678 / 100000 = 3
remainder = remainder - (HundredskHz * 100000); // remainder = 345678 - (3 * 100000) = 45678
TenskHz = remainder / 10000; // TenskHz = 45678 / 10000 = 4
remainder = remainder - (TenskHz * 10000); // remainder = 45678 - (4 * 10000) = 5678
OneskHz = remainder / 1000; // OneskHz = 5678 / 1000 = 5
remainder = remainder - (OneskHz * 1000); // remainder = 5678 - (5 * 1000) = 678
HundredsHz = remainder / 100; // HundredsHz = 678 / 100 = 6
remainder = remainder - (HundredsHz * 100); // remainder = 678 - (6 * 100) = 78
TensHz = remainder / 10; // TensHz = 78 / 10 = 7
remainder = remainder - (TensHz * 10); // remainder = 78 - (7 * 10) = 8
OnesHz = remainder; // OnesHz = 8
display.showNumberDec(((1000 * HundredskHz) + ( 100 * TenskHz) + (10 * OneskHz) + HundredsHz), true);
}
void SendFrequency()
{
if (currentmode == 1) // Transmit
{
si5351.set_freq(((freq - BFO_freq + 50) * 100ULL), SI5351_CLK2);
si5351.set_freq((BFO_freq * 100ULL), SI5351_CLK0);
}
else // Receive
{
si5351.set_freq(((freq - BFO_freq + 50) * 100ULL), SI5351_CLK0);
si5351.set_freq((BFO_freq * 100ULL), SI5351_CLK2);
}
}