Sunday, September 13, 2015

Simple RTTY Transmitter with Arduino

Continuing our quest for a simple transmitter for tracking public transport, I experimented with various modes on the small oscillator that my friend Shashank had made. Finally, a simple arrangement to generate the RTTY is presented here.

By writing simple code and tweaking the a preset, one could generate various digital modes from a very simple circuit.

So, here is the oscillator:

There are two control lines going into this. These are connected to an Arduino. The D10 line controls the bias of the oscillator. Essentially switching in on or off. One could key this from the Arduino to generate CW or QRSS. Try doing that on your own, there is no code for it here.

The D11 line controls the frequency shift. Taking D11 high switches on the D1 diode and adds another 10 pf in parallel to C7, pulling down the frequency of the oscillator. The preset in series with the 10 pf is a crude but effective way to adjust the frequency shift more precisely than is possible with a trimmer. I am quite happy with the way this works.

Building it is quite easy. Download the source code below to an Arduino. The code is pretty simple too. The code is meant to read the GPS location from Han's excellent GPS kit and transmit it through RTTY on 27 MHz band. You can choose any other frequency (try a 14.318 MHz crystal).

If you want, you  can program it to transmit anything else too. My friend VU2MY (Shekhar) is planning to use this to monitor his crops.

The preset needs careful adjustment. Here is how you do it:

  1. Download and install MMTTY on your PC. 
  2. Run it, keeping the FFT view to 1.5 KHz
  3. Switch on this RTTY transmitter and tune it on your receiver.
  4. Watch the waterfall on MMTTY and click to place the two lines representing the 170 Hz spacing over your signal's strong line.
  5. Adjust the preset until the two peaks (presenting the two frequencies with the shift) are aligned to the two tuning lines. 
  6. Watch the RTTY message scroll by.
A Catch
  • Use only CAPS. I am not checking for the lower case.
  • Add the letter 'f' (lower case F) before the start of numbers and follow it with 'l' (lower case L). See the code. 
Final Comments

An primitive oscillator when coupled with a 4 dollar Arduino can make for a very interesting plaything. I am sure one could do several other things. With a few resistors connected to the digital output of the Arduino, the modulation can be take varying voltages rather than the current  on/off arrangement. Such a scheme will open us up to WSPR, JT9 and other modes. 

Code (under GPL 3.0)

#include <SoftwareSerial.h>
#include <gps.h>

/* works 
 * with LSB and diode with a twisted wire for a cap in parallel with 10pf (in series with the xtal) 

SoftwareSerial mySerial(2, 3); // RX, TX
int tick = 0;
long lon, lat;
unsigned long nextUpdate=0;
char letter[33] = "0EnA SIUrDRJNFCKTZLWHYPQOBGfMXVl";
char number[33] = " 3n- b87r#4',!:(5')2#6019?&f./;l";
char buff[100];
char rttyMode = 'L';

#define BIT_TIME 22
#define MODULATION 11
#define TX 10

void setup() {
  // put your setup code here, to run once:
 pinMode(11, OUTPUT); 
 pinMode(TX, OUTPUT);

  digitalWrite(TX, HIGH);
  digitalWrite(11, LOW);


void txChar(char ascii){
  int i;
  char c= 0;

  if (isalpha(ascii)){  
    for (i = 0; i <= 32; i++){
      if (letter[i] == ascii)
            c = i;
    for (i = 0; i < 32; i++){
      if (number[i] == ascii)
            c = i;
  //start bit
  digitalWrite(11, HIGH);
  for (i=0; i < 5; i++){
      if (bitRead(c, i) == 1)
        digitalWrite(11, LOW);
        digitalWrite(11, HIGH);
  digitalWrite(11, LOW);
  delay((BIT_TIME * 3)/2);

/* provides half a second of carrier for the receiver to lock-in before the transmission */
void txString(char *string){
  /* to lock onto the signal */
  digitalWrite(TX, HIGH);
  digitalWrite(11, LOW);

  while (*string){
  digitalWrite(11, LOW);
  /* comment out the below line if the receiver is unable to lock in within half a second */
  digitalWrite(TX, LOW);

void loop() {
 unsigned long now;
 char c;
 if (mySerial.available()) {
    c =;

  now = millis();
  if (now > nextUpdate){
    lon = (long)(gps_lon * 10000.0);
    lat = (long)(gps_lat * 10000.0);    

    /* this is the text to be transmitted */
    sprintf(buff, "CQ CQ CQ DE VUf2lLCH f%ldl f%ldln", lon, lat);
    nextUpdate = now + 10000;