Saturday 21 March 2020

Homebrew CW Rig

Please see the YouTube videos for an explanation on the code and circuits:
https://www.youtube.com/channel/UCSNPW3_gzuMJcX_ErBZTv2g/

Crystal Filter





IF Amps









Antenna Amp, 700Hz LPF


Initial Class E RF Amplifier Experiment (see YouTube video for explanation)




Final Class E Amplifier












Code

#include <LiquidCrystal_I2C.h>
#include <si5351.h>

const long band80mStart = 3500000;    // start of 80m
const long band80mEnd = 3900000;      // end of 80m
volatile uint32_t FilterCentreFreq = 8996500;
volatile uint32_t BFO = 8997243;      // Filter centre freq plus offset to get 700Hz AF out.

volatile long freq = 3525000;         // this is a variable (changes) - set it to the beginning of the band
volatile long radix = 100;            // how much to change the frequency by, clicking the rotary encoder will change this.
volatile long oldfreq = 0;
volatile long currentfreq = 0;
volatile int updatedisplay = 0;
volatile int band = 0;                // 0=80m, 1=40m
volatile int oldband = 0;

// Rotary encoder pins and other inputs
static const int rotAPin = 2;
static const int rotBPin = 3;
static const int pushPin = 4;

// Rotary encoder variables, used by interrupt routines
volatile int rotState = 0;
volatile int rotAval = 1;
volatile int rotBval = 1;

// Instantiate the Objects
LiquidCrystal_I2C lcd(0x27, 16, 2);
Si5351 si5351;

// 700Hz Osc
static const int Osc = 11;
static const int TuneSw = 9;

// Morse Key
static const int Key = 8;
unsigned long BreakInTimer;
unsigned long BreakInDelay = 1000;    //1000mS - 1.0Sec

// Relays
static const int AntRelay = 7;
static const int PowerRelay = 6;

void setup()
{
  // Set up I/O Pins
  pinMode(rotAPin, INPUT_PULLUP);
  pinMode(rotBPin, INPUT_PULLUP);
  pinMode(pushPin, INPUT_PULLUP);
  pinMode(TuneSw, INPUT_PULLUP);
  pinMode(Key, INPUT_PULLUP);
  pinMode(AntRelay, OUTPUT);
  pinMode(PowerRelay, OUTPUT);
  pinMode(Osc, OUTPUT);

  digitalWrite(AntRelay, HIGH);         // Default to Rx
  digitalWrite(PowerRelay, HIGH);       // Default to Rx

  // Set up interrupt pins
  attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE);

  // Initialize the display
  lcd.begin();
  lcd.backlight();
  lcd.cursor();

  // Initialize the DDS
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
  si5351.set_correction(-400, SI5351_PLL_INPUT_XO);       // Set to specific Si5351 calibration number
  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
  si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_8MA);
  si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA);
  si5351.output_enable(SI5351_CLK1, 0);                   // Turn off CW carrier

  // Update display and send start frequency
  UpdateDisplay();
  SendFrequency();
}


void loop()
{
  if (digitalRead(Key) == LOW)                // Check to see if CW key down
  {
    BreakInTimer = millis();                  // Reset the break in timer
    digitalWrite(AntRelay, LOW);              // Swap over the antenna to Tx
    digitalWrite(PowerRelay, LOW);            // Rx 12VDC = 0, Tx 12VDC = 12
    delay(25);                                // Allow time for relays to swap over (Spec sheet 10mS)
    si5351.output_enable(SI5351_CLK1, 1);     // Get ready to transmit CW carrier
    SendFrequency();                          // Send CW carrier
  }
  else                                        // Key up
  {
    si5351.output_enable(SI5351_CLK1, 0);     // Turn off the CW carrier
  }

  if ((millis() - BreakInTimer) >= BreakInDelay)    // Check break in timer
  {
    digitalWrite(AntRelay, HIGH);             // Swap over the antenna to Rx
    digitalWrite(PowerRelay, HIGH);           // Rx 12VDC = 12, Tx 12VDC = 0
  }

  if (digitalRead(TuneSw) == LOW)             // Check tune switch
    tone(Osc, 700);                           // Turn on the 700Hz tome
  else
    noTone(Osc);                              // Turn off the 700Hz tome

  currentfreq = getfreq();                    // Interrupt safe method to get the current frequency

  if (currentfreq != oldfreq)
  {
    UpdateDisplay();
    SendFrequency();
    oldfreq = currentfreq;
  }

  if (!digitalRead(pushPin)) {
    delay(10);
    while (!digitalRead(pushPin))
    {
      if (updatedisplay == 1)
      {
        UpdateDisplay();
        updatedisplay = 0;
      }
    }
    delay(50);
  }
}


