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