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;
}
}
***********************************************************
This comment has been removed by a blog administrator.
ReplyDeleteHi Charlie, I'm glad you came back with details about the SDR Rig. I also have an idea inspired from everything you have published so far, in which I change the SBL mixer with SA612, because in Romania it is easier to find SA612 than SBLs and it is much cheaper. But I have two problems, namely how to get on the blog the drawing made by me and I am not sure about the connections to Teensy, to the sound card, because in the specialty shops from us we could not find the sound card that you use in the project. So the super code you wrote is not very helpful and I think if I go to use a Raspberry Pi with a USB audio card and a Linux SDR application next to the RF side with SA612. Anyway it would be great if I could send you your drawing to tell you your opinion of a specialist in this field.
ReplyDeleteWith friendship and respect 73! by YO5PQJ Alex
Hi Alex. Unfortunately, the code will only work if you have the audio shield. You won't be able to feed the audio straight into the Teensy. Looks like you will have to use a Raspberry Pi and-say-QUISK. Please note that my next project will be a NE612 based from end that will be able to be computer controlled using one of the SDR programmes. I'm still looking at how that will work.
ReplyDeleteCharlie
Thanks for the answer Charlie can tell you that I look forward to the project and I am very interested in it, and if you want, please send me an email address that you use, to send you see what I have done so far , what filters I used, etc.
ReplyDelete73! Alex
Hi Charlie!please scetch vfo/bfo si5351,arduino uno,displei1602? Vladimir martynov.
ReplyDeleteHi Vladimir. All I have is above. Sorry about that.
DeleteCharlie
Hello Charlie
ReplyDeleteWhen you use filters with 45° phase shift, you don't need to create two coeffs arrays (one for +45° and another for -45°). Just use one array in forward coeffs order for +45° and the same one but in reverse order for -45°.
If you carefully look into your coeffs arrays you will see that them are exactly the same just in reverse order.
Cheers
Oscar (LU3EBW)
Thanks Oscar. That's good to know as it will save some space.
DeleteCharlie
Hello
ReplyDeleteForget my comment. I assumed you take care of the convolution in your code but later I realized you are using a library function for filtering and you in fact need two arrays.
Regard.
Oscar (LU3EBW0
hi charlie i am trying to download your code but is error... so sad
ReplyDeleteSorry about that. Not much I can do sorry. I use the Jason Mildrum Si5351 library if that is a help.
DeleteSorry to go back years, but 1) you seem to use only "Wire.h" so I2C bus is 19&18 on T4. 2) Is this where you connected Si5351, same pins used by audio board?
ReplyDeleteWorking on a new SSB Exciter... using T4 and a lot more taps on Hilberts (thinking 200-500)... Si5351 module > mixers ADE-1's > ADP-1 combiner > MMIC output amp...
Are you switching to Floating point ... You are going to find out that with fast integer you are going to tap out around 125-135 taps max per filter .. The t4 has i2c Buss 1 on 18/19 and i2c buss 2 in 16/17
ReplyDeleteThank you. I'll look into that.
ReplyDeleteHi, I am following your page with interest. Very interesting! Have you ever thought about writing a code for AM rx/tx? Thanks.Stefano from Italy.
ReplyDeleteOnly using hardware Stefano. I'll add AM to the SDR list of things to try out.
DeleteCharlie
Thanks Charlie for the reply. I will be happy to test your software. Ciao!
DeleteHi Charlie, I see you are using a software: "coefficient formatter" for the Hilbert Filter. Is it online, or is it your code? Thanks. Stefano.
ReplyDeleteYes. It's a small Python script.
Deletedef main():
"""Asks for input file name"""
input_filename = (input("Input file name ") + ".txt")
output_filename = input_filename.rstrip(".txt") + "_output.txt"
format_numbers(input_filename, output_filename)
input("Formatting complete, press ENTER to continue")
def format_numbers(inputfile, outputfile):
"""Formats the numbers from the input file and writes to the output file"""
infile = open(inputfile)
outfile = open(outputfile, 'w')
for line in infile:
number = line.rstrip("\n")
number = number.lstrip(" ")
number = number.rstrip(" ")
outfile.write("(short)(32768 * {}),\n".format(number))
infile.close()
outfile.close()
main()
Thanks for the answer Charlie, I don't know Python well, but I installed the editor vers. 3.10.0 on Win 10 and the result is this: File "C:\Users\lp\Desktop\PythonConv.py", line 2
Delete"""Asks for input file name"""
^
IndentationError: expected an indented block
Can you help me? Thanks again! Stefano.
Not sure sorry, as I don't have python on this machine. I wonder if it was the earlier version. You should be able to port the syntax.
DeleteNo problem Charlie! I solved the problem! Thanks again for your availability.
ReplyDeleteGreat, Good to hear.
Delete