long getfreq()
{
  long temp_freq;
  cli();
  temp_freq = freq;
  sei();
  return temp_freq;
}


// Interrupt routines
void ISRrotAChange()
{
  if (digitalRead(rotAPin))
  {
    rotAval = 1;
    UpdateRot();
  }
  else
  {
    rotAval = 0;
    UpdateRot();
  }
}


void ISRrotBChange()
{
  if (digitalRead(rotBPin))
  {
    rotBval = 1;
    UpdateRot();
  }
  else
  {
    rotBval = 0;
    UpdateRot();
  }
}


void UpdateRot()
{
  switch (rotState)
  {

    case 0:                                         // Idle state, look for direction
      if (!rotBval)
        rotState = 1;                               // CW 1
      if (!rotAval)
        rotState = 11;                              // CCW 1
      break;

    case 1:                                         // CW, wait for A low while B is low
      if (!rotBval)
      {
        if (!rotAval)
        {
          // either increment radixindex or freq
          if (digitalRead(pushPin) == LOW)
          {
            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 > 3900000)
              freq = 3900000;
          }
          rotState = 2;                             // CW 2
        }
      } else
      {
        if (rotAval)
          rotState = 0;                             // It was just a glitch on B, go back to start
      }
      break;

    case 2:                                         // CW, wait for B high
      if (rotBval)
        rotState = 3;                               // CW 3
      break;

    case 3:                                         // CW, wait for A high
      if (rotAval)
        rotState = 0;                               // back to idle (detent) state
      break;

    case 11:                                        // CCW, wait for B low while A is low
      if (!rotAval)
      {
        if (!rotBval)
        {
          // either decrement radixindex or freq
          if (digitalRead(pushPin) == LOW)
          {
            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 < 3500000)
              freq = 3500000;
          }
          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()
{
  lcd.setCursor(0, 0);
  lcd.print("        ");
  lcd.setCursor(0, 0);
  lcd.print(freq);
  lcd.setCursor(10, 0);
  lcd.print("ZL2CTM");

  if (radix == 1)
    lcd.setCursor(6, 0);
  if (radix == 10)
    lcd.setCursor(5, 0);
  if (radix == 100)
    lcd.setCursor(4, 0);
  if (radix == 1000)
    lcd.setCursor(3, 0);
  if (radix == 10000)
    lcd.setCursor(2, 0);
  if (radix == 100000)
    lcd.setCursor(1, 0);
  if (radix == 1000000)
    lcd.setCursor(0, 0);
}


void SendFrequency()
{
  // VFO
  si5351.set_freq(((freq + FilterCentreFreq) * 100ULL), SI5351_CLK0);

  // BFO
  si5351.set_freq((BFO * 100ULL), SI5351_CLK2);

  // Transmit CW carrier
  si5351.set_freq(((freq - 43)  * 100ULL), SI5351_CLK1);         // 43Hz to align Tx and Rx
}

Saturday 15 February 2020

Homebrew DSB-SC Rig

AF Amps Ideas






The AF amp now has a pi filter on the input made up of 100nF - 1mH - 100nF
That removes the high freq noise.



Ant RF Amp



Mic Amp



Test Low Power RF Amplifier
Out of the junk box hence the 13.8VDC VCC.




Initial code for the radio. Please see the YouTube video for an explanation:

#include <LiquidCrystal_I2C.h>
#include <si5351.h>

const long band80mStart = 3500000;    // start of 80m
const long band80mEnd = 3900000;      // end of 80m
const long band40mStart = 7000000;    // start of 40m
const long band40mEnd = 7300000;      // end of 40m
volatile long freq = 3700000;         // this is a variable (changes) - set it to the beginning of the band
volatile long radix = 1000;           // how much to change the frequency by, clicking the rotary encoder will change this.
volatile long oldfreq = 0;
volatile long old80mfreq = 3700000;
volatile long old40mfreq = 7100000;
volatile long currentfreq = 0;
volatile int updatedisplay = 0;
volatile int band = 0;                // 0=80m, 1=40m
volatile int oldband = 0;

// Rotary encoder pins and other inputs
static const int rotAPin = 2;
static const int rotBPin = 3;
static const int pushSwPin = 4;

// Band switch
static const int BandSwPin = 5;

// Rotary encoder variables, used by interrupt routines
volatile int rotState = 0;
volatile int rotAval = 1;
volatile int rotBval = 1;

// Instantiate the Objects
LiquidCrystal_I2C lcd(0x27, 16, 2);
Si5351 si5351;

void setup()
{
  // Set up frequency and radix switches
  pinMode(rotAPin, INPUT_PULLUP);
  pinMode(rotBPin, INPUT_PULLUP);
  pinMode(pushSwPin, INPUT_PULLUP);
  pinMode(BandSwPin, INPUT_PULLUP);

  // Set up interrupt pins
  attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE);

  // Initialize the display
  lcd.begin();
  lcd.backlight();
  lcd.cursor();

  // Initialize the Si5351
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
  si5351.set_correction(191, SI5351_PLL_INPUT_XO);
  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);

  // Update display and send start frequency
  UpdateDisplay();
  SendFrequency();
}


