To round off this session on generating various digital transmissions with the AD9850 synthesiser and the Arduino, here is the RTTY one.
Beacon Tx
SDR RX
Received signals, using MacOS MultiMode Cooca software
And here's the code
// BCN_RTTY Beacon for RTTY
// V1.1 9-3-17
// thanks to F0GOJ for some of the code
// AD9850
// W_CLK 8
// FQ_UD 9
// DATA 10
// RESET 11
// LCD I2C bus (16x2)
// SDA = A4
// SCL = A5
// ADS9850, LCD and Rotary Encoder libraries
#include "ADS9850.h"
#include "LiquidCrystal_I2C.h"
// AD9850 pins
#define W_CLK 8
#define FQ_UD 9
#define DATA 10
#define RESET 11
// chose address of 0x27 or 0x3F for LCD
//#define LCDADDR 0x27
#define LCDADDR 0x3F
#define LCDCOLS 16
#define LCDROWS 2
// baudot varicode in b4-b0 (sent b0->b4)
char rttyVaricode[59] = {
4, 22, 17, 5, 18, 0, 11, 26, 30, 9,
0, 0, 6, 24, 7, 23, 13, 29, 25, 16,
10, 1, 21, 28, 12, 3, 14, 15, 0, 0,
0, 19, 0, 24, 19, 14, 18, 16, 22, 11,
5, 12, 26, 30, 9, 7, 6, 3, 13, 29,
10, 20, 1, 28, 15, 25, 23, 21, 17
};
#define FIGS 27
#define LTRS 31
// beacon message to send (u.c.)
char msg[] = "RTTY BCN M0IFA";
// freq in Hz and cHz
double freqHz = 7080000; // frequency Hz
double freqChz = 0; // sub freuency cHz
// repeat time (ms)
unsigned long repeat = 2000;
// ads (analog-output digital synthesiser) object
ADS9850 ads;
// lcd object
LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS);
void setup() {
// init LCD
lcd.begin();
//init AD9850
ads.begin(W_CLK, FQ_UD, DATA, RESET); // initialise synthesiser, pins
dispMsg(0, 0, "RTTY");
dispFreq(5, 0, freqHz, freqChz, 0); // display FREQ xxxxxx.xx kHz col 5 row 0
dispMsg(0, 1, msg); // out msg
}
void loop() {
// send message at frequency
sendMsg(freqHz, freqChz, msg);
delay(repeat); // repeat
}
void sendMsg(double fHz, double fChz, char *m) {
bool figsLtrs; // FIGS/LTRS toggle
char c;
figsLtrs = 1; // start in letter mode
c = *m++;
while ( c != '\0') { // EOM?
c = toupper((int)c); // get char, uppercase
if (c == 10) { // Line Feed 8
rttyTxByte(fHz, fChz, 8);
}
else if (c == 13) { // Carriage Return 2
rttyTxByte(fHz, fChz, 2);
}
else if (c == 32) {
rttyTxByte(fHz, fChz, 4);
}
else if (c > ' ' && c <= 'Z' ) { // non-baudot chars sent as blanks 00000
c = c - ' '; // c index 0-58
if (c < 33) {
if (figsLtrs == 1) { // if LTRS
figsLtrs = 0; // toggle to FIGS
rttyTxByte(fHz, fChz, FIGS); // send 27
}
}
else if (figsLtrs == 0) { // if FIGS
figsLtrs = 1; // toggle to LTRS
rttyTxByte(fHz, fChz, LTRS); // send 31
}
rttyTxByte(fHz, fChz, rttyVaricode[c]); // Send the 5 bits word
}
c = *m++; // Next character in string
}
ads.down();
}
// send at fHz, fChz, rttyVaricode s(ymb nnnnn
void rttyTxByte(long fHzSymb, long fChzSymb, char symb) {
int bits, val;
// build the byte to send
symb = (symb << 2) + 3; // shift two left, add B00000011, makes B0nnnnn11
for (bits = 7; bits >= 0; bits--) { // MSB first, b7 -> b0
val = bitRead(symb, bits); // Read 1 bit
ads.setFreq(fHzSymb + (170 * val), fChzSymb, 0); // Let's transmit (bit 1 is 170Hz shifted up)
delay(22); // Gives the baud rate, 22ms per bit
}
delay(110); // intersumbol pause
}
// display freq at c)ol, r)ow, f (cHz), d decimal places
void dispFreq(uint8_t c, uint8_t r, float f, float cf, uint8_t d) {
lcd.setCursor(c, r);
lcd.print((f + cf / 100.0), d);
lcd.print("Hz ");
}
// display msg *m at c)ol, r)ow
void dispMsg(uint8_t c, uint8_t r, char *m) {
lcd.setCursor(c, r);
lcd.print(m);
}
I am not too happy with this code as it seems VERY timing sensitive.
No comments:
Post a Comment