SSB_Radio_Control/SSB_Radio_Control.ino

376 wiersze
13 KiB
C++

/*
SSB_Radio_Control
Dean Souleles, KK4DAS, contact kk4das@gmail.com
This sketch implement s basic SSB radio control panel with the following features:
Dual VFO A/B
Rotary encoder for tuning, push button to change tuning increment
SI5351 Clock generator for the LO and BFO
CAT Control (emulates an ICOM IC-746)
Split mode support (Split from CAT, manual split requres Nextion touch screen)
Settings memory (last frequency and mode are saved)
Optional S-Meter
Controls
* Rotary encoder to change frequence
* Rotary encode button changes tuning increment
* VFO A/B Select toggle
* Mode select USB/LSB toggle
* Tune button (emits 10 second pulsed tone at 800Hz for tuning)
* MOX toggle - puts rig in to Tx/Rx
* Optional dual-band support 20/40
Modules for different display types
* 20x4 LCD
* 320x240 TFT color display
* 2.8" Nextion Touch Screen
Display features
* Dual VFOS
* Mode indicator SSB/LSB
* Tx/Rx ndicator
* TuningStep Inidicator
* Optional S Meter
* Banner including callsign
Additional controls with the Nextion display
* Continuous scanning
* Split mode
Version 1.4
March 9 2021
Rstored LCD Display Option
Compile time selection of S-Meter and Dual Band mods
Refactoring of encoder handling
Version 1.3
Jan 25, 2021
Changed CAT module to IC-746
Version 1.2
Dec 14, 2020
Dual Band 20/40 Support
S-Meter
Version 1.1
Dec 13. 2020
Ported to Nano Every for more sweet SRAM
* * Updated interrupt handling in Encoder.cpp to work with Nano Every (as well as UNO/Nano)
* * Replaced SoftwareSerial connections to Nextion with Hardware Serial - Serial1
Version 1.0
Aug 13, 2020
Adapted from SimpleSSB Sketch by N6QW, Pete Juliano and others
NOTE TO BUILDERS
This is a reference implementation of an SSB radio control program for a homebrew SSB transceiver.
It is a fully functioning SSB radio control program. While it has been built for my particular hardware
configuration every attempt has been made to make it modular in design so that the builder can swap out
modules at will. It should be fairly straight forward to adapt to the builder's hardware selection
of switches, buttons and knobs or even alternate displays.
*/
#include "RadioControl.h"
#ifdef DEBUG
char debugmsg[25];
#endif
//=============== Globals ============================================
//////////////////////////////////////////////////////////////////////
// //
// si5351 Clock Module //
// //
//////////////////////////////////////////////////////////////////////
Si5351 si5351;
// Calibration offest - adjust for variability in the SI5351 module
// crystal - must be set for the particular SI5351 installed
//#define CALIBRATION_OFFSET 1190 // Calibration for the SI-5351
#define CALIBRATION_OFFSET 880 // Calibration for the SI-5351
//////////////////////////////////////////////////////////////////////
// //
// BFO and VFO Constants and Variables //
// //
//////////////////////////////////////////////////////////////////////
#ifdef BFO12MHZ
const uint32_t USB_BFO = 12001600L;
const uint32_t LSB_BFO = 11998600L;
#endif
#ifdef BFO9MHZ
const uint32_t USB_BFO = 9001500L;
const uint32_t LSB_BFO = 8998500L;
#endif
uint32_t bfo = LSB_BFO; // Startup BFO frequency
const uint32_t BFO_DELTA = USB_BFO - LSB_BFO; // Difference between USB and LSB for BFO change
//
// Startup VFO A/B frequencies
//
uint32_t vfoAfreq = 7200000L; // 7.200.000
uint32_t vfoBfreq = 7074000L; // FT-8 7.074.000
byte vfoASideband = LSB;
byte vfoBSideband = USB;
uint32_t increment = 1000; // startup VFO tuning increment in HZ.
//////////////////////////////////////////////////////////////////////
// //
// Active VFO //
// //
//////////////////////////////////////////////////////////////////////
byte active_vfo = VFOA; // startup on VFOA
//////////////////////////////////////////////////////////////////////
// //
// Sideband Selection //
// //
//////////////////////////////////////////////////////////////////////
byte sideband = LSB; // startup in LSB
//////////////////////////////////////////////////////////////////////
// //
// Sideband Selection //
// //
/////////////////////////////////////////////////////////////////////
uint32_t band20Freq = 14200000L; // 14.200.000
uint32_t band40Freq = 7200000L; // 7.200.000
byte band20Sideband = USB;
byte band40Sideband = LSB;
byte band = BAND40;
//////////////////////////////////////////////////////////////////////
// //
// Transmit / Receive Indicators //
// //
//////////////////////////////////////////////////////////////////////
byte TxRxState = RX; // startup in RX
byte lastTxRxState = RX; // previous TxRxState
byte txSource = PTT_MIC; // transmit source - Mic, Tune, CAT
//////////////////////////////////////////////////////////////////////
// //
// S Meter 0-9 +10, +20 +30 //
// //
//////////////////////////////////////////////////////////////////////
byte smeter = 0; // startup s_meter reading (requires SMETER)
//////////////////////////////////////////////////////////////////////
// //
// Split Mode On/Off //
// //
//////////////////////////////////////////////////////////////////////
bool split = false;
///////////////////////////////////////////////////////////
// setBandFilters(band) //
// For 20 meters turn relay ON (NO) //
// For 40 meters turn relay OFF (NC) //
///////////////////////////////////////////////////////////
void setBandFilters(int band) {
#ifdef DUAL_BAND
switch (band) {
case BAND20:
digitalWrite(BAND_PIN, HIGH);
break;
case BAND40:
digitalWrite(BAND_PIN, LOW);
break;
}
#endif
}
#ifdef CW
//
// setCW()
//
// Experimental code to generate CW tone on key down at 700Hz above the dial frequency
// Needs a bunch of scaffolding to implement CW mode
//
// Turns off the BFO, sets the LO to the VFO frequency + 700
//
// After testing -
// tone produced OK but needs an amplifier to get significant power out
//
void setCW() {
si5351.set_freq(0, 0, SI5351_CLK2); // turn off BFO
si5351.set_freq(vfoAfreq+700L , SI5351_PLL_FIXED, SI5351_CLK0); // set LO to operating freq
}
#endif
//********************setVFO******************************************
void setVFO(uint32_t freq) {
//
// Set CLK0 to the to input frequency adjusted for the current BFO frequency
#ifdef DUAL_BAND
//
// Set filters for the band based on frequency
// Save frequency and sideband for band switching
//
if (freq >= BAND20_EDGE) {
setBandFilters(BAND20);
band20Freq = freq;
band20Sideband = sideband;
band = BAND20;
} else if (freq >= BAND40_EDGE) {
setBandFilters(BAND40);
band40Freq = freq;
band40Sideband = sideband;
band=BAND40;
}
#endif
si5351.set_freq(freq + bfo, SI5351_PLL_FIXED, SI5351_CLK0);
startSettingsTimer(); // start timer to save current settings
}
void setBFO(uint32_t freq) {
//
// Set CLK2 to the to input frequency
//
si5351.set_freq(freq, 0, SI5351_CLK2);
}
//*********************Setup Arduino Pins*****************************
void setupPins() {
//
// Set the control buttons to INPUT_PULLUP
// Button state will be HIGH when open and LOW when pressed
//
pinMode(TUNE_BTN, INPUT_PULLUP); // Tune - momentary button
pinMode(VFO_BTN, INPUT_PULLUP); // VFO A/B Select - momentary button
pinMode(SIDEBAND_BTN, INPUT_PULLUP); // Upper/lower SB Select - momentary button
pinMode(BAND_BTN, INPUT_PULLUP); // Band Switch 20/40 - momentary button
pinMode(PTT_SENSE, INPUT_PULLUP); // Mic PTT swtich
pinMode(PTT, OUTPUT); digitalWrite(PTT, LOW); // HIGH to enable TX
pinMode(BAND_PIN, OUTPUT); digitalWrite(BAND_PIN, LOW); // Band Switch Relay (LOW = NC = 40m, HIGH = NO = 20m)
pinMode(LED_BUILTIN, OUTPUT);
}
//**********************Initialize SI5351******************************
void setupSI5351() {
si5351.init(SI5351_CRYSTAL_LOAD_8PF);
si5351.set_correction(CALIBRATION_OFFSET); // calibration offset
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); // Higher Drive since it is a ADE-1 DBM
si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA);
si5351.set_freq(bfo, 0, SI5351_CLK2); // Initialize the bfo
//
// Initialize the VFO
//
switch (active_vfo) {
case VFOA:
setVFO(vfoAfreq);
break;
case VFOB:
setVFO(vfoBfreq);
break;
}
}
//////////////////////////////////////////////////////////////////////
// Setup //
// //
// Called once by the Arduino operating system at startup //
// All initialization code goes here //
// //
//////////////////////////////////////////////////////////////////////
void setup() {
uint32_t vfoActfreq;
uint32_t vfoAltfreq;
#ifdef DEBUG
Serial.begin(57600);
#endif
setupPins(); // Initialize arduino pins
setupEncoder(); // Initialize interrupt service for rotary encoder
setupSettings(); // Retrive settings from EEPROM
setupSI5351();
if (active_vfo == VFOA) {
vfoActfreq = vfoAfreq;
vfoAltfreq = vfoBfreq;
} else {
vfoActfreq = vfoBfreq;
vfoAltfreq = vfoAfreq;
}
// Initialize the display with startup values
Delay(500); // short delay to let the display initialize - needed for Nextion
// Construct banner for TFT or Nextion display
// "Vx.x RIGNAME CALLSIGN"
String banner;
banner = F("V");
banner += F(VERSION);
banner += F(" ");
banner += F(RIGNAME);
banner += F(" ");
banner += F(CALLSIGN);
displaySetup(banner, // version number. call sign
vfoActfreq, vfoAltfreq, // Initial active and alternate VFO
active_vfo, // VFO A/B indicator
TxRxState, // TX/RX indicator
sideband, // LSB/USB,
split, // Split mode on/off
increment, // Tuning increment
smeter); // S Meter
setupCat();
}
void loop() {
CheckEncoder(); //VFO frequency changes
CheckIncrement(); // Encoder Button
#ifdef DUAL_BAND
CheckBand(); // Band Switch 20/40
#endif
CheckVFO(); // VFO A/B change
CheckSB(); // USB/LSB change
CheckPTT(); // Check for Mic PTT
CheckTune(); // Check for Tune button press
#ifdef SMETER
CheckSmeter(); // Signal strength
#endif
CheckCat(); // CAT Control
CheckSettings(); // Update EEPROM on Settings Change
#ifdef DISPLAY_NEXTION
CheckTouch(); // Check for touch screen action
#endif
}