void loop()
{
  // Check to see if the freq has changed
  currentfreq = getfreq();                    // Interrupt safe method to get the current frequency

  if (currentfreq != oldfreq)
  {
    UpdateDisplay();
    SendFrequency();
    oldfreq = currentfreq;
  }

  // Check the rotary encoder (radix) swith
  if (digitalRead(pushSwPin) == LOW)           // Read the rotary encoder switch
  {
    delay(10);
    while (digitalRead(pushSwPin) == LOW)
    {
      if (updatedisplay == 1)
      {
        UpdateDisplay();
        updatedisplay = 0;
      }
    }
    delay(50);
  }

  // Check the band swith
  if (digitalRead(BandSwPin) == LOW)
    band = 1;                                  // 1=40m
  else
    band = 0;                                  // 0=80m

  if (band != oldband)                         // Only update the display on band change
  {
    if (band == 0)                             // Now 80m was 40m
    {
      old40mfreq = freq;                       // Store old 40m freq
      freq = old80mfreq;                       // Recall old 40m freq
    }
    if (band == 1)                             // Now 40m was 80m
    {
      old80mfreq = freq;                       // Store old 80m freq
      freq = old40mfreq;                       // Recall old 40m freq
    }
    UpdateDisplay();
    oldband = band;
  }
}


long getfreq()
{
  long temp_freq;
  cli();
  temp_freq = freq;
  sei();
  return temp_freq;
}


// Interrupt routines
void ISRrotAChange()
{
  if (digitalRead(rotAPin))
  {
    rotAval = 1;
    UpdateRot();
  }
  else
  {
    rotAval = 0;
    UpdateRot();
  }
}


void ISRrotBChange()
{
  if (digitalRead(rotBPin))
  {
    rotBval = 1;
    UpdateRot();
  }
  else
  {
    rotBval = 0;
    UpdateRot();
  }
}


// Determine which way the rotary encoder is rotating and action as required
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 the radix or freq
          if (digitalRead(pushSwPin) == 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 (band == 0)                          // 80m
              if (freq > band80mEnd)
                freq = band80mEnd;
            if (band == 1)                          // 40m
              if (freq > band40mEnd)
                freq = band40mEnd;
          }
          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 the radix or freq
          if (digitalRead(pushSwPin) == 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 (band == 0)                          // 80m
              if (freq < band80mStart)
                freq = band80mStart;
            if (band == 1)                          // 40m
              if (freq < band40mStart)
                freq = band40mStart;
          }
          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()
{
  lcd.setCursor(0, 0);
  lcd.print("        ");
  lcd.setCursor(0, 0);
  lcd.print(freq);
  lcd.setCursor(10, 0);
  lcd.print("ZL2CTM");

  if (radix == 1)
    lcd.setCursor(6, 0);
  if (radix == 10)
    lcd.setCursor(5, 0);
  if (radix == 100)
    lcd.setCursor(4, 0);
  if (radix == 1000)
    lcd.setCursor(3, 0);
  if (radix == 10000)
    lcd.setCursor(2, 0);
  if (radix == 100000)
    lcd.setCursor(1, 0);
  if (radix == 1000000)
    lcd.setCursor(0, 0);
}


void SendFrequency()
{
  si5351.set_freq((freq * 100ULL), SI5351_CLK0);
}

Saturday 7 December 2019

40m SSB Tramping Rig

Please see my YouTube channel for details of the build.

http://www.youtube.com/c/CharlieMorrisZL2CTM

2N3904 Antenna Amplifier (initial)

Voltage gain is set for 4 using Rdegen





J310 Antenna Amplifer

First need to determine Vp and Idss




2N3904 Antenna Amplifier (final)

Note, T2 is now a 10:5



7MHz BandPass Filter


2N3904 IF Amplifiers




 Relay and Crystal Configuration




High side versus low side injection



