Code
// Universal_VFO_HELL outputs Hellschrieber message
// keys LP PA or 403020 PA on pin D12, VFO runs continuously
// ----- 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"
// LCD
#define LCDADDR 0x27
#define LCDCOLS 16
#define LCDROWS 2
// rotary Encoder pins 2 & 3 (DT & CLK)
#define DT 2
#define CLK 3
#define SW 4
// RX & TX enable
#define RX 13
#define TX 12
#define MSGSIZE 30
// dds object
Si5351 dds;
// LCD object
LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS);
// rotary Encoder object
Rotary rot = Rotary(DT, CLK);
// message, new data in flag
char msg[MSGSIZE];
bool newMsg = false;
// band
byte band;
// freq
uint32_t freq;
uint32_t startFreq[] = {707700000, 1014400000, 1406000000};
typedef struct glyph {
char ch ;
word col[7] ;
} Glyph ;
const Glyph glyphtab[] PROGMEM = {
{' ', {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}},
{'A', {0x07fc, 0x0e60, 0x0c60, 0x0e60, 0x07fc, 0x0000, 0x0000}},
{'B', {0x0c0c, 0x0ffc, 0x0ccc, 0x0ccc, 0x0738, 0x0000, 0x0000}},
{'C', {0x0ffc, 0x0c0c, 0x0c0c, 0x0c0c, 0x0c0c, 0x0000, 0x0000}},
{'D', {0x0c0c, 0x0ffc, 0x0c0c, 0x0c0c, 0x07f8, 0x0000, 0x0000}},
{'E', {0x0ffc, 0x0ccc, 0x0ccc, 0x0c0c, 0x0c0c, 0x0000, 0x0000}},
{'F', {0x0ffc, 0x0cc0, 0x0cc0, 0x0c00, 0x0c00, 0x0000, 0x0000}},
{'G', {0x0ffc, 0x0c0c, 0x0c0c, 0x0ccc, 0x0cfc, 0x0000, 0x0000}},
{'H', {0x0ffc, 0x00c0, 0x00c0, 0x00c0, 0x0ffc, 0x0000, 0x0000}},
{'I', {0x0ffc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}},
{'J', {0x003c, 0x000c, 0x000c, 0x000c, 0x0ffc, 0x0000, 0x0000}},
{'K', {0x0ffc, 0x00c0, 0x00e0, 0x0330, 0x0e1c, 0x0000, 0x0000}},
{'L', {0x0ffc, 0x000c, 0x000c, 0x000c, 0x000c, 0x0000, 0x0000}},
{'M', {0x0ffc, 0x0600, 0x0300, 0x0600, 0x0ffc, 0x0000, 0x0000}},
{'N', {0x0ffc, 0x0700, 0x01c0, 0x0070, 0x0ffc, 0x0000, 0x0000}},
{'O', {0x0ffc, 0x0c0c, 0x0c0c, 0x0c0c, 0x0ffc, 0x0000, 0x0000}},
{'P', {0x0c0c, 0x0ffc, 0x0ccc, 0x0cc0, 0x0780, 0x0000, 0x0000}},
{'Q', {0x0ffc, 0x0c0c, 0x0c3c, 0x0ffc, 0x000f, 0x0000, 0x0000}},
{'R', {0x0ffc, 0x0cc0, 0x0cc0, 0x0cf0, 0x079c, 0x0000, 0x0000}},
{'S', {0x078c, 0x0ccc, 0x0ccc, 0x0ccc, 0x0c78, 0x0000, 0x0000}},
{'T', {0x0c00, 0x0c00, 0x0ffc, 0x0c00, 0x0c00, 0x0000, 0x0000}},
{'U', {0x0ff8, 0x000c, 0x000c, 0x000c, 0x0ff8, 0x0000, 0x0000}},
{'V', {0x0ffc, 0x0038, 0x00e0, 0x0380, 0x0e00, 0x0000, 0x0000}},
{'W', {0x0ff8, 0x000c, 0x00f8, 0x000c, 0x0ff8, 0x0000, 0x0000}},
{'X', {0x0e1c, 0x0330, 0x01e0, 0x0330, 0x0e1c, 0x0000, 0x0000}},
{'Y', {0x0e00, 0x0380, 0x00fc, 0x0380, 0x0e00, 0x0000, 0x0000}},
{'Z', {0x0c1c, 0x0c7c, 0x0ccc, 0x0f8c, 0x0e0c, 0x0000, 0x0000}},
{'0', {0x07f8, 0x0c0c, 0x0c0c, 0x0c0c, 0x07f8, 0x0000, 0x0000}},
{'1', {0x0300, 0x0600, 0x0ffc, 0x0000, 0x0000, 0x0000, 0x0000}},
{'2', {0x061c, 0x0c3c, 0x0ccc, 0x078c, 0x000c, 0x0000, 0x0000}},
{'3', {0x0006, 0x1806, 0x198c, 0x1f98, 0x00f0, 0x0000, 0x0000}},
{'4', {0x1fe0, 0x0060, 0x0060, 0x0ffc, 0x0060, 0x0000, 0x0000}},
{'5', {0x000c, 0x000c, 0x1f8c, 0x1998, 0x18f0, 0x0000, 0x0000}},
{'6', {0x07fc, 0x0c66, 0x18c6, 0x00c6, 0x007c, 0x0000, 0x0000}},
{'7', {0x181c, 0x1870, 0x19c0, 0x1f00, 0x1c00, 0x0000, 0x0000}},
{'8', {0x0f3c, 0x19e6, 0x18c6, 0x19e6, 0x0f3c, 0x0000, 0x0000}},
{'9', {0x0f80, 0x18c6, 0x18cc, 0x1818, 0x0ff0, 0x0000, 0x0000}},
{'*', {0x018c, 0x0198, 0x0ff0, 0x0198, 0x018c, 0x0000, 0x0000}},
{'.', {0x001c, 0x001c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}},
{'?', {0x1800, 0x1800, 0x19ce, 0x1f00, 0x0000, 0x0000, 0x0000}},
{'!', {0x1f9c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}},
{'(', {0x01e0, 0x0738, 0x1c0e, 0x0000, 0x0000, 0x0000, 0x0000}},
{')', {0x1c0e, 0x0738, 0x01e0, 0x0000, 0x0000, 0x0000, 0x0000}},
{'#', {0x0330, 0x0ffc, 0x0330, 0x0ffc, 0x0330, 0x0000, 0x0000}},
{'$', {0x078c, 0x0ccc, 0x1ffe, 0x0ccc, 0x0c78, 0x0000, 0x0000}},
{'/', {0x001c, 0x0070, 0x01c0, 0x0700, 0x1c00, 0x0000, 0x0000}},
} ;
#define NGLYPHS (sizeof(glyphtab)/sizeof(glyphtab[0]))
void setup()
{
Serial.begin(9600);
// init LCD & backlight on
lcd.init();
lcd.backlight();
pinMode(SW, INPUT_PULLUP);
pinMode(RX, OUTPUT) ;
pinMode(TX, OUTPUT) ;
// init dds si5351 module, "0" = default 25MHz XTAL
dds.init(SI5351_CRYSTAL_LOAD_8PF, 0);
dds.output_enable(SI5351_CLK0, 0); // all disable
dds.output_enable(SI5351_CLK1, 0);
dds.output_enable(SI5351_CLK2, 0);
band = 0;
freq = startFreq[band];
// CLK0 output at freq
dds.set_freq(freq, 0ULL, SI5351_CLK0); // VFO tuned to startfreq
dispMsg(0, 0, "HELL ");
dispFreq(5, 0, freq, 2);
}
void loop()
{
tune();
chgBand();
getMsg();
encodeIt();
}
void tune()
{
unsigned char dir; // enc direction
dir = rot.process(); // read encoder
if (dir != DIR_NONE) // turned?
{
if (dir == DIR_CW) freq += 1000; // increment freq +/-10Hz
else freq -= 1000;
dispFreq(5, 0, freq, 2); // update freq disp
}
}
void chgBand()
{
if (digitalRead(SW) == LOW)
{
while (!digitalRead(SW)); // wait for release
if (band == 2)
{
band = 0;
}
else
{
band++;
}
freq = startFreq[band];
dispFreq(5, 0, freq, 2); // update freq disp
}
}
void encodeIt()
{
byte n;
n = 0;
if (newMsg == true)
{
while (msg[n] != '\0')
{
dispChar(n, 1, msg[n]); // display message, char by char
encodeChar(msg[n++]);
}
newMsg = false;
dispMsg(0, 0, "HELL "); // reset display
dispFreq(5, 0, freq, 2);
dispMsg(0, 1, " ");
}
}
void encodeChar(int ch)
{
int i, x, y, fch ;
word fbits ;
// search continues all the way to the end, to keep timing right
for (i = 0; i < NGLYPHS; i++)
{
fch = pgm_read_byte(&glyphtab[i].ch);
if (fch == ch)
{
for (x = 0; x < 7; x++)
{
fbits = pgm_read_word(&(glyphtab[i].col[x]));
for (y = 0; y < 14; y++)
{
if (fbits & (1 << y))
digitalWrite(TX, LOW) ; // TX = LOW
else
digitalWrite(TX, HIGH) ;
delayMicroseconds(4045L) ; // adjust for bit timing
}
}
}
}
}
// get input msg
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';
ndx = 0;
Serial.println(msg);
newMsg = true;
}
}
}
// display char msg at col c, row r
void dispMsg(uint8_t c, uint8_t r, char *m)
{
lcd.setCursor(c, r);
lcd.print(m);
}
// display a number at col c, row r
void dispNum(uint8_t c, uint8_t r, uint16_t n)
{
lcd.setCursor(c, r);
lcd.print(n);
}
// display character m at col c, row r
void dispChar(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