One of the interesting things to do when operating narrow band is to use the QRSS frequencies which normally transmit slow morse or DFCW (dual frequency CW), to instead transmit ASCII characters on a set of 8 bit mapped frequencies, this sends a bit mapped font character.
This results in a display at QRSS3 speeds as shown in Argo software:
I am using an SDR receiver (this one is the Elektor SDR) tuned to 7050kHz centre frequency, with the IQ outputs going to a Startech A/D and on to my iMac computer. I am running the HDSDR software (under Wine) tuned to 7038.7kHz USB, so giving an audio tone of 1500kHz displayed in Argo
The transmitter is an Arduino UNO programming an Si5351 synthesiser module. This includes an RTC and TX is made every 5 mins
And here's couple more photos using the SDR_40M "Concept" SDR and Mac native DSP Radio software, audio is sent from the Radio to Argo using Soundflower software (recently updated for MacOS 10 and much improved)
Updated message after I got my Full Licence...
The code below is for transmission of an embedded line "CQ M0IFA IO92HF" (replace this with your text, max 16 characters if you want it to display on the LCD screen). The font here is a normal right-way-up font.
Code - updated 5-2-17
// HELL_S/MT_5x7 Sequential MultiTone Hellschreiber
// 5x7 font, normal
// Si5351 correction for ARDUINO COURSE BB, may need adustment
// Si5351 I2C bus
// SDA = A4
// SCL = A5
// LCD I2C bus (16x2)
// SDA = A4
// SCL = A5
// rotary encoder pins
// DT = 2
// CLK = 3
// SW = 4
// Si5351, LCDI2C libraries
#include "si5351.h"
#include "LiquidCrystal_I2C.h"
// LCD 0x27 or 0x3F
//#define LCDADDR 0x3F
#define LCDADDR 0x27
#define LCDCOLS 16
#define LCDROWS 2
// frequencies, base and shift (cHz)
#define BASEFREQ 707000000 // 40m, freqs 7077, 10132, 14070kHz
#define SHIFT 200 // 2Hz shift, 14Hz total BW
//each pixel 300ms, chargap 5pix = 1500ms
#define PIXTIME 300
#define CHARGAP 1500
// table of glyphs 0-9 & A-Z, cols b0-b7
byte glyphs[][6] = {
{' ', 0x00, 0x00, 0x00, 0x00, 0x00, },
{'/', 0x04, 0x08, 0x10, 0x20, 0x40, },
{'0', 0x7C, 0x8A, 0x92, 0xA2, 0x7C, },
{'1', 0x00, 0x42, 0xFE, 0x02, 0x00, },
{'2', 0x42, 0x86, 0x8A, 0x92, 0x62, },
{'3', 0x84, 0x82, 0xA2, 0xD2, 0x8C, },
{'4', 0x18, 0x28, 0x48, 0xFE, 0x08, },
{'5', 0xE4, 0xA2, 0xA2, 0xA2, 0x9C, },
{'6', 0x3C, 0x52, 0x92, 0x92, 0x0C, },
{'7', 0x80, 0x8E, 0x90, 0xA0, 0xC0, },
{'8', 0x6C, 0x92, 0x92, 0x92, 0x6C, },
{'9', 0x60, 0x92, 0x92, 0x94, 0x78, },
{'A', 0x7E, 0x88, 0x88, 0x88, 0x7E, },
{'B', 0xFE, 0x92, 0x92, 0x92, 0x6C, },
{'C', 0x7C, 0x82, 0x82, 0x82, 0x44, },
{'D', 0xFE, 0x82, 0x82, 0x44, 0x38, },
{'E', 0xFE, 0x92, 0x92, 0x92, 0x82, },
{'F', 0xFE, 0x90, 0x90, 0x90, 0x80, },
{'G', 0x7C, 0x82, 0x92, 0x92, 0x5E, },
{'H', 0xFE, 0x10, 0x10, 0x10, 0xFE, },
{'I', 0x00, 0x82, 0xFE, 0x82, 0x00, },
{'J', 0x04, 0x02, 0x82, 0xFC, 0x80, },
{'K', 0xFE, 0x10, 0x28, 0x44, 0x82, },
{'L', 0xFE, 0x02, 0x02, 0x02, 0x02, },
{'M', 0xFE, 0x40, 0x30, 0x40, 0xFE, },
{'N', 0xFE, 0x20, 0x10, 0x08, 0xFE, },
{'O', 0x7C, 0x82, 0x82, 0x82, 0x7C, },
{'P', 0xFE, 0x90, 0x90, 0x90, 0x60, },
{'Q', 0x7C, 0x82, 0x8A, 0x84, 0x7A, },
{'R', 0xFE, 0x90, 0x98, 0x94, 0x62, },
{'S', 0x62, 0x92, 0x92, 0x92, 0x8C, },
{'T', 0x80, 0x80, 0xFE, 0x80, 0x80, },
{'U', 0xFC, 0x02, 0x02, 0x02, 0xFC, },
{'V', 0xF8, 0x04, 0x02, 0x04, 0xF8, },
{'W', 0xFC, 0x02, 0x1C, 0x02, 0xFC, },
{'X', 0xC6, 0x28, 0x10, 0x28, 0xC6, },
{'Y', 0xE0, 0x10, 0x0E, 0x10, 0xE0, },
{'Z', 0x86, 0x8A, 0x92, 0xA2, 0xC2, },
};
// calc number of glyphs in glyphs table
#define NGLYPHS ((sizeof glyphs) / (sizeof glyphs[0]))
// freq variable
uint64_t freq = BASEFREQ; // base or bottom freq of pixels
// message to send
char msg[] = "TESTING M0IFA"; // max 16 char for LCD display, can transmit longer
// dds object
Si5351 dds;
// LCD object
LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS);
void setup() {
// init lcd & I2C
lcd.begin();
// init dds
dds.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
// set drive output 8mA (about 4dBm into 50R)
dds.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
// disable all outputs
dds.output_enable(SI5351_CLK0, 0);
dds.output_enable(SI5351_CLK1, 0);
dds.output_enable(SI5351_CLK2, 0);
// initial display
dispMsg(0, 0, " HELLSCHREIBER "); // title & clear line
Serial.println("START 1 sec");
delay(1000);
}
void loop() {
dispMsg(0, 0, " "); // clear title
dispMsg(0, 0, msg); // disp msg
dispFreq(1, 1, freq, 1); // display freq
dispMsg(11, 1, " USB ");
sendMsg(msg);
dispMsg(11, 1, " ");
dispMsg(0, 0, " HELLSCHREIBER "); // title & clear line
dispMsg(0, 1, " ");
delay(30000); // next 30sec delay
}
// take glyphs of message and send
void sendMsg(char *m) {
int c, i, j; // c scans msg, i & j scan the glyphs & rows
int pix; // pix scans pixel cols in glyph
c = 0;
while (m[c] != '\0') { // scan until end of msg
for (i = 0; i < NGLYPHS; i++) { // scan glyphs, always scan all rows to preserve timing
if (m[c] == glyphs[i][0]) { // if m[c] found at [i][0]
for (j = 1; j <= 5; j++) { // read glyphs[j][1] to [j][5]
for (pix = 1; pix <= 7; pix++) { // font cols b1-b7 for USB
if (bitRead(glyphs[i][j], pix) == 1) { // send pix
outFreq(freq + (pix * SHIFT), PIXTIME); // calc output freq
}
else {
delay(PIXTIME);
}
}
}
delay(CHARGAP);
}
}
c++;
}
}
// output f for t ms
void outFreq(uint64_t f, uint16_t t) {
dds.set_freq(f, SI5351_CLK0); // output freq
dds.output_enable(SI5351_CLK0, 1);
delay(t);
dds.output_enable(SI5351_CLK0, 0);
}
// display freq in kHz,col c, row r, d decimal places
void dispFreq(uint8_t c, uint8_t r, uint64_t f, uint8_t d)
{
lcd.setCursor(c, r); // clear last freq display
lcd.print((float)f / 100000, d); // convert to float for print function
lcd.print("kHz "); // + trailing spaces to clear previous display
}
// 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 char msg at col c, row r
void dispMsg(uint8_t c, uint8_t r, char *m)
{
lcd.setCursor(c, r);
lcd.print(m);
}
No comments:
Post a Comment