Initial RF Power Amplifier Driver








Software

#include <Wire.h>
#include <SPI.h>
#include <TM1637Display.h>
#include <si5351.h>
#include "LowPower.h"

const uint32_t bandStart = 7000000;   // start of 40m
const uint32_t bandEnd = 7300000;     // end of 40m
const uint32_t bandInit = 7100000;    // where to initially set the frequency
volatile long currentfreq = 0;
volatile long oldfreq = 0;
volatile int currentmode = 0;
volatile int oldmode = 0;

volatile uint32_t freq = bandInit ;     // this is a variable (changes) - set it to the beginning of the band
volatile uint32_t radix = 1000;         // how much to change the frequency by, clicking the rotary encoder will change this.

//const uint32_t BFO_freq = 9000000;      // Low side injection use 9000000;
const uint32_t BFO_freq = 8996400;      // High side injection use 8996400;

// Rotary encoder pins and other inputs
static const int rotBPin = 2;
static const int rotAPin = 3;
static const int pushPin = 4;
static const int PTTInput = 9;
static const int brightnessPin = A3;
static const int tunespeedLED = A2;
static const int gnd = 10;
static const int vcc = 11;
static const int DIO = 12;
static const int CLK = 13;

// Rotary encoder variables, used by interrupt routines
volatile int rotState = 0;
volatile int rotAval = 1;
volatile int rotBval = 1;


volatile long remainder = 0;
volatile long OnesHz = 0;
volatile long TensHz = 0;
volatile long HundredsHz = 0;
volatile long OneskHz = 0;
volatile long TenskHz = 0;
volatile long HundredskHz = 0;
volatile long OnesMHz = 0;
volatile long TensMHz = 0;
volatile int Brightness = 3;
volatile int batterySave = 0;

// Instantiate the Objects
TM1637Display display(CLK, DIO);    // CLK, DIO
Si5351 si5351;

void setup()
{
  // Set up frequency and radix switches
  pinMode(rotAPin, INPUT);
  pinMode(rotBPin, INPUT);
  pinMode(pushPin, INPUT);
  pinMode(brightnessPin, INPUT);
  pinMode(gnd, OUTPUT);
  pinMode(tunespeedLED, OUTPUT);
  pinMode(vcc, OUTPUT);
  pinMode(PTTInput, INPUT);

  // Set up pull-up resistors on inputs
  digitalWrite(rotAPin, HIGH);
  digitalWrite(rotBPin, HIGH);
  digitalWrite(pushPin, HIGH);
  digitalWrite(brightnessPin, HIGH);
  digitalWrite(gnd, LOW);
  digitalWrite(vcc, HIGH);
  digitalWrite(tunespeedLED, LOW);
  digitalWrite(PTTInput, LOW);

  // Set up interrupt pins
  attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE);

  // Initialize the display
  display.setBrightness(Brightness, true);
  UpdateDisplay();
  delay(1000);

  // Initialize the DDS
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
  si5351.set_correction(29100, SI5351_PLL_INPUT_XO);      // Set to specific Si5351 calibration number
  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_2MA);
  si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_2MA);
  SendFrequency();
}


void loop()
{
  LowPower.idle(SLEEP_60MS, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_ON, SPI_OFF, USART0_OFF, TWI_OFF);

  currentmode = digitalRead(PTTInput);
  if (currentmode != oldmode)
  {
    SendFrequency();
    oldmode = currentmode;
  }


  currentfreq = getfreq();                // Interrupt safe method to get the current frequency
  if (currentfreq != oldfreq)
  {
    UpdateDisplay();
    SendFrequency();
    oldfreq = currentfreq;
  }

  if (digitalRead(brightnessPin) == LOW)
  {
    Brightness--;
    display.setBrightness(Brightness, true);
    if (Brightness == -1)
    {
      display.setBrightness(0, false);
      digitalWrite(tunespeedLED, LOW);
      batterySave = 1;
    }
    if (Brightness == -2)
    {
      Brightness = 3;
      batterySave = 0;
    }
    UpdateDisplay();
    delay(500);
  }

  if ((radix == 100) && (batterySave == 0))
    digitalWrite(tunespeedLED, HIGH);

  if (radix == 1000)
    digitalWrite(tunespeedLED, LOW);
}


void wakeUp()
{
  // Just a handler for the sleep pin interrupt.
}


long getfreq()
{
  long temp_freq;
  cli();
  temp_freq = freq;
  sei();
  return temp_freq;
}


// Interrupt routines
void ISRrotAChange()
{
  if (digitalRead(rotAPin))
  {
    rotAval = 1;
    UpdateRot();
  }
  else
  {
    rotAval = 0;
    UpdateRot();
  }
}


