https://www.youtube.com/channel/UCSNPW3_gzuMJcX_ErBZTv2g
Antenna RF amplifer
Final configuration
Test Software for Phasing technique.
// Libraries
#include <Wire.h> // I2C comms library
#include <si5351.h> // Si5351Jason library
#include "ILI9341_t3.h"
#include <Audio.h> // Teensy audio library
#define NO_HILBERT_COEFFS 100 // Used to define the Hilbert transform filter arrays. More typical than 'const int'.
// Define Constants and Vaviables
static const long bandStart = 1000000; // start of HF band
static const long bandEnd = 30000000; // end of HF band
static const long bandInit = 3690000; // where to initially set the frequency
volatile long oldfreq = 0;
volatile long freq = bandInit ;
volatile long radix = 1000; // how much to change the frequency. Pushing the rotary encoder switch will change this.
volatile long oldradix = 1;
volatile int updatedisplay = 0;
volatile int mode = 1; // 1 = LSB, 0 = USB
volatile int oldmode = 0;
volatile int Even_Divisor = 0;
volatile int oldEven_Divisor = 0;
// Audio panel gains
static const int Linein_Gain = 10; // Range is 0-15. 0 = 3.12 Vp-p, 15 = 0.24 Vp-p. Default = 5
// Rotary Encoder
static const int EncoderPushButton = 39;
static const int rotBPin = 36;
static const int rotAPin = 35;
static const int ModeSwitch = 24;
static const int PTTSwitch = 25;
volatile int rotState = 0;
volatile int rotAval = 1;
volatile int rotBval = 1;
volatile int rotAcc = 0;
// For optimized ILI9341_t3 library
#define TFT_DC 20
#define TFT_CS 21
#define TFT_RST 255 // 255 = unused, connect to 3.3V
#define TFT_MOSI 7
#define TFT_SCLK 14
#define TFT_MISO 12
// Iowa Hills Hilbert transform filter coefficients
const short Hilbert_Plus_45_Coeffs[NO_HILBERT_COEFFS] = {
(short)(32768 * 483.9743406915770E-9),
(short)(32768 * 1.866685817417670E-6),
(short)(32768 * 4.392570072495770E-6),
(short)(32768 * 8.820636712774380E-6),
(short)(32768 * 0.000016184764415848),
(short)(32768 * 0.000027249288101724),
(short)(32768 * 0.000041920439805110),
(short)(32768 * 0.000059016345361008),
(short)(32768 * 0.000076756191268614),
(short)(32768 * 0.000094055071776657),
(short)(32768 * 0.000112261583662573),
(short)(32768 * 0.000136518354793722),
(short)(32768 * 0.000175696544399550),
(short)(32768 * 0.000240067250940666),
(short)(32768 * 0.000336609833081347),
(short)(32768 * 0.000462990951098187),
(short)(32768 * 0.000602421399161912),
(short)(32768 * 0.000722301614841713),
(short)(32768 * 0.000779305755125654),
(short)(32768 * 0.000732056920489209),
(short)(32768 * 0.000559948250896998),
(short)(32768 * 0.000283585816755988),
(short)(32768 * -0.000020215761694049),
(short)(32768 * -0.000216819118897174),
(short)(32768 * -0.000131758715732279),
(short)(32768 * 0.000409948902196685),
(short)(32768 * 0.001528130963104050),
(short)(32768 * 0.003227564604759798),
(short)(32768 * 0.005351504118228274),
(short)(32768 * 0.007567804706902511),
(short)(32768 * 0.009402820162611196),
(short)(32768 * 0.010328512135999630),
(short)(32768 * 0.009894246835039863),
(short)(32768 * 0.007879714166593881),
(short)(32768 * 0.004433421126740721),
(short)(32768 * 0.000156366633965185),
(short)(32768 * -0.003904389468521576),
(short)(32768 * -0.006371988171406650),
(short)(32768 * -0.005761887634323113),
(short)(32768 * -0.000778938771957753),
(short)(32768 * 0.009365085367419172),
(short)(32768 * 0.024681757404317366),
(short)(32768 * 0.044251382160327521),
(short)(32768 * 0.066233642104189930),
(short)(32768 * 0.088062621169129954),
(short)(32768 * 0.106806616459214951),
(short)(32768 * 0.119635362035632908),
(short)(32768 * 0.124309482163432433),
(short)(32768 * 0.119596382589365807),
(short)(32768 * 0.105526834497225247),
(short)(32768 * 0.083435851600156402),
(short)(32768 * 0.055774084237545388),
(short)(32768 * 0.025722508803868269),
(short)(32768 * -0.003316774367731974),
(short)(32768 * -0.028256325810852603),
(short)(32768 * -0.046784860848984686),
(short)(32768 * -0.057671422122216751),
(short)(32768 * -0.060863961385426720),
(short)(32768 * -0.057377469068775784),
(short)(32768 * -0.049008885222883866),
(short)(32768 * -0.037947605693328487),
(short)(32768 * -0.026365178611104038),
(short)(32768 * -0.016063741251826878),
(short)(32768 * -0.008242320709669780),
(short)(32768 * -0.003409329314875374),
(short)(32768 * -0.001436295024424050),
(short)(32768 * -0.001719754923178513),
(short)(32768 * -0.003400970055132929),
(short)(32768 * -0.005589187214751837),
(short)(32768 * -0.007542651980327935),
(short)(32768 * -0.008778747041127889),
(short)(32768 * -0.009105231860961261),
(short)(32768 * -0.008583286966676333),
(short)(32768 * -0.007445876442758468),
(short)(32768 * -0.005999873442098177),
(short)(32768 * -0.004537732597630097),
(short)(32768 * -0.003276341625911221),
(short)(32768 * -0.002330120643710241),
(short)(32768 * -0.001715559019593159),
(short)(32768 * -0.001377498498508186),
(short)(32768 * -0.001224659509681699),
(short)(32768 * -0.001162953813794283),
(short)(32768 * -0.001118850197066992),
(short)(32768 * -0.001049829425495061),
(short)(32768 * -0.000943240226180188),
(short)(32768 * -0.000807608474652057),
(short)(32768 * -0.000661296218869203),
(short)(32768 * -0.000522622836450865),
(short)(32768 * -0.000403818527830429),
(short)(32768 * -0.000309261220275339),
(short)(32768 * -0.000236981246010256),
(short)(32768 * -0.000181726899678497),
(short)(32768 * -0.000137960767232952),
(short)(32768 * -0.000101749677323657),
(short)(32768 * -0.000071268112804006),
(short)(32768 * -0.000046246069278189),
(short)(32768 * -0.000026984224473470),
(short)(32768 * -0.000013519855860183),
(short)(32768 * -5.268419079329310E-6),
(short)(32768 * -1.152120275972750E-6)
};
// Iowa Hills Hilbert transform filter coefficients
const short Hilbert_Minus_45_Coeffs[NO_HILBERT_COEFFS] = {
(short)(32768 * -1.152120275972720E-6),
(short)(32768 * -5.268419079329100E-6),
(short)(32768 * -0.000013519855860182),
(short)(32768 * -0.000026984224473469),
(short)(32768 * -0.000046246069278187),
(short)(32768 * -0.000071268112804004),
(short)(32768 * -0.000101749677323656),
(short)(32768 * -0.000137960767232950),
(short)(32768 * -0.000181726899678496),
(short)(32768 * -0.000236981246010254),
(short)(32768 * -0.000309261220275334),
(short)(32768 * -0.000403818527830420),
(short)(32768 * -0.000522622836450852),
(short)(32768 * -0.000661296218869189),
(short)(32768 * -0.000807608474652046),
(short)(32768 * -0.000943240226180185),
(short)(32768 * -0.001049829425495072),
(short)(32768 * -0.001118850197067017),
(short)(32768 * -0.001162953813794315),
(short)(32768 * -0.001224659509681719),
(short)(32768 * -0.001377498498508169),
(short)(32768 * -0.001715559019593075),
(short)(32768 * -0.002330120643710066),
(short)(32768 * -0.003276341625910951),
(short)(32768 * -0.004537732597629757),
(short)(32768 * -0.005999873442097817),
(short)(32768 * -0.007445876442758181),
(short)(32768 * -0.008583286966676212),
(short)(32768 * -0.009105231860961396),
(short)(32768 * -0.008778747041128323),
(short)(32768 * -0.007542651980328638),
(short)(32768 * -0.005589187214752684),
(short)(32768 * -0.003400970055133710),
(short)(32768 * -0.001719754923178943),
(short)(32768 * -0.001436295024423829),
(short)(32768 * -0.003409329314874256),
(short)(32768 * -0.008242320709667652),
(short)(32768 * -0.016063741251823811),
(short)(32768 * -0.026365178611100354),
(short)(32768 * -0.037947605693324706),
(short)(32768 * -0.049008885222880681),
(short)(32768 * -0.057377469068773987),
(short)(32768 * -0.060863961385426962),
(short)(32768 * -0.057671422122219533),
(short)(32768 * -0.046784860848990188),
(short)(32768 * -0.028256325810860565),
(short)(32768 * -0.003316774367741772),
(short)(32768 * 0.025722508803857579),
(short)(32768 * 0.055774084237534945),
(short)(32768 * 0.083435851600147395),
(short)(32768 * 0.105526834497218600),
(short)(32768 * 0.119596382589362227),
(short)(32768 * 0.124309482163432142),
(short)(32768 * 0.119635362035635753),
(short)(32768 * 0.106806616459220294),
(short)(32768 * 0.088062621169136893),
(short)(32768 * 0.066233642104197507),
(short)(32768 * 0.044251382160334737),
(short)(32768 * 0.024681757404323448),
(short)(32768 * 0.009365085367423625),
(short)(32768 * -0.000778938771955104),
(short)(32768 * -0.005761887634322139),
(short)(32768 * -0.006371988171407000),
(short)(32768 * -0.003904389468522771),
(short)(32768 * 0.000156366633963640),
(short)(32768 * 0.004433421126739255),
(short)(32768 * 0.007879714166592786),
(short)(32768 * 0.009894246835039278),
(short)(32768 * 0.010328512135999562),
(short)(32768 * 0.009402820162611529),
(short)(32768 * 0.007567804706903086),
(short)(32768 * 0.005351504118228925),
(short)(32768 * 0.003227564604760380),
(short)(32768 * 0.001528130963104480),
(short)(32768 * 0.000409948902196933),
(short)(32768 * -0.000131758715732195),
(short)(32768 * -0.000216819118897210),
(short)(32768 * -0.000020215761694147),
(short)(32768 * 0.000283585816755878),
(short)(32768 * 0.000559948250896909),
(short)(32768 * 0.000732056920489157),
(short)(32768 * 0.000779305755125639),
(short)(32768 * 0.000722301614841724),
(short)(32768 * 0.000602421399161936),
(short)(32768 * 0.000462990951098213),
(short)(32768 * 0.000336609833081367),
(short)(32768 * 0.000240067250940678),
(short)(32768 * 0.000175696544399555),
(short)(32768 * 0.000136518354793723),
(short)(32768 * 0.000112261583662573),
(short)(32768 * 0.000094055071776658),
(short)(32768 * 0.000076756191268616),
(short)(32768 * 0.000059016345361010),
(short)(32768 * 0.000041920439805112),
(short)(32768 * 0.000027249288101726),
(short)(32768 * 0.000016184764415849),
(short)(32768 * 8.820636712774440E-6),
(short)(32768 * 4.392570072495580E-6),
(short)(32768 * 1.866685817417500E-6),
(short)(32768 * 483.9743406915230E-9)
};
// Instantiate the Objects
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);
Si5351 si5351; // Name for the Si5351 DDS
AudioControlSGTL5000 audioShield; // Name for the Teensy audio CODEC on the audio shield
// Audio shield
AudioInputI2S audioInput; // Name for the input to the audio shield (either line-in or mic)
AudioOutputI2S audioOutput; // Name for the output of the audio shield (either headphones or line-out)
// Receiver
AudioFilterFIR RX_Hilbert_Plus_45; // Name for the RX +45 Hilbert transform
AudioFilterFIR RX_Hilbert_Minus_45; // Name for the RX +45 Hilbert transform
AudioMixer4 RX_Summer; // Name for the RX summer
// Audio connections
AudioConnection patchCord5(audioInput, 0, RX_Hilbert_Plus_45, 0); // Left channel in Hilbert transform +45
AudioConnection patchCord10(audioInput, 1, RX_Hilbert_Minus_45, 0); // Right channel in Hilbert transform -45
AudioConnection patchCord15(RX_Hilbert_Plus_45, 0, RX_Summer, 0); // Hilbert transform +45 to receiver summer
AudioConnection patchCord20(RX_Hilbert_Minus_45, 0, RX_Summer, 1); // Hilbert transform -45 to receiver summer
AudioConnection patchCord25(RX_Summer, 0, audioOutput, 0);
AudioConnection patchCord30(RX_Summer, 0, audioOutput, 1);
void setup()
{
// Setup screen
tft.begin();
tft.setRotation(1);
tft.fillScreen(ILI9341_BLACK);
tft.drawRect(31, 0, 257, 37, ILI9341_YELLOW);
tft.drawRect(31, 36, 257, 103, ILI9341_YELLOW);
tft.drawRect(31, 138, 257, 102, ILI9341_YELLOW);
// Setup input switches
pinMode(rotAPin, INPUT);
pinMode(rotBPin, INPUT);
pinMode(EncoderPushButton, INPUT);
pinMode(ModeSwitch, INPUT);
digitalWrite(rotAPin, HIGH);
digitalWrite(rotBPin, HIGH);
digitalWrite(EncoderPushButton, HIGH);
digitalWrite(ModeSwitch, HIGH);
// Setup interrupt pins
attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE);
attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE);
// Initialize the DDS
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0); // 25MHz crystal = 0, 27MHz crystal = 27000000
si5351.set_correction(62799, SI5351_PLL_INPUT_XO); // Set to specific Si5351 calibration number
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_6MA);
si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_6MA);
si5351.set_freq_manual(freq * SI5351_FREQ_MULT, Even_Divisor * freq * SI5351_FREQ_MULT, SI5351_CLK0);
si5351.set_freq_manual(freq * SI5351_FREQ_MULT, Even_Divisor * freq * SI5351_FREQ_MULT, SI5351_CLK1);
si5351.set_phase(SI5351_CLK0, 0);
si5351.set_phase(SI5351_CLK1, Even_Divisor);
si5351.pll_reset(SI5351_PLLA);
// Setup the audio shield
AudioNoInterrupts();
AudioMemory(12);
audioShield.enable();
AudioInterrupts();
// Setup transceiver mode
Turn_On_Receiver();
UpdateDisplay();
}
void loop()
{
if (freq != oldfreq) // Check to see if the frequency has changed. If so, update everything.
{
EvenDivisor();
UpdateDisplay();
SendFrequency();
oldfreq = freq;
}
if (digitalRead(EncoderPushButton) == LOW) // Update cursor, but also stop it from flickering
{
delay(50);
while (digitalRead(EncoderPushButton) == LOW)
{
if (updatedisplay == 1)
{
UpdateDisplay();
updatedisplay = 0;
}
}
delay(50);
}
}
void Turn_On_Receiver()
{
AudioNoInterrupts();
audioShield.inputSelect(AUDIO_INPUT_LINEIN);
audioShield.lineInLevel(Linein_Gain);
audioShield.unmuteHeadphone(); // Output to the audio amplifier
audioShield.volume(0.7);
RX_Hilbert_Plus_45.begin(Hilbert_Plus_45_Coeffs, NO_HILBERT_COEFFS);
RX_Hilbert_Minus_45.begin(Hilbert_Minus_45_Coeffs, NO_HILBERT_COEFFS);
RX_Summer.gain(0, 1);
RX_Summer.gain(1, -1);
AudioInterrupts();
}
// 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(EncoderPushButton) == LOW)
{
updatedisplay = 1;
if (radix == 1000000)
radix = 100000;
else if (radix == 100000)
radix = 10000;
else if (radix == 10000)
radix = 1000;
else if (radix == 1000)
radix = 100;
else if (radix == 100)
radix = 10;
else if (radix == 10)
radix = 1;
else
radix = 1000000;
}
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(EncoderPushButton) == LOW)
{
updatedisplay = 1;
if (radix == 1)
radix = 10;
else if (radix == 10)
radix = 100;
else if (radix == 100)
radix = 1000;
else if (radix == 1000)
radix = 10000;
else if (radix == 10000)
radix = 100000;
else if (radix == 100000)
radix = 1000000;
else
radix = 1;
}
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()
{
tft.setTextSize(2);
tft.setCursor(50, 10);
tft.setTextColor(ILI9341_BLACK);
tft.println(oldfreq);
tft.setCursor(50, 10);
tft.setTextColor(ILI9341_WHITE);
tft.println(freq);
if (radix != oldradix) // stops radix display flashing/blinking on freq change
{
tft.setCursor(170, 10);
tft.setTextColor(ILI9341_BLACK);
if (oldradix == 1)
tft.print(" 1 Hz");
if (oldradix == 10)
tft.print(" 10 Hz");
if (oldradix == 100)
tft.print(" 100 Hz");
if (oldradix == 1000)
tft.print(" 1 kHz");
if (oldradix == 10000)
tft.print(" 10 kHz");
if (oldradix == 100000)
tft.print("100 kHz");
if (oldradix == 1000000)
tft.print(" 1 MHz");
tft.setCursor(170, 10);
tft.setTextColor(ILI9341_WHITE);
if (radix == 1)
tft.print(" 1 Hz");
if (radix == 10)
tft.print(" 10 Hz");
if (radix == 100)
tft.print(" 100 Hz");
if (radix == 1000)
tft.print(" 1 kHz");
if (radix == 10000)
tft.print(" 10 kHz");
if (radix == 100000)
tft.print("100 kHz");
if (radix == 1000000)
tft.print(" 1 MHz");
oldradix = radix;
}
}
void EvenDivisor()
{
if (freq < 6850000)
{
Even_Divisor = 126;
}
if ((freq >= 6850000) && (freq < 9500000))
{
Even_Divisor = 88;
}
if ((freq >= 9500000) && (freq < 13600000))
{
Even_Divisor = 64;
}
if ((freq >= 13600000) && (freq < 17500000))
{
Even_Divisor = 44;
}
if ((freq >= 17500000) && (freq < 25000000))
{
Even_Divisor = 34;
}
if ((freq >= 25000000) && (freq < 36000000))
{
Even_Divisor = 24;
}
if ((freq >= 36000000) && (freq < 45000000)) {
Even_Divisor = 18;
}
if ((freq >= 45000000) && (freq < 60000000)) {
Even_Divisor = 14;
}
if ((freq >= 60000000) && (freq < 80000000)) {
Even_Divisor = 10;
}
if ((freq >= 80000000) && (freq < 100000000)) {
Even_Divisor = 8;
}
if ((freq >= 100000000) && (freq < 146600000)) {
Even_Divisor = 6;
}
if ((freq >= 150000000) && (freq < 220000000)) {
Even_Divisor = 4;
}
}
void SendFrequency()
{
//freq = freq + 10;
si5351.set_freq_manual(freq * SI5351_FREQ_MULT, Even_Divisor * freq * SI5351_FREQ_MULT, SI5351_CLK0);
si5351.set_freq_manual(freq * SI5351_FREQ_MULT, Even_Divisor * freq * SI5351_FREQ_MULT, SI5351_CLK1);
si5351.set_phase(SI5351_CLK0, 0);
si5351.set_phase(SI5351_CLK1, Even_Divisor);
if (Even_Divisor != oldEven_Divisor)
{
si5351.pll_reset(SI5351_PLLA);
oldEven_Divisor = Even_Divisor;
}
}
***********************************************
Test software for Weaver technique.
// Libraries
#include <Wire.h> // I2C comms library
#include <si5351.h> // Si5351Jason library
#include "ILI9341_t3.h"
#include <Audio.h> // Teensy audio library
#define NO_LPF_COEFFS 100 // Used to define the Hilbert transform filter arrays. More typical than 'const int'.
int Osc_freq = 1350;
// Define Constants and Vaviables
static const long bandStart = 1000000; // start of HF band
static const long bandEnd = 30000000; // end of HF band
static const long bandInit = 3690000 - 1350; // where to initially set the frequency
volatile long oldfreq = 0;
volatile long freq = bandInit;
volatile long dispfreq = 0;
volatile long olddispfreq = 0;
volatile long radix = 1000; // how much to change the frequency. Pushing the rotary encoder switch will change this.
volatile long oldradix = 1;
volatile int updatedisplay = 0;
volatile int mode = 1; // 1 = LSB, 0 = USB
volatile int oldmode = 0;
volatile int Even_Divisor = 0;
volatile int oldEven_Divisor = 0;
// Audio panel gains
static const int Linein_Gain = 10; // Range is 0-15. 0 = 3.12 Vp-p, 15 = 0.24 Vp-p. Default = 5
// Rotary Encoder
static const int EncoderPushButton = 39;
static const int rotBPin = 36;
static const int rotAPin = 35;
static const int ModeSwitch = 24;
static const int PTTSwitch = 25;
volatile int rotState = 0;
volatile int rotAval = 1;
volatile int rotBval = 1;
volatile int rotAcc = 0;
// For optimized ILI9341_t3 library
#define TFT_DC 20
#define TFT_CS 21
#define TFT_RST 255 // 255 = unused, connect to 3.3V
#define TFT_MOSI 7
#define TFT_SCLK 14
#define TFT_MISO 12
// Iowa Hills LPF filter coefficients
const short LPF_Coeffs[NO_LPF_COEFFS] = {
(short)(32768 * 306.4951185627353420E-9),
(short)(32768 * 2.389304478278580830E-6),
(short)(32768 * 7.113585052311595550E-6),
(short)(32768 * 14.72828307076125930E-6),
(short)(32768 * 24.58848420405347920E-6),
(short)(32768 * 35.02666821312011080E-6),
(short)(32768 * 43.43839783397800150E-6),
(short)(32768 * 46.61576513715636590E-6),
(short)(32768 * 41.31600135178678100E-6),
(short)(32768 * 24.99939715244948960E-6),
(short)(32768 * -3.381010660280591830E-6),
(short)(32768 * -42.69541258485239870E-6),
(short)(32768 * -89.23441801688076680E-6),
(short)(32768 * -136.7515827038860440E-6),
(short)(32768 * -177.0704045420265800E-6),
(short)(32768 * -201.2975885521037750E-6),
(short)(32768 * -201.5817136692013490E-6),
(short)(32768 * -173.2410096718713530E-6),
(short)(32768 * -116.9727242504059600E-6),
(short)(32768 * -40.76876611355810100E-6),
(short)(32768 * 38.88327362518843700E-6),
(short)(32768 * 96.92273299774292640E-6),
(short)(32768 * 101.0929496871475240E-6),
(short)(32768 * 14.95903728424654490E-6),
(short)(32768 * -197.4484620824715080E-6),
(short)(32768 * -565.6166584117947880E-6),
(short)(32768 * -0.001105659124309112),
(short)(32768 * -0.001813271033445281),
(short)(32768 * -0.002657413489625704),
(short)(32768 * -0.003575681889777568),
(short)(32768 * -0.004472272286104596),
(short)(32768 * -0.005219295852277327),
(short)(32768 * -0.005661909790021988),
(short)(32768 * -0.005627354513012373),
(short)(32768 * -0.004937547773786580),
(short)(32768 * -0.003424434146231942),
(short)(32768 * -946.8768746362549110E-6),
(short)(32768 * 0.002592437620492790),
(short)(32768 * 0.007231787528579316),
(short)(32768 * 0.012938601156477677),
(short)(32768 * 0.019602556730010448),
(short)(32768 * 0.027034742068844295),
(short)(32768 * 0.034973496032183256),
(short)(32768 * 0.043096926615698458),
(short)(32768 * 0.051041434503589389),
(short)(32768 * 0.058424937851007025),
(short)(32768 * 0.064872965661608481),
(short)(32768 * 0.070045425749411874),
(short)(32768 * 0.073661704425816404),
(short)(32768 * 0.075521841389624714),
(short)(32768 * 0.075521841389624714),
(short)(32768 * 0.073661704425816404),
(short)(32768 * 0.070045425749411874),
(short)(32768 * 0.064872965661608481),
(short)(32768 * 0.058424937851007025),
(short)(32768 * 0.051041434503589389),
(short)(32768 * 0.043096926615698458),
(short)(32768 * 0.034973496032183256),
(short)(32768 * 0.027034742068844295),
(short)(32768 * 0.019602556730010448),
(short)(32768 * 0.012938601156477677),
(short)(32768 * 0.007231787528579316),
(short)(32768 * 0.002592437620492790),
(short)(32768 * -946.8768746362549110E-6),
(short)(32768 * -0.003424434146231942),
(short)(32768 * -0.004937547773786580),
(short)(32768 * -0.005627354513012373),
(short)(32768 * -0.005661909790021988),
(short)(32768 * -0.005219295852277327),
(short)(32768 * -0.004472272286104596),
(short)(32768 * -0.003575681889777568),
(short)(32768 * -0.002657413489625704),
(short)(32768 * -0.001813271033445281),
(short)(32768 * -0.001105659124309112),
(short)(32768 * -565.6166584117947880E-6),
(short)(32768 * -197.4484620824715080E-6),
(short)(32768 * 14.95903728424654490E-6),
(short)(32768 * 101.0929496871475240E-6),
(short)(32768 * 96.92273299774292640E-6),
(short)(32768 * 38.88327362518843700E-6),
(short)(32768 * -40.76876611355810100E-6),
(short)(32768 * -116.9727242504059600E-6),
(short)(32768 * -173.2410096718713530E-6),
(short)(32768 * -201.5817136692013490E-6),
(short)(32768 * -201.2975885521037750E-6),
(short)(32768 * -177.0704045420265800E-6),
(short)(32768 * -136.7515827038860440E-6),
(short)(32768 * -89.23441801688076680E-6),
(short)(32768 * -42.69541258485239870E-6),
(short)(32768 * -3.381010660280591830E-6),
(short)(32768 * 24.99939715244948960E-6),
(short)(32768 * 41.31600135178678100E-6),
(short)(32768 * 46.61576513715636590E-6),
(short)(32768 * 43.43839783397800150E-6),
(short)(32768 * 35.02666821312011080E-6),
(short)(32768 * 24.58848420405347920E-6),
(short)(32768 * 14.72828307076125930E-6),
(short)(32768 * 7.113585052311595550E-6),
(short)(32768 * 2.389304478278580830E-6),
(short)(32768 * 306.4951185627353420E-9)
};
// Instantiate the Objects
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);
Si5351 si5351; // Name for the Si5351 DDS
AudioControlSGTL5000 audioShield; // Name for the Teensy audio CODEC on the audio shield
// Audio shield
AudioInputI2S audioInput; // Name for the input to the audio shield (either line-in or mic)
AudioOutputI2S audioOutput; // Name for the output of the audio shield (either headphones or line-out)
// Receiver
AudioFilterFIR RX_I_LPF; // Name for the RX LPF
AudioFilterFIR RX_Q_LPF; // Name for the RX LPF
AudioEffectMultiply RX_I_Mixer;
AudioEffectMultiply RX_Q_Mixer;
AudioSynthWaveform RX_I_Osc;
AudioSynthWaveform RX_Q_Osc;
AudioMixer4 RX_Summer; // Name for the RX summer
//Audio connections
AudioConnection patchCord5(audioInput, 0, RX_I_LPF, 0);
AudioConnection patchCord10(audioInput, 1, RX_Q_LPF, 0);
AudioConnection patchCord15(RX_I_LPF, 0, RX_I_Mixer, 0);
AudioConnection patchCord20(RX_Q_LPF, 0, RX_Q_Mixer, 0);
AudioConnection patchCord25(RX_I_Osc, 0, RX_I_Mixer, 1); // Left channel in Hilbert transform +45
AudioConnection patchCord30(RX_Q_Osc, 0, RX_Q_Mixer, 1); // Right channel in Hilbert transform -45
AudioConnection patchCord35(RX_I_Mixer, 0, RX_Summer, 0); // Hilbert transform +45 to receiver summer
AudioConnection patchCord40(RX_Q_Mixer, 0, RX_Summer, 1); // Hilbert transform -45 to receiver summer
AudioConnection patchCord45(RX_Summer, 0, audioOutput, 0);
AudioConnection patchCord50(RX_Summer, 0, audioOutput, 1);
void setup()
{
// Setup screen
tft.begin();
tft.setRotation(1);
tft.fillScreen(ILI9341_BLACK);
tft.drawRect(31, 0, 257, 37, ILI9341_YELLOW);
tft.drawRect(31, 36, 257, 103, ILI9341_YELLOW);
tft.drawRect(31, 138, 257, 102, ILI9341_YELLOW);
// Setup input switches
pinMode(rotAPin, INPUT);
pinMode(rotBPin, INPUT);
pinMode(EncoderPushButton, INPUT);
pinMode(ModeSwitch, INPUT);
digitalWrite(rotAPin, HIGH);
digitalWrite(rotBPin, HIGH);
digitalWrite(EncoderPushButton, HIGH);
digitalWrite(ModeSwitch, HIGH);
// Setup interrupt pins
attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE);
attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE);
// Initialize the DDS
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0); // 25MHz crystal = 0, 27MHz crystal = 27000000
si5351.set_correction(62799, SI5351_PLL_INPUT_XO); // Set to specific Si5351 calibration number
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_6MA);
si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_6MA);
si5351.set_freq_manual(freq * SI5351_FREQ_MULT, Even_Divisor * freq * SI5351_FREQ_MULT, SI5351_CLK0);
si5351.set_freq_manual(freq * SI5351_FREQ_MULT, Even_Divisor * freq * SI5351_FREQ_MULT, SI5351_CLK1);
si5351.set_phase(SI5351_CLK0, 0);
si5351.set_phase(SI5351_CLK1, Even_Divisor);
si5351.pll_reset(SI5351_PLLA);
// Setup the audio shield
AudioNoInterrupts();
AudioMemory(16);
audioShield.enable();
AudioInterrupts();
// Setup transceiver mode
Turn_On_Receiver();
UpdateDisplay();
}
void loop()
{
if (freq != oldfreq) // Check to see if the frequency has changed. If so, update everything.
{
EvenDivisor();
SendFrequency();
UpdateDisplay();
oldfreq = freq;
}
if (digitalRead(EncoderPushButton) == LOW) // Update cursor, but also stop it from flickering
{
delay(50);
while (digitalRead(EncoderPushButton) == LOW)
{
if (updatedisplay == 1)
{
UpdateDisplay();
updatedisplay = 0;
}
}
delay(50);
}
}
void Turn_On_Receiver()
{
AudioNoInterrupts();
audioShield.inputSelect(AUDIO_INPUT_LINEIN);
audioShield.lineInLevel(Linein_Gain);
audioShield.unmuteHeadphone(); // Output to the audio amplifier
audioShield.volume(0.7);
RX_I_LPF.begin(LPF_Coeffs, NO_LPF_COEFFS);
RX_Q_LPF.begin(LPF_Coeffs, NO_LPF_COEFFS);
RX_I_Osc.frequency(Osc_freq);
RX_I_Osc.amplitude(1);
RX_I_Osc.phase(0);
RX_Q_Osc.frequency(Osc_freq);
RX_Q_Osc.amplitude(1);
RX_Q_Osc.phase(90);
RX_Summer.gain(0, 1);
RX_Summer.gain(1, -1);
AudioInterrupts();
}
// 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(EncoderPushButton) == LOW)
{
updatedisplay = 1;
if (radix == 1000000)
radix = 100000;
else if (radix == 100000)
radix = 10000;
else if (radix == 10000)
radix = 1000;
else if (radix == 1000)
radix = 100;
else if (radix == 100)
radix = 10;
else if (radix == 10)
radix = 1;
else
radix = 1000000;
}
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(EncoderPushButton) == LOW)
{
updatedisplay = 1;
if (radix == 1)
radix = 10;
else if (radix == 10)
radix = 100;
else if (radix == 100)
radix = 1000;
else if (radix == 1000)
radix = 10000;
else if (radix == 10000)
radix = 100000;
else if (radix == 100000)
radix = 1000000;
else
radix = 1;
}
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()
{
dispfreq = freq + 1350;
tft.setTextSize(2);
tft.setCursor(50, 10);
tft.setTextColor(ILI9341_BLACK);
tft.println(olddispfreq);
tft.setCursor(50, 10);
tft.setTextColor(ILI9341_WHITE);
tft.println(dispfreq);
olddispfreq = dispfreq;
if (radix != oldradix) // stops radix display flashing/blinking on freq change
{
tft.setCursor(170, 10);
tft.setTextColor(ILI9341_BLACK);
if (oldradix == 1)
tft.print(" 1 Hz");
if (oldradix == 10)
tft.print(" 10 Hz");
if (oldradix == 100)
tft.print(" 100 Hz");
if (oldradix == 1000)
tft.print(" 1 kHz");
if (oldradix == 10000)
tft.print(" 10 kHz");
if (oldradix == 100000)
tft.print("100 kHz");
if (oldradix == 1000000)
tft.print(" 1 MHz");
tft.setCursor(170, 10);
tft.setTextColor(ILI9341_WHITE);
if (radix == 1)
tft.print(" 1 Hz");
if (radix == 10)
tft.print(" 10 Hz");
if (radix == 100)
tft.print(" 100 Hz");
if (radix == 1000)
tft.print(" 1 kHz");
if (radix == 10000)
tft.print(" 10 kHz");
if (radix == 100000)
tft.print("100 kHz");
if (radix == 1000000)
tft.print(" 1 MHz");
oldradix = radix;
}
}
void EvenDivisor()
{
if (freq < 6850000)
{
Even_Divisor = 126;
}
if ((freq >= 6850000) && (freq < 9500000))
{
Even_Divisor = 88;
}
if ((freq >= 9500000) && (freq < 13600000))
{
Even_Divisor = 64;
}
if ((freq >= 13600000) && (freq < 17500000))
{
Even_Divisor = 44;
}
if ((freq >= 17500000) && (freq < 25000000))
{
Even_Divisor = 34;
}
if ((freq >= 25000000) && (freq < 36000000))
{
Even_Divisor = 24;
}
if ((freq >= 36000000) && (freq < 45000000)) {
Even_Divisor = 18;
}
if ((freq >= 45000000) && (freq < 60000000)) {
Even_Divisor = 14;
}
if ((freq >= 60000000) && (freq < 80000000)) {
Even_Divisor = 10;
}
if ((freq >= 80000000) && (freq < 100000000)) {
Even_Divisor = 8;
}
if ((freq >= 100000000) && (freq < 146600000)) {
Even_Divisor = 6;
}
if ((freq >= 150000000) && (freq < 220000000)) {
Even_Divisor = 4;
}
}
void SendFrequency()
{
//freq = freq + 10;
si5351.set_freq_manual(freq * SI5351_FREQ_MULT, Even_Divisor * freq * SI5351_FREQ_MULT, SI5351_CLK0);
si5351.set_freq_manual(freq * SI5351_FREQ_MULT, Even_Divisor * freq * SI5351_FREQ_MULT, SI5351_CLK1);
si5351.set_phase(SI5351_CLK0, 0);
si5351.set_phase(SI5351_CLK1, Even_Divisor);
if (Even_Divisor != oldEven_Divisor)
{
si5351.pll_reset(SI5351_PLLA);
oldEven_Divisor = Even_Divisor;
}
}
*********************************************************
Transmit Software
// Libraries
#include <Wire.h> // I2C comms library
#include <si5351.h> // Si5351Jason library
#include <ILI9341_t3.h>
#include <font_Arial.h> // Arial font library
#include <Audio.h> // Teensy audio library
#include <Metro.h> // Metro library
// Define Constants and Variables
// Display
static const int TFT_DC = 20;
static const int TFT_CS = 21;
static const int TFT_RST = 255; // 255 = unused, connect to 3.3V
static const int TFT_MOSI = 7;
static const int TFT_SCLK = 14;
static const int TFT_MISO = 12;
// Switches, relays
static const int TxRxRelay = 29;
static const int Band80mSwitch = 28;
static const int Band40mSwitch = 27;
static const int Band20mSwitch = 26;
static const int PTTSwitch = 25;
static const int ModeSwitch = 24;
// Audio panel gains
static const int Linein_Gain = 10; // Range is 0-15. 0 = 3.12 Vp-p, 15 = 0.24 Vp-p. Default = 5
static const int Lineout_Gain = 20; // Range is 13-31. 13 = 3.16 Vp-p, 31 = 1.16 Vp-p Original was 20
static const int Mic_Gain = 30; // Range is 0-63dB. Original was 0
// Rotary Encoder
static const int EncoderPushButton = 39;
static const int rotBPin = 36;
static const int rotAPin = 35;
volatile int rotState = 0;
volatile int rotAval = 1;
volatile int rotBval = 1;
volatile int rotAcc = 0;
// Other
static const int NO_HILBERT_COEFFS = 100; // Used to define the Hilbert transform filter arrays
static const long bandInit = 3690000; // where to initially set the frequency
static const long band80mStart = 3500000; // start of 80m
static const long band80mEnd = 3900000; // end of 80m
static const long band40mStart = 7000000; // start of 40m
static const long band40mEnd = 7300000; // end of 40m
static const long band20mStart = 14000000; // start of 20m
static const long band20mEnd = 14350000; // end of 20m
volatile long oldfreq = 14123456;
volatile long old80mfreq = 3700000;
volatile long old40mfreq = 7100000;
volatile long old20mfreq = 14100000;
volatile long freq = bandInit ;
volatile long radix = 1000; // how much to change the frequency. Pushing the rotary encoder switch will change this.
volatile long oldradix = 1000;
volatile int band = 80; // 80 = 80m, 40 = 40m, 20 = 20m
volatile int oldband = 0;
volatile int Even_Divisor = 0;
volatile int oldEven_Divisor = 0;
char PTT = 'R'; // R = receive, T = transmit
volatile int oldPTT = 0;
float raw_sMeter[20] = {0}; // Raw received signal strength
volatile int sMeterBar = 0; // Received signal strength
volatile int oldsMeterBar = 0;
static const int scale = 60; // Scale factor for the S Meter
volatile int x = 0;
char mode = 'L'; // L = LSB, U = USB, C = CQ, A = AM
char oldmode = 'L';
volatile int MHz10, MHz1, kHz100, kHz10, kHz1, Hz100, Hz10, Hz1 = 0;
volatile int oldMHz10, oldMHz1, oldkHz100, oldkHz10, oldkHz1, oldHz100, oldHz10, oldHz1 = 0;
// Iowa Hills Hilbert transform filter coefficients
const short Hilbert_Plus_45_Coeffs[NO_HILBERT_COEFFS] = {
(short)(32768 * 483.9743406915770E-9),
(short)(32768 * 1.866685817417670E-6),
(short)(32768 * 4.392570072495770E-6),
(short)(32768 * 8.820636712774380E-6),
(short)(32768 * 0.000016184764415848),
(short)(32768 * 0.000027249288101724),
(short)(32768 * 0.000041920439805110),
(short)(32768 * 0.000059016345361008),
(short)(32768 * 0.000076756191268614),
(short)(32768 * 0.000094055071776657),
(short)(32768 * 0.000112261583662573),
(short)(32768 * 0.000136518354793722),
(short)(32768 * 0.000175696544399550),
(short)(32768 * 0.000240067250940666),
(short)(32768 * 0.000336609833081347),
(short)(32768 * 0.000462990951098187),
(short)(32768 * 0.000602421399161912),
(short)(32768 * 0.000722301614841713),
(short)(32768 * 0.000779305755125654),
(short)(32768 * 0.000732056920489209),
(short)(32768 * 0.000559948250896998),
(short)(32768 * 0.000283585816755988),
(short)(32768 * -0.000020215761694049),
(short)(32768 * -0.000216819118897174),
(short)(32768 * -0.000131758715732279),
(short)(32768 * 0.000409948902196685),
(short)(32768 * 0.001528130963104050),
(short)(32768 * 0.003227564604759798),
(short)(32768 * 0.005351504118228274),
(short)(32768 * 0.007567804706902511),
(short)(32768 * 0.009402820162611196),
(short)(32768 * 0.010328512135999630),
(short)(32768 * 0.009894246835039863),
(short)(32768 * 0.007879714166593881),
(short)(32768 * 0.004433421126740721),
(short)(32768 * 0.000156366633965185),
(short)(32768 * -0.003904389468521576),
(short)(32768 * -0.006371988171406650),
(short)(32768 * -0.005761887634323113),
(short)(32768 * -0.000778938771957753),
(short)(32768 * 0.009365085367419172),
(short)(32768 * 0.024681757404317366),
(short)(32768 * 0.044251382160327521),
(short)(32768 * 0.066233642104189930),
(short)(32768 * 0.088062621169129954),
(short)(32768 * 0.106806616459214951),
(short)(32768 * 0.119635362035632908),
(short)(32768 * 0.124309482163432433),
(short)(32768 * 0.119596382589365807),
(short)(32768 * 0.105526834497225247),
(short)(32768 * 0.083435851600156402),
(short)(32768 * 0.055774084237545388),
(short)(32768 * 0.025722508803868269),
(short)(32768 * -0.003316774367731974),
(short)(32768 * -0.028256325810852603),
(short)(32768 * -0.046784860848984686),
(short)(32768 * -0.057671422122216751),
(short)(32768 * -0.060863961385426720),
(short)(32768 * -0.057377469068775784),
(short)(32768 * -0.049008885222883866),
(short)(32768 * -0.037947605693328487),
(short)(32768 * -0.026365178611104038),
(short)(32768 * -0.016063741251826878),
(short)(32768 * -0.008242320709669780),
(short)(32768 * -0.003409329314875374),
(short)(32768 * -0.001436295024424050),
(short)(32768 * -0.001719754923178513),
(short)(32768 * -0.003400970055132929),
(short)(32768 * -0.005589187214751837),
(short)(32768 * -0.007542651980327935),
(short)(32768 * -0.008778747041127889),
(short)(32768 * -0.009105231860961261),
(short)(32768 * -0.008583286966676333),
(short)(32768 * -0.007445876442758468),
(short)(32768 * -0.005999873442098177),
(short)(32768 * -0.004537732597630097),
(short)(32768 * -0.003276341625911221),
(short)(32768 * -0.002330120643710241),
(short)(32768 * -0.001715559019593159),
(short)(32768 * -0.001377498498508186),
(short)(32768 * -0.001224659509681699),
(short)(32768 * -0.001162953813794283),
(short)(32768 * -0.001118850197066992),
(short)(32768 * -0.001049829425495061),
(short)(32768 * -0.000943240226180188),
(short)(32768 * -0.000807608474652057),
(short)(32768 * -0.000661296218869203),
(short)(32768 * -0.000522622836450865),
(short)(32768 * -0.000403818527830429),
(short)(32768 * -0.000309261220275339),
(short)(32768 * -0.000236981246010256),
(short)(32768 * -0.000181726899678497),
(short)(32768 * -0.000137960767232952),
(short)(32768 * -0.000101749677323657),
(short)(32768 * -0.000071268112804006),
(short)(32768 * -0.000046246069278189),
(short)(32768 * -0.000026984224473470),
(short)(32768 * -0.000013519855860183),
(short)(32768 * -5.268419079329310E-6),
(short)(32768 * -1.152120275972750E-6)
};
// Iowa Hills Hilbert transform filter coefficients
const short Hilbert_Minus_45_Coeffs[NO_HILBERT_COEFFS] = {
(short)(32768 * -1.152120275972720E-6),
(short)(32768 * -5.268419079329100E-6),
(short)(32768 * -0.000013519855860182),
(short)(32768 * -0.000026984224473469),
(short)(32768 * -0.000046246069278187),
(short)(32768 * -0.000071268112804004),
(short)(32768 * -0.000101749677323656),
(short)(32768 * -0.000137960767232950),
(short)(32768 * -0.000181726899678496),
(short)(32768 * -0.000236981246010254),
(short)(32768 * -0.000309261220275334),
(short)(32768 * -0.000403818527830420),
(short)(32768 * -0.000522622836450852),
(short)(32768 * -0.000661296218869189),
(short)(32768 * -0.000807608474652046),
(short)(32768 * -0.000943240226180185),
(short)(32768 * -0.001049829425495072),
(short)(32768 * -0.001118850197067017),
(short)(32768 * -0.001162953813794315),
(short)(32768 * -0.001224659509681719),
(short)(32768 * -0.001377498498508169),
(short)(32768 * -0.001715559019593075),
(short)(32768 * -0.002330120643710066),
(short)(32768 * -0.003276341625910951),
(short)(32768 * -0.004537732597629757),
(short)(32768 * -0.005999873442097817),
(short)(32768 * -0.007445876442758181),
(short)(32768 * -0.008583286966676212),
(short)(32768 * -0.009105231860961396),
(short)(32768 * -0.008778747041128323),
(short)(32768 * -0.007542651980328638),
(short)(32768 * -0.005589187214752684),
(short)(32768 * -0.003400970055133710),
(short)(32768 * -0.001719754923178943),
(short)(32768 * -0.001436295024423829),
(short)(32768 * -0.003409329314874256),
(short)(32768 * -0.008242320709667652),
(short)(32768 * -0.016063741251823811),
(short)(32768 * -0.026365178611100354),
(short)(32768 * -0.037947605693324706),
(short)(32768 * -0.049008885222880681),
(short)(32768 * -0.057377469068773987),
(short)(32768 * -0.060863961385426962),
(short)(32768 * -0.057671422122219533),
(short)(32768 * -0.046784860848990188),
(short)(32768 * -0.028256325810860565),
(short)(32768 * -0.003316774367741772),
(short)(32768 * 0.025722508803857579),
(short)(32768 * 0.055774084237534945),
(short)(32768 * 0.083435851600147395),
(short)(32768 * 0.105526834497218600),
(short)(32768 * 0.119596382589362227),
(short)(32768 * 0.124309482163432142),
(short)(32768 * 0.119635362035635753),
(short)(32768 * 0.106806616459220294),
(short)(32768 * 0.088062621169136893),
(short)(32768 * 0.066233642104197507),
(short)(32768 * 0.044251382160334737),
(short)(32768 * 0.024681757404323448),
(short)(32768 * 0.009365085367423625),
(short)(32768 * -0.000778938771955104),
(short)(32768 * -0.005761887634322139),
(short)(32768 * -0.006371988171407000),
(short)(32768 * -0.003904389468522771),
(short)(32768 * 0.000156366633963640),
(short)(32768 * 0.004433421126739255),
(short)(32768 * 0.007879714166592786),
(short)(32768 * 0.009894246835039278),
(short)(32768 * 0.010328512135999562),
(short)(32768 * 0.009402820162611529),
(short)(32768 * 0.007567804706903086),
(short)(32768 * 0.005351504118228925),
(short)(32768 * 0.003227564604760380),
(short)(32768 * 0.001528130963104480),
(short)(32768 * 0.000409948902196933),
(short)(32768 * -0.000131758715732195),
(short)(32768 * -0.000216819118897210),
(short)(32768 * -0.000020215761694147),
(short)(32768 * 0.000283585816755878),
(short)(32768 * 0.000559948250896909),
(short)(32768 * 0.000732056920489157),
(short)(32768 * 0.000779305755125639),
(short)(32768 * 0.000722301614841724),
(short)(32768 * 0.000602421399161936),
(short)(32768 * 0.000462990951098213),
(short)(32768 * 0.000336609833081367),
(short)(32768 * 0.000240067250940678),
(short)(32768 * 0.000175696544399555),
(short)(32768 * 0.000136518354793723),
(short)(32768 * 0.000112261583662573),
(short)(32768 * 0.000094055071776658),
(short)(32768 * 0.000076756191268616),
(short)(32768 * 0.000059016345361010),
(short)(32768 * 0.000041920439805112),
(short)(32768 * 0.000027249288101726),
(short)(32768 * 0.000016184764415849),
(short)(32768 * 8.820636712774440E-6),
(short)(32768 * 4.392570072495580E-6),
(short)(32768 * 1.866685817417500E-6),
(short)(32768 * 483.9743406915230E-9)
};
// Instantiate the Objects
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);
Si5351 si5351; // Name for the Si5351 DDS
AudioControlSGTL5000 audioShield; // Name for the Teensy audio CODEC on the audio shield
Metro sMeterMetro = Metro(150); // Name for the sMeter update timer
// Audio shield objects
AudioInputI2S audioInput; // Name for the input to the audio shield (either line-in or mic)
AudioOutputI2S audioOutput; // Name for the output of the audio shield (either headphones or line-out)
// Receiver
AudioFilterFIR RX_Hilbert_Plus_45; // Name for the RX +45 Hilbert transform
AudioFilterFIR RX_Hilbert_Minus_45; // Name for the RX +45 Hilbert transform
AudioMixer4 RX_Summer; // Name for the RX summer
AudioAnalyzePeak S_Meter; // Received signal strength
// Transmitter
AudioFilterFIR TX_Hilbert_Plus_45; // Name for the TX +45 Hilbert transform
AudioFilterFIR TX_Hilbert_Minus_45; // Name for the TX +45 Hilbert transform
AudioMixer4 TX_I_Sideband_Switch; // Name for the sideband switching summer for the I channel
// Audio shield connections
// Receiver
AudioConnection patchCord5(audioInput, 0, RX_Hilbert_Plus_45, 0); // Left channel to Hilbert transform +45
AudioConnection patchCord10(audioInput, 1, RX_Hilbert_Minus_45, 0); // Right channel to Hilbert transform -45
AudioConnection patchCord15(RX_Hilbert_Plus_45, 0, RX_Summer, 0); // Hilbert transform +45 to receiver summer
AudioConnection patchCord20(RX_Hilbert_Minus_45, 0, RX_Summer, 1); // Hilbert transform -45 to receiver summer
AudioConnection patchCord25(RX_Summer, 0, S_Meter, 0);
AudioConnection patchCord30(RX_Summer, 0, audioOutput, 0);
AudioConnection patchCord35(RX_Summer, 0, audioOutput, 1);
// Transmitter
AudioConnection patchCord40(audioInput, 0, TX_Hilbert_Plus_45, 0); // Mic audio to Hilbert transform +45
AudioConnection patchCord45(audioInput, 0, TX_Hilbert_Minus_45, 0); // Mic audio to Hilbert transform -45
AudioConnection patchCord50(TX_Hilbert_Plus_45, 0, TX_I_Sideband_Switch, 0); // In phase channel to sideband switch
AudioConnection patchCord55(TX_I_Sideband_Switch, 0, audioOutput, 0); // I to left channel out
AudioConnection patchCord60(TX_Hilbert_Minus_45, 0, audioOutput, 1); // Q to right channel out
void setup()
{
// Setup screen
tft.begin();
tft.setRotation(1);
tft.fillScreen(ILI9341_BLACK);
// Setup input/output
pinMode(rotAPin, INPUT);
pinMode(rotBPin, INPUT);
pinMode(EncoderPushButton, INPUT);
pinMode(ModeSwitch, INPUT);
pinMode(Band80mSwitch, INPUT);
pinMode(Band40mSwitch, INPUT);
pinMode(Band20mSwitch, INPUT);
pinMode(PTTSwitch, INPUT);
pinMode(TxRxRelay, OUTPUT);
digitalWrite(rotAPin, HIGH);
digitalWrite(rotBPin, HIGH);
digitalWrite(EncoderPushButton, HIGH);
digitalWrite(ModeSwitch, HIGH);
digitalWrite(Band80mSwitch, HIGH);
digitalWrite(Band40mSwitch, HIGH);
digitalWrite(Band20mSwitch, HIGH);
digitalWrite(PTTSwitch, HIGH);
digitalWrite(TxRxRelay, LOW);
// Setup interrupt pins
attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE);
attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE);
// Initialize the DDS
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0); // 25MHz crystal = 0, 27MHz crystal = 27000000
si5351.set_correction(62799, SI5351_PLL_INPUT_XO); // Set to specific Si5351 calibration number
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_6MA);
si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_6MA);
si5351.set_freq_manual(freq * SI5351_FREQ_MULT, Even_Divisor * freq * SI5351_FREQ_MULT, SI5351_CLK0);
si5351.set_freq_manual(freq * SI5351_FREQ_MULT, Even_Divisor * freq * SI5351_FREQ_MULT, SI5351_CLK1);
si5351.set_phase(SI5351_CLK0, 0);
si5351.set_phase(SI5351_CLK1, Even_Divisor);
si5351.pll_reset(SI5351_PLLA);
// Setup the audio shield
AudioNoInterrupts();
AudioMemory(12);
audioShield.enable();
AudioInterrupts();
// Setup initial transceiver state
Receive();
UpdateMode();
UpdateDisplay();
UpdateFreqDisplay();
}
void loop()
{
// Check to see if the freq has changed
if (freq != oldfreq) // Check to see if the frequency has changed. If so, update everything.
{
EvenDivisor();
UpdateFreqDisplay();
SendFrequency();
oldfreq = freq;
}
// Check to see if the radix has changed
if (radix != oldradix)
{
UpdateFreqDisplay();
oldradix = radix;
}
// Check the mode switch
if (digitalRead(ModeSwitch) == LOW)
mode = 'L';
else
mode = 'U';
// Check to see if the mode has changed
if (mode != oldmode) // Only update the display on mode change
{
UpdateMode();
UpdateDisplay();
oldmode = mode;
}
// Check the band switch
if (digitalRead(Band80mSwitch) == LOW)
band = 80; // 80m band
if (digitalRead(Band40mSwitch) == LOW)
band = 40; // 40m band
if (digitalRead(Band20mSwitch) == LOW)
band = 20; // 20m band
// Check to see if the band has changed
if (band != oldband) // Only update the display on band change
{
UpdateBand();
UpdateFreqDisplay();
oldband = band;
}
// Check the PTT switch
if (digitalRead(PTTSwitch) == LOW)
PTT = 'T';
else
PTT = 'R';
// Check to see if PTT has changed
if (PTT != oldPTT)
{
if (PTT == 'T')
Transmit();
if (PTT == 'R')
Receive();
UpdateDisplay();
oldPTT = PTT;
}
// Read raw signal strength (running average)
if (S_Meter.available())
{
raw_sMeter[x] = S_Meter.read() * scale;
x++;
if (x == 20)
{
x = 0;
float av_raw_sMeter = 0;
for (int i = 0; i <= 19; i++)
av_raw_sMeter = av_raw_sMeter + raw_sMeter[i];
sMeterBar = (av_raw_sMeter / 20) * 250;
}
}
if (sMeterMetro.check() == 1) // Update sMeter every 250mS
{
UpdateSMeter();
oldsMeterBar = sMeterBar;
}
}
void Transmit()
{
AudioNoInterrupts();
// Turn off the receiver
audioShield.muteHeadphone();
RX_Hilbert_Plus_45.end();
RX_Hilbert_Minus_45.end();
// Turn on the trasmitter
audioShield.inputSelect(AUDIO_INPUT_MIC);
audioShield.micGain(Mic_Gain);
audioShield.unmuteLineout(); // Output to the TX
audioShield.lineOutLevel(Lineout_Gain);
TX_Hilbert_Plus_45.begin(Hilbert_Plus_45_Coeffs, NO_HILBERT_COEFFS);
TX_Hilbert_Minus_45.begin(Hilbert_Minus_45_Coeffs, NO_HILBERT_COEFFS);
AudioInterrupts();
digitalWrite(TxRxRelay, HIGH); // Key the transmitter
}
void Receive()
{
digitalWrite(TxRxRelay, LOW); // Unkey the transmitter
AudioNoInterrupts();
// Turn off the transmitter
audioShield.muteLineout();
TX_Hilbert_Plus_45.end();
TX_Hilbert_Minus_45.end();
// Turn on the receiver
audioShield.inputSelect(AUDIO_INPUT_LINEIN);
audioShield.lineInLevel(Linein_Gain);
audioShield.unmuteHeadphone(); // Output to the audio amplifier
audioShield.volume(0.7);
RX_Hilbert_Plus_45.begin(Hilbert_Plus_45_Coeffs, NO_HILBERT_COEFFS);
RX_Hilbert_Minus_45.begin(Hilbert_Minus_45_Coeffs, NO_HILBERT_COEFFS);
AudioInterrupts();
}
void UpdateMode()
{
if (mode == 'L') // LSB
{
RX_Summer.gain(0, 1);
RX_Summer.gain(1, -1); // Invert Q channel
RX_Summer.gain(2, 0);
RX_Summer.gain(3, 0);
TX_I_Sideband_Switch.gain(0, 1); // No inversion of I channel
TX_I_Sideband_Switch.gain(1, 0);
TX_I_Sideband_Switch.gain(2, 0);
TX_I_Sideband_Switch.gain(3, 0);
}
if (mode == 'U') // USB
{
RX_Summer.gain(0, 1);
RX_Summer.gain(1, 1); // No inversion of Q channel
RX_Summer.gain(2, 0);
RX_Summer.gain(3, 0);
TX_I_Sideband_Switch.gain(0, -1); // Invert I channel
TX_I_Sideband_Switch.gain(1, 0);
TX_I_Sideband_Switch.gain(2, 0);
TX_I_Sideband_Switch.gain(3, 0);
}
}
void UpdateBand()
{
if ((band == 80) && (oldband == 40))
{
old40mfreq = freq;
freq = old80mfreq;
}
if ((band == 80) && (oldband == 20))
{
old20mfreq = freq;
freq = old80mfreq;
}
if ((band == 40) && (oldband == 80))
{
old80mfreq = freq;
freq = old40mfreq;
}
if ((band == 40) && (oldband == 20))
{
old20mfreq = freq;
freq = old40mfreq;
}
if ((band == 20) && (oldband == 80))
{
old80mfreq = freq;
freq = old20mfreq;
}
if ((band == 20) && (oldband == 40))
{
old40mfreq = freq;
freq = old20mfreq;
}
}
// 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(EncoderPushButton) == LOW)
{
if (radix == 100000)
radix = 10000;
else if (radix == 10000)
radix = 1000;
else if (radix == 1000)
radix = 100;
else if (radix == 100)
radix = 10;
else if (radix == 10)
radix = 1;
else
radix = 100000;
}
else
{
freq = (freq + radix);
if (band == 80)
if (freq > band80mEnd)
freq = band80mEnd;
if (band == 40)
if (freq > band40mEnd)
freq = band40mEnd;
if (band == 20)
if (freq > band20mEnd)
freq = band20mEnd;
}
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(EncoderPushButton) == LOW)
{
if (radix == 1)
radix = 10;
else if (radix == 10)
radix = 100;
else if (radix == 100)
radix = 1000;
else if (radix == 1000)
radix = 10000;
else if (radix == 10000)
radix = 100000;
else
radix = 1;
}
else
{
freq = (freq - radix);
if (band == 80)
if (freq < band80mStart)
freq = band80mStart;
if (band == 40)
if (freq < band40mStart)
freq = band40mStart;
if (band == 20)
if (freq < band20mStart)
freq = band20mStart;
}
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()
{
tft.setFont(Arial_16);
// RX, TX
if (PTT == 'R')
{
tft.drawRoundRect(0, 0, 60, 40, 5, tft.color565(0, 255, 0));
tft.setCursor(12, 12);
tft.setTextColor(tft.color565(0, 255, 0)); // Green
tft.println("RX");
tft.drawRoundRect(70, 0, 60, 40, 5, tft.color565(160, 160, 160));
tft.setCursor(83, 12);
tft.setTextColor(tft.color565(160, 160, 160));
tft.println("TX");
}
if (PTT == 'T')
{
tft.drawRoundRect(0, 0, 60, 40, 5, tft.color565(160, 160, 160));
tft.setCursor(12, 12);
tft.setTextColor(tft.color565(160, 160, 160));
tft.println("RX");
tft.drawRoundRect(70, 0, 60, 40, 5, tft.color565(255, 0, 0));
tft.setCursor(83, 12);
tft.setTextColor(tft.color565(255, 0, 0)); // Red
tft.println("TX");
}
// Tune
tft.drawRoundRect(140, 0, 80, 40, 5, tft.color565(160, 160, 160));
tft.setCursor(149, 12);
tft.setTextColor(tft.color565(160, 160, 160));
tft.println("TUNE");
// Mode
if (mode == 'U')
{
tft.drawRoundRect(0, 50, 60, 40, 5, tft.color565(160, 160, 160));
tft.setCursor(9, 62);
tft.setTextColor(tft.color565(160, 160, 160));
tft.println("LSB");
tft.drawRoundRect(70, 50, 60, 40, 5, tft.color565(255, 255, 0)); // Yellow
tft.setCursor(79, 62);
tft.setTextColor(tft.color565(255, 255, 0));
tft.println("USB");
tft.drawRoundRect(140, 50, 60, 40, 5, tft.color565(160, 160, 160));
tft.setCursor(150, 62);
tft.setTextColor(tft.color565(160, 160, 160));
tft.println("CW");
}
if (mode == 'L')
{
tft.drawRoundRect(0, 50, 60, 40, 5, tft.color565(255, 255, 0)); // Yellow
tft.setCursor(9, 62);
tft.setTextColor(tft.color565(255, 255, 0));
tft.println("LSB");
tft.drawRoundRect(70, 50, 60, 40, 5, tft.color565(160, 160, 160));
tft.setCursor(79, 62);
tft.setTextColor(tft.color565(160, 160, 160));
tft.println("USB");
tft.drawRoundRect(140, 50, 60, 40, 5, tft.color565(160, 160, 160));
tft.setCursor(150, 62);
tft.setTextColor(tft.color565(160, 160, 160));
tft.println("CW");
}
if (mode == 'C')
{
tft.drawRoundRect(0, 50, 60, 40, 5, tft.color565(160, 160, 160));
tft.setCursor(9, 62);
tft.setTextColor(tft.color565(160, 160, 160));
tft.println("LSB");
tft.drawRoundRect(70, 50, 60, 40, 5, tft.color565(160, 160, 160));
tft.setCursor(79, 62);
tft.setTextColor(tft.color565(160, 160, 160));
tft.println("USB");
tft.drawRoundRect(140, 50, 60, 40, 5, tft.color565(255, 255, 0)); // Yellow
tft.setCursor(150, 62);
tft.setTextColor(tft.color565(255, 255, 0));
tft.println("CW");
}
// S Meter
tft.setFont(Arial_8);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(6, 230);
tft.println("S1");
tft.setCursor(38, 230);
tft.println("3");
tft.setCursor(68, 230);
tft.println("5");
tft.setCursor(98, 230);
tft.println("7");
tft.setCursor(128, 230);
tft.println("9");
tft.setTextColor(ILI9341_RED);
tft.setCursor(150, 230);
tft.println("+20");
tft.setCursor(180, 230);
tft.println("+40");
tft.setCursor(210, 230);
tft.println("+60");
tft.drawLine(10, 220, 10, 215, ILI9341_WHITE);
tft.drawLine(25, 220, 25, 218, ILI9341_WHITE);
tft.drawLine(40, 220, 40, 215, ILI9341_WHITE);
tft.drawLine(55, 220, 55, 218, ILI9341_WHITE);
tft.drawLine(70, 220, 70, 215, ILI9341_WHITE);
tft.drawLine(85, 220, 85, 218, ILI9341_WHITE);
tft.drawLine(100, 220, 100, 215, ILI9341_WHITE);
tft.drawLine(115, 220, 115, 218, ILI9341_WHITE);
tft.drawLine(130, 220, 130, 215, ILI9341_WHITE);
tft.drawLine(145, 220, 145, 218, ILI9341_WHITE);
tft.drawLine(160, 220, 160, 215, ILI9341_RED);
tft.drawLine(175, 220, 175, 218, ILI9341_RED);
tft.drawLine(190, 220, 190, 215, ILI9341_RED);
tft.drawLine(205, 220, 205, 218, ILI9341_RED);
tft.drawLine(220, 220, 220, 215, ILI9341_RED);
tft.drawLine(235, 220, 235, 218, ILI9341_RED);
tft.drawLine(10, 221, 159, 221, ILI9341_WHITE);
tft.drawLine(160, 221, 235, 221, ILI9341_RED);
}
void UpdateFreqDisplay()
{
oldMHz10 = (oldfreq % 100000000) / 10000000;
oldMHz1 = (oldfreq % 10000000) / 1000000;
oldkHz100 = (oldfreq % 1000000) / 100000;
oldkHz10 = (oldfreq % 100000) / 10000;
oldkHz1 = (oldfreq % 10000) / 1000;
oldHz100 = (oldfreq % 1000) / 100;
oldHz10 = (oldfreq % 100) / 10;
oldHz1 = (oldfreq % 10) / 1;
MHz10 = (freq % 100000000) / 10000000;
MHz1 = (freq % 10000000) / 1000000;
kHz100 = (freq % 1000000) / 100000;
kHz10 = (freq % 100000) / 10000;
kHz1 = (freq % 10000) / 1000;
Hz100 = (freq % 1000) / 100;
Hz10 = (freq % 100) / 10;
Hz1 = (freq % 10) / 1;
tft.setFont(Arial_40);
//10MHz
if (oldfreq > 10000000)
{
if (MHz10 != oldMHz10)
{
tft.setCursor(10, 115);
tft.setTextColor(ILI9341_BLACK);
tft.println(oldMHz10);
}
}
if (freq > 10000000)
{
tft.setCursor(10, 115);
tft.setTextColor(ILI9341_WHITE);
tft.println(MHz10);
}
//1MHz
if (MHz1 != oldMHz1)
{
tft.setCursor(40, 115);
tft.setTextColor(ILI9341_BLACK);
tft.println(oldMHz1);
tft.setCursor(40, 115);
tft.setTextColor(ILI9341_WHITE);
tft.println(MHz1);
}
// .
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(70, 115);
tft.println(".");
//100kHz
if (kHz100 != oldkHz100)
{
tft.setCursor(85, 115);
tft.setTextColor(ILI9341_BLACK);
tft.println(oldkHz100);
tft.setCursor(85, 115);
tft.setTextColor(ILI9341_WHITE);
tft.println(kHz100);
}
//10kHz
if (kHz10 != oldkHz10)
{
tft.setCursor(115, 115);
tft.setTextColor(ILI9341_BLACK);
tft.println(oldkHz10);
tft.setCursor(115, 115);
tft.setTextColor(ILI9341_WHITE);
tft.println(kHz10);
}
//1kHz
if (kHz1 != oldkHz1)
{
tft.setCursor(145, 115);
tft.setTextColor(ILI9341_BLACK);
tft.println(oldkHz1);
tft.setCursor(145, 115);
tft.setTextColor(ILI9341_WHITE);
tft.println(kHz1);
}
// .
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(175, 115);
tft.println(".");
//100Hz
if (Hz100 != oldHz100)
{
tft.setCursor(190, 115);
tft.setTextColor(ILI9341_BLACK);
tft.println(oldHz100);
tft.setCursor(190, 115);
tft.setTextColor(ILI9341_WHITE);
tft.println(Hz100);
}
//10Hz
if (Hz10 != oldHz10)
{
tft.setCursor(220, 115);
tft.setTextColor(ILI9341_BLACK);
tft.println(oldHz10);
tft.setCursor(220, 115);
tft.setTextColor(ILI9341_WHITE);
tft.println(Hz10);
}
//1Hz
if (Hz1 != oldHz1)
{
tft.setCursor(250, 115);
tft.setTextColor(ILI9341_BLACK);
tft.println(oldHz1);
tft.setCursor(250, 115);
tft.setTextColor(ILI9341_WHITE);
tft.println(Hz1);
}
// Radix line
if (oldradix == 1)
tft.fillRect(258, 160, 15, 4, ILI9341_BLACK);
if (oldradix == 10)
tft.fillRect(228, 160, 15, 4, ILI9341_BLACK);
if (oldradix == 100)
tft.fillRect(198, 160, 15, 4, ILI9341_BLACK);
if (oldradix == 1000)
tft.fillRect(153, 160, 15, 4, ILI9341_BLACK);
if (oldradix == 10000)
tft.fillRect(123, 160, 15, 4, ILI9341_BLACK);
if (oldradix == 100000)
tft.fillRect(93, 160, 15, 4, ILI9341_BLACK);
if (radix == 1)
tft.fillRect(258, 160, 15, 4, ILI9341_WHITE);
if (radix == 10)
tft.fillRect(228, 160, 15, 4, ILI9341_WHITE);
if (radix == 100)
tft.fillRect(198, 160, 15, 4, ILI9341_WHITE);
if (radix == 1000)
tft.fillRect(153, 160, 15, 4, ILI9341_WHITE);
if (radix == 10000)
tft.fillRect(123, 160, 15, 4, ILI9341_WHITE);
if (radix == 100000)
tft.fillRect(93, 160, 15, 4, ILI9341_WHITE);
oldMHz10 = MHz10;
oldMHz1 = MHz1;
oldkHz100 = kHz100;
oldkHz10 = kHz10;
oldkHz1 = kHz1;
oldHz100 = Hz100;
oldHz10 = Hz10;
oldHz1 = Hz1;
}
void UpdateSMeter()
{
tft.fillRect(10, 205, oldsMeterBar, 4, ILI9341_BLACK);
tft.fillRect(10, 205, sMeterBar, 4, tft.color565(0, 255, 255));
}
void EvenDivisor()
{
if (freq < 6850000)
Even_Divisor = 126;
if ((freq >= 6850000) && (freq < 9500000))
Even_Divisor = 88;
if ((freq >= 9500000) && (freq < 13600000))
Even_Divisor = 64;
if ((freq >= 13600000) && (freq < 17500000))
Even_Divisor = 44;
if ((freq >= 17500000) && (freq < 25000000))
Even_Divisor = 34;
if ((freq >= 25000000) && (freq < 36000000))
Even_Divisor = 24;
if ((freq >= 36000000) && (freq < 45000000))
Even_Divisor = 18;
if ((freq >= 45000000) && (freq < 60000000))
Even_Divisor = 14;
if ((freq >= 60000000) && (freq < 80000000))
Even_Divisor = 10;
if ((freq >= 80000000) && (freq < 100000000))
Even_Divisor = 8;
if ((freq >= 100000000) && (freq < 146600000))
Even_Divisor = 6;
if ((freq >= 150000000) && (freq < 220000000))
Even_Divisor = 4;
}
void SendFrequency()
{
si5351.set_freq_manual(freq * SI5351_FREQ_MULT, Even_Divisor * freq * SI5351_FREQ_MULT, SI5351_CLK0);
si5351.set_freq_manual(freq * SI5351_FREQ_MULT, Even_Divisor * freq * SI5351_FREQ_MULT, SI5351_CLK1);
si5351.set_phase(SI5351_CLK0, 0);
si5351.set_phase(SI5351_CLK1, Even_Divisor);
if (Even_Divisor != oldEven_Divisor)
{
si5351.pll_reset(SI5351_PLLA);
oldEven_Divisor = Even_Divisor;
}
}
***********************************************************