#include <SPI.h>
#include <TM1637Display.h>
#include <si5351.h>
#include "LowPower.h"
const uint32_t bandStart = 7000000; // start of 80m
const uint32_t bandEnd = 7400000; // end of 80m
const uint32_t bandInit = 7025000; // where to initially set the frequency
volatile long oldfreq = 0;
volatile long currentfreq = 0;
volatile int currentTime = 0;
volatile int previousTime = 0;
volatile int elapsed = 0;
volatile int QSK_Timer = 1000;
int PTT = 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.
volatile uint32_t LSB_IF_freq = 9011500; // Crystal filter centre freq
volatile uint32_t LSB_BFO_freq = 9000000; // Crystal filter centre freq
// Rotary encoder pins and other inputs
static const int rotBPin = 2;
static const int rotAPin = 3;
static const int pushPin = 4;
static const int KeyInput = 7;
static const int PTTOutput = 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(KeyInput, INPUT);
pinMode(PTTOutput, OUTPUT);
// 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(KeyInput, HIGH);
digitalWrite(PTTOutput, 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);
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_8MA);
si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA);
si5351.set_freq(((8999300 + freq) * 100ULL), SI5351_PLL_FIXED, SI5351_CLK0);
si5351.set_freq((LSB_BFO_freq * 100ULL), SI5351_PLL_FIXED, SI5351_CLK2);
}
void loop()
{
//LowPower.idle(SLEEP_60MS, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART0_OFF, TWI_OFF);
LowPower.idle(SLEEP_60MS, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_ON, SPI_OFF, USART0_OFF, TWI_OFF);
if (digitalRead(KeyInput) == LOW)
{
si5351.output_enable(SI5351_CLK1, 1);
SendFrequency();
}
if (digitalRead(KeyInput) == HIGH)
{
si5351.output_enable(SI5351_CLK1, 0);
}
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()
{
// PA TX Drive
si5351.set_freq((freq * 100ULL), SI5351_PLL_FIXED, SI5351_CLK1);
// VFO
//si5351.set_freq((freq * 100ULL), SI5351_PLL_FIXED, SI5351_CLK0);
si5351.set_freq(((8999300 + freq) * 100ULL), SI5351_PLL_FIXED, SI5351_CLK0);
// BFO
si5351.set_freq((LSB_BFO_freq * 100ULL), SI5351_PLL_FIXED, SI5351_CLK2);
}