void ISRrotBChange()
{
  if (digitalRead(rotBPin))
  {
    rotBval = 1;
    UpdateRot();
  }
  else
  {
    rotBval = 0;
    UpdateRot();
  }
}


void UpdateRot()
{
  switch (rotState)
  {

    case 0:                                         // Idle state, look for direction
      if (!rotBval)
        rotState = 1;                               // CW 1
      if (!rotAval)
        rotState = 11;                              // CCW 1
      break;

    case 1:                                         // CW, wait for A low while B is low
      if (!rotBval)
      {
        if (!rotAval)
        {
          // either increment radixindex or freq
          if (digitalRead(pushPin) == LOW)
          {
            if (radix == 1000)
              radix = 100;
            else if (radix == 100)
              radix = 1000;
          }
          else
          {
            freq = (freq + radix);
            if (freq > bandEnd)
              freq = bandEnd;
          }
          rotState = 2;                             // CW 2
        }
      }
      else if (rotAval)
        rotState = 0;                               // It was just a glitch on B, go back to start
      break;

    case 2:                                         // CW, wait for B high
      if (rotBval)
        rotState = 3;                               // CW 3
      break;

    case 3:                                         // CW, wait for A high
      if (rotAval)
        rotState = 0;                               // back to idle (detent) state
      break;

    case 11:                                        // CCW, wait for B low while A is low
      if (!rotAval)
      {
        if (!rotBval)
        {
          // either decrement radixindex or freq
          if (digitalRead(pushPin) == LOW)
          {
            if (radix == 100)
              radix = 1000;
            else if (radix == 1000)
              radix = 100;
          }
          else
          {
            freq = (freq - radix);
            if (freq < bandStart)
              freq = bandStart;
          }
          rotState = 12;                            // CCW 2
        }
      }
      else if (rotBval)
        rotState = 0;                             // It was just a glitch on A, go back to start
      break;

    case 12:                                        // CCW, wait for A high
      if (rotAval)
        rotState = 13;                              // CCW 3
      break;

    case 13:                                        // CCW, wait for B high
      if (rotBval)
        rotState = 0;                               // back to idle (detent) state
      break;
  }
}


void UpdateDisplay()
{
  TensMHz = freq / 10000000;                                // TensMHz = 12345678 / 10000000 = 1
  remainder = freq - (TensMHz * 10000000);                  // remainder = 12345678 - 10000000 = 2345678
  OnesMHz = remainder / 1000000;                            // OnesMhz = 2345678 / 1000000 = 2
  remainder = remainder - (OnesMHz * 1000000);              // remainder = 2345678 - (2 * 1000000) = 345678
  HundredskHz = remainder / 100000;                         // HundredskHz = 345678 / 100000 = 3
  remainder = remainder - (HundredskHz * 100000);           // remainder = 345678 - (3 * 100000) = 45678
  TenskHz = remainder / 10000;                              // TenskHz = 45678 / 10000 = 4
  remainder = remainder - (TenskHz * 10000);                // remainder = 45678 - (4 * 10000) = 5678
  OneskHz = remainder / 1000;                               // OneskHz = 5678 / 1000 = 5
  remainder = remainder - (OneskHz * 1000);                 // remainder = 5678 - (5 * 1000) = 678
  HundredsHz = remainder / 100;                             // HundredsHz = 678 / 100 = 6
  remainder = remainder - (HundredsHz * 100);               // remainder = 678 - (6 * 100) = 78
  TensHz = remainder / 10;                                  // TensHz = 78 / 10 = 7
  remainder = remainder - (TensHz * 10);                    // remainder = 78 - (7 * 10) = 8
  OnesHz = remainder;                                       // OnesHz = 8

  display.showNumberDec(((1000 * HundredskHz) + ( 100 * TenskHz) + (10 * OneskHz) + HundredsHz), true);
}


void SendFrequency()
{
  if (currentmode == 1)             // Transmit
  {
    si5351.set_freq(((freq + BFO_freq) * 100ULL), SI5351_CLK2);
    si5351.set_freq((BFO_freq * 100ULL), SI5351_CLK0);
  }
  else                              // Receive
  {
    //si5351.set_freq(((BFO_freq - freq) * 100ULL), SI5351_CLK0);   // Low side injection
    si5351.set_freq(((BFO_freq + freq) * 100ULL), SI5351_CLK0);   // High side injection

    si5351.set_freq((BFO_freq * 100ULL), SI5351_CLK2);
  }
}