Sunday 27 August 2023

Digital Modes Transceiver

 


#include <SPI.h>

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>

#include <si5351.h>

#include <FreqMeasure.h>


#define MODE_SWITCH 7                                         // Mode switch is on D7

#define PTT 2                                                 // PTT output is on D2


double sum = 0;

int count = 0;

int TX_heartbeat = 0;

int TX_heartbeat_count = 0;

float frequency = 0;

unsigned long start_vox_timer;

unsigned long current_vox_timer;

long Mode = 0;

const long WSPR_40 = 7038600;

const long FT8_40 = 7074000;

const long JS8_40 = 7078000;

const long WSPR_20 = 14095600;

const long FT8_20 = 14074000;

const long JS8_20 = 14078000;


// Instantiate the Objects

Si5351 si5351;

Adafruit_SSD1306 display(4);


void setup()

{

  // Set up switches

  pinMode(MODE_SWITCH, INPUT);

  digitalWrite(MODE_SWITCH, HIGH);

  pinMode(PTT, OUTPUT);

  digitalWrite(PTT, LOW);


  // Initialize the frequency measureing routine

  FreqMeasure.begin();


  Mode = WSPR_40;


  // Initialize the display with the I2C addr 0x3C

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

  display.setTextColor(WHITE);

  display.clearDisplay();

  display.setTextSize(2);

  UpdateDisplay();


  // Initialize the DDS

  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);

  si5351.set_correction(123200, 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.output_enable(SI5351_CLK0, 0);


  start_vox_timer = millis();                               // Initial start of the vox timer


  //Serial.begin(57600);

}


void loop()

{

  current_vox_timer = millis();                             // Update the vox timer in preparation


  if (digitalRead(MODE_SWITCH) == LOW)

  {

    if (Mode == WSPR_40)

      Mode = FT8_40;

    else if (Mode == FT8_40)

      Mode = JS8_40;

    else if (Mode == JS8_40)

      Mode = WSPR_20;

    else if (Mode == WSPR_20)

      Mode = FT8_20;

    else if (Mode == FT8_20)

      Mode = JS8_20;

    else if (Mode == JS8_20)

      Mode = WSPR_40;


    UpdateDisplay();

    delay(100);

  }


  if (FreqMeasure.available())                              // If available, average several frequency readings for greater accuuracy

  {

    TX_heartbeat = 1;                                       // Set the TX_heartbeat to 1 as we are still transmitting

    TX_heartbeat_count = 0;                                 // Reset the TX heartbeat counter

    sum = sum + FreqMeasure.read();

    count = count + 1;


    if (count > 60)

    {

      frequency = FreqMeasure.countToFrequency(sum / count);

      si5351.output_enable(SI5351_CLK0, 1);                                 // Turn on the Si5351

      digitalWrite(PTT, HIGH);                                              // Key the transmitter

      si5351.set_freq(((frequency + Mode) * 100ULL), SI5351_CLK0);          // Convert to TX freq and update the Si5351

      sum = 0;                                                              // Clear the sum ready for next time

      count = 0;                                                            // Reset the count ready for next time

    }

  }


  if (current_vox_timer - start_vox_timer >= 100)           // Test to see if we are still transmitting

  {

    if (TX_heartbeat == 0)

      TX_heartbeat_count = TX_heartbeat_count + 1;          // Increment the counter


    if (TX_heartbeat_count >= 10)                           // Turn off after 1 second of no TX heartbeat (10 x 100mS = 1Sec)

      {

        si5351.output_enable(SI5351_CLK0, 0);               // Turn off the Si5351

        digitalWrite(PTT, LOW);                             // Turn off the transmitter

      }


    start_vox_timer = current_vox_timer;                    // Reset the vox timer ready for next time

  }


  TX_heartbeat = 0;                                         // Set the TX_heartbeat to 0 ready for next check

}



void UpdateDisplay()

{

  display.clearDisplay();

  display.setCursor(0, 0);

  display.println("Digi Radio");

  display.setCursor(0, 18);

  if (Mode == WSPR_40)

    display.println("40m WSPR");

  if (Mode == FT8_40)

    display.println("40m FT8");

  if (Mode == JS8_40)

    display.println("40m JS8");

  if (Mode == WSPR_20)

    display.println("20m WSPR");

  if (Mode == FT8_20)

    display.println("20m FT8");

  if (Mode == JS8_20)

    display.println("20m JS8");

  display.display();

}