The LCD displays RX & TX and the message letter-by-letter as it is sent, with the output frequency.
The transmit frequency is preset at 101401000Hz (10140.100kHz), but can be tuned with the rotary encoder in 10Hz steps.
Code
// Universal_QRSS_KB sends a QRSS3 message from the KB
// uses Universal VFO shield
// 30m only (at the moment), at 1014000000Hz
// IQ output for SDR GRG is at 10140kHz
// tunable in 10Hz steps, button does nothing
// ----- SHIELD CONNECTIONS
// DDS I2C SI5351
// SCL = A5
// SDA = A4
// I2C address 0x60
// ------
// display I2C LCD 16 * 2
// o A5 SCL (y)
// o A4 SDA (or)
// o +5 (r)
// o GND (bwn)
// I2C address 0x27
// -----
// encoder KY-040
// o D2 DT (y)
// o D3 CLK (g)
// o +5 (r)
// o GND (bwn)
// I2C, Si5351 libraries
#include "Wire.h"
#include "si5351.h"
#include "LiquidCrystal_I2C.h"
#include "Rotary.h"
// rotary Encoder pins 2 & 3 (DT & CLK), TX & RX enable (LOW)
#define DT 2
#define CLK 3
#define TX 12
#define RX 13
// tuning freq STEPS, 1000cHz (10Hz)
#define STEPS 1000
// 3sec dot time
#define DOT 3000
// ASCII input
char msg[30];
bool newMsg = false;
// start freq
uint32_t qrg = 1014000000; // SDR 10140kHz
uint32_t freq = 1014000000; // cHz
// dds object
Si5351 dds;
// lcd object
LiquidCrystal_I2C lcd(0x27, 16, 2);
// rotary Encoder object
Rotary rot = Rotary(DT, CLK);
// morse code strings, _ = dot space, 0-9 numbers, 10-36 A..Z
// table from 0 - 36
char morse[][8] = {
"-----_", // 0
".----_", // 1-9
"..---_",
"...--_",
"....-_",
"....._",
"-...._",
"--..._",
"---.._",
"----._",
".-_", // A
"-..._", // B
"-.-._", // C
"-.._", // D
"._", // E
"..-._", // F
"--._", // G
"...._", // H
".._", // I
".---_", // J
"-.-_", // K
".-.._", // L
"--_", // M
"-._", // N
"---_", // O
".--._", // P
"--.-_", // Q
".-._", // R
"..._", // S
"-_", // T
"..-_", // U
"...-_", // V
".--_", // W
"-..-_", // X
"-.--_", // Y
"--.._", // Z
"__", // word space
};
void setup()
{
Serial.begin(9600);
// init dds si5351 module, "0" = default 25MHz XTAL
dds.init(SI5351_CRYSTAL_LOAD_8PF, 0);
// CLK2 output qrg x 4, for IQ
dds.set_freq(qrg * 4, 0ULL, SI5351_CLK2); // CLK2/IQ SDR tuned to 10104.00kHz
// CLK 0, 1 off, CLK2 on
dds.output_enable(SI5351_CLK0, 0);
dds.output_enable(SI5351_CLK1, 0);
dds.output_enable(SI5351_CLK2, 1); // SDR on
// init LCD & backlight on
lcd.init();
lcd.backlight();
// encoder, button, RX, TX, band and XMIT pins
pinMode(DT, INPUT_PULLUP);
pinMode(CLK, INPUT_PULLUP);
pinMode(RX, OUTPUT); // SDR RX enable
pinMode(TX, OUTPUT); // QRSS TX enable
rx(); // receive
freqOut(freq); // output freq
dispMsg(0, 0, "QRSS "); // display title
dispFreq(5, 0, freq, 2); // display freq
}
void loop()
{
tune();
getMsg();
qrssOut();
}
void tune()
{
unsigned char dir;
dir = rot.process(); // read encoder
if (dir != DIR_NONE) // turned?
{
if (dir == DIR_CW) freq += STEPS; // increment freq +/- STEPS
if (dir == DIR_CCW) freq -= STEPS;
freqOut(freq); // output freq
dispFreq(5, 0, freq, 2); // display freq
}
}
// get input msg[] uc
void getMsg()
{
static byte ndx = 0; // ndx into msg[]
char in;
while (Serial.available() > 0 && newMsg == false)
{
in = Serial.read();
if (in != '\n')
{
if (in >= 97 & in <= 122) in = in - 32; // to uc
msg[ndx] = in;
ndx++;
}
else
{
msg[ndx] = '\0'; // terminate msg
Serial.write(msg); // echo msg
ndx = 0;
newMsg = true;
}
}
}
// look up morse string, send char by char
void qrssOut()
{
static byte ndx;
byte n;
char c;
// step along msg chraracters
ndx = 0;
while (msg[ndx] != '\0' && newMsg == true)
{
tx(); // transmit
dispChar(ndx, 1, msg[ndx]); // display char at col ndx
// convert to position in morse table
// convert SPACE
if (msg[ndx] == 32)
c = msg[ndx] + 4;
// convert ASCII
else if (msg[ndx] >= 48 && msg[ndx] <= 57) // table 0-9
c = msg[ndx] - 48;
else if (msg[ndx] >= 65 && msg[ndx] <= 90) // table A-Z (uc)
c = msg[ndx] - 55;
else if (msg[ndx] >= 97 && msg[ndx] <= 122) // table a-z (lc)
c = msg[ndx] - 87;
// output morse, up to SPACE
n = 0;
while (morse[c][n] != '_')
{
if (morse[c][n] == '.') dotOut(); // dot out
else if (morse[c][n] == '-') dashOut(); // dash out
n++;
}
spaceOut(); // end of char
ndx++;
}
// end of msg
if(newMsg == true)
{
dispMsg(0, 1, " "); // clear msg c, r
Serial.println();
rx(); // receive
}
newMsg = false;
}
// QRSS frequency (in cHz) on CLK0
void freqOut(uint32_t f)
{
dds.set_freq(f, 0ULL, SI5351_CLK0);
}
// send a dot for DOT time
void dotOut()
{
unsigned long t;
dds.output_enable(SI5351_CLK0, 1);
t = millis();
while (millis() < t + DOT);
dds.output_enable(SI5351_CLK0, 0);
t = millis();
while (millis() < t + DOT);
}
// send a dash for 3* DOT time
void dashOut()
{
unsigned long t;
dds.output_enable(SI5351_CLK0, 1);
t = millis();
while (millis() < t + DOT * 3);
dds.output_enable(SI5351_CLK0, 0);
t = millis();
while (millis() < t + DOT);
}
// word space for 2 * DOT time (each character has its own one DOT space
void spaceOut()
{
unsigned long t;
t = millis();
while (millis() < t + DOT * 2);
}
//switch to transmit
void tx()
{
digitalWrite(RX, HIGH);
digitalWrite(TX, LOW);
dispMsg(14, 1, "TX");
}
// switch to receive
void rx()
{
digitalWrite(TX, HIGH);
digitalWrite(RX, LOW);
dispMsg(14, 1, "RX");
}
// display character m at col c
void dispChar(uint8_t c, uint8_t r, char m)
{
lcd.setCursor(c, r);
lcd.print(m);
}
// display msg on row l
void dispMsg(uint8_t c, uint8_t r, char *m)
{
lcd.setCursor(c, r);
lcd.print(m);
}
// display freq in kHz,col c, row r, d decimal places
void dispFreq(uint8_t c, uint8_t r, uint32_t f, uint8_t d)
{
lcd.setCursor(c, r); // clear last freq display
lcd.print(" ");
lcd.setCursor(c, r); // clear last freq display
lcd.print((float)f / 100000, d); // convert to float for print function
lcd.print("kHz");
}
No comments:
Post a Comment