Demodulating FSK radio signals

I'm attempting to transmit data over radio signals, but my receiving end is spitting out gibberish.

The serial monitor shows,
Start
0 0 1 0 0 0 16 5 (@) (!) 0 1 0 0 0 128 16 4 0 17 0 1 0 0 0 0 4 1 0 0
0 0 1 176 2 0 0 4 1 0 0 130 0 0 ( ) (") 0 0 0 0 0 4 1 0 0 1 16 0 (@) 0 0 0 0 4 1 0 0 0 (H) 0
0 0 0
When it should be a legible message.

On the signal out I have a radio transmitter with a Tx pin connected to serial 2 on an Arduino mega. The code just enables the transmitter, then does "Serial2.println("message");". Baud is 1200. Transmitter data sheet here (HX1)

On the receiving end I'm using a library called SoftModem (SoftModem-005) to demodulate the signal. I'm pretty sure my code here is the reason the gibberish, I have almost no idea what I'm doing. Most of this code is from a tutorial I found. These are the settings I have in the .h file.

#define SOFT_MODEM_BAUD_RATE (1200)
#define SOFT_MODEM_LOW_FREQ (1200)
#define SOFT_MODEM_HIGH_FREQ (2200)
#define SOFT_MODEM_RX_BUF_SIZE (32)

#include <SoftModem.h>            //Software Modem Library

SoftModem modem;                  //Because SoftModem.begin wont work for some reason

const int redLED = 5;
const int greenLED = 3;
int i;

void setup()
{
  pinMode(redLED, OUTPUT);
  pinMode(greenLED, OUTPUT);
  Serial.begin(115200);
  Serial.println("Start :");
  modem.begin();
  redFlash();
}

void loop()
{
  while (modem.available ())
  {
    digitalWrite(greenLED, HIGH); //Indicate receiving data
    int c = modem.read ();        //1 byte Lead
    if (isprint(c))
    {
      Serial.print(" (");
      Serial.print ((char)c);
      Serial.print(")");
    }
    else
    {
      Serial.print (" ");         //Hex printable characters are displayed in decimal
      Serial.print (c);
    }
    i++;
    if (i == 40)
    {
      Serial.println();           //Wrapping line
      i = 0;
    }
  }
  digitalWrite(greenLED, LOW);
}

void redFlash()
{
  for (i = 0; i < 10; i++)
  {
    digitalWrite(redLED, HIGH);
    delay(25);
    digitalWrite(redLED, LOW);
    delay(25);
  }
}

void greenFlash()
{
  for (i = 0; i < 10; i++)
  {
    digitalWrite(greenLED, HIGH);
    delay(25);
    digitalWrite(greenLED, LOW);
    delay(25);
  }
}

More info:

The receiver is a handheld radio tuned to the correct frequency. It makes an audible "kshhh" sound when it receives the message. The audio out is sent to a circuit that level shifts the signal and cleans it up with a buffer before going into the arduino. I've tested it with the sound jack on my phone and it will read a pure triangle, sine, or square wave at the low frequency, 1200, as all ones in binary. It outputs "ÿ ÿ ÿ ÿ" on the serial monitor since that's 11111111 in binary. It prints nothing when receiving the high frequency, 2200hz.

You will probably find this site very informative, and the open source Arduino software is light-years ahead of the "softmodem" code you found, which uses the unreliable zero-crossing method to decode FSK signals. Perfect for APRS applications.

Or you can buy the reasonably priced, programmed TX/RX boards that are ready to communicate via audio FSK signals using any radio.

My circuit is actually based on the micromodem. I attempted to use the software too but it wasn't something I could just include in the Arduino IDE and upload. I got pretty lost.

This might not be your only problem but use serial write not serial print to output your message.

Grumpy_Mike:
This might not be your only problem but use serial write not serial print to output your message.

I tried that first, but I get this error message.

Transmitter_test.ino: In function 'void loop()':
Transmitter_test:64: error: no matching function for call to 'HardwareSerial::write(String&)'
Transmitter_test.ino:64:21: note: candidates are:
In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:224:0,
from C:\Users\gustavo\Documents\Arduino\libraries\Adafruit_GPS_Library/Adafruit_GPS.h:90,
from Transmitter_test.ino:3:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:124:20: note: virtual size_t HardwareSerial::write(uint8_t)
virtual size_t write(uint8_t);
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:124:20: note: no known conversion for argument 1 from 'String' to 'uint8_t {aka unsigned char}'
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:125:19: note: size_t HardwareSerial::write(long unsigned int)
inline size_t write(unsigned long n) { return write((uint8_t)n); }
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:125:19: note: no known conversion for argument 1 from 'String' to 'long unsigned int'
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:126:19: note: size_t HardwareSerial::write(long int)
inline size_t write(long n) { return write((uint8_t)n); }
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:126:19: note: no known conversion for argument 1 from 'String' to 'long int'
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:127:19: note: size_t HardwareSerial::write(unsigned int)
inline size_t write(unsigned int n) { return write((uint8_t)n); }
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:127:19: note: no known conversion for argument 1 from 'String' to 'unsigned int'
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:128:19: note: size_t HardwareSerial::write(int)
inline size_t write(int n) { return write((uint8_t)n); }
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:128:19: note: no known conversion for argument 1 from 'String' to 'int'
In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Stream.h:26:0,
from C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\SoftwareSerial/SoftwareSerial.h:36,
from Transmitter_test.ino:2:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:54:12: note: size_t Print::write(const char*, size_t)
size_t write(const char buffer, size_t size) {
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:54:12: note: candidate expects 2 arguments, 1 provided
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:53:20: note: virtual size_t Print::write(const uint8_t
, size_t)
virtual size_t write(const uint8_t buffer, size_t size);
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:53:20: note: candidate expects 2 arguments, 1 provided
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:49:12: note: size_t Print::write(const char
)
size_t write(const char str) {
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:49:12: note: no known conversion for argument 1 from 'String' to 'const char
'
no matching function for call to 'HardwareSerial::write(String&)'

I'm not sure what all that means, but I know I can't just go Serial.write(String); for some reason. Is there a different syntax for writing vs printing?

This is what I am attempting to write:

String APRS = "KM6BIN>APRS:@" + String(UTC) + "h" + String(longitude) + "N" + "/" + String(latitude) + "W" + "O" + String(angle) + "/" + String(velocity) + "/A=" + String(altitude);

Maybe is I break it up and write them characters one at a tie like this?

  for(int i = 0; i < APRS.length(); i++) {
    Serial2.write(APRS[i]);
  }

You are trying to demodulate by tuning 1.7kHz off the carrier and hoping the transmitter or receiver don't
drift? Not convinced that is workablea at 144MHz, its not how FSK data is normally handled. You modulation parameters
are worrying too, a frequency shift of 1kHz but a modulation rate of 1.2kbaud...

What demodulation technique is the radio using? It sounds like SSB rather than FM demodulation, which
would mean you only have the I part of an IQ demodulator so don't have phase information.

You are trying to demodulate by tuning 1.7kHz off the carrier and hoping the transmitter or receiver don't
drift? Not convinced that is workablea at 144MHz,

Yes it is. The proper name is called "slope demodulation" because you are tuning down the slope of the IF filter. Used to use that years ago to receive FM on a and AM radio. Old ham trick.

parameters are worrying too, a frequency shift of 1kHz but a modulation rate of 1.2kbaud...

That would be fine, the trouble is the overall bandwidth of the resulting signal might be being restricted.

Maybe is I break it up and write them characters one at a tie time like this?

Yes try that.

I attempted to use the software too but it wasn't something I could just include in the Arduino IDE and upload. I got pretty lost.

Post on the Micromodem forum, or email the site owner directly. He is very interested in the project and responds quickly (at least in my case) to comments and questions.

Ok, I tried writing it rather than printing and I'm still getting gibberish, but I believe my issue might actually be with the transmitter instead of the receiver. The transmitter is receiving only the 1's and 0's digitally. The HX1 might not be FSK modulating it at all and just sending out the digital signal as an FM wave. I read over the datasheet for the millionth time and I see nothing about how the signal is modulated. Would I need to make it an FSK message before it goes into the transmitter?

If I could read the receiver as just binary instead of FSK, that would show me that the transmitter module doesn't modulate the signal for me. I don't know where to start with the code. How do I read the incoming bits?
I wish I had an oscilloscope to see the signal.

jremington:
Post on the Micromodem forum, or email the site owner directly. He is very interested in the project and responds quickly (at least in my case) to comments and questions.

That's a good idea, I'll try that after I give up on the softmodem.

MarkT:
You are trying to demodulate by tuning 1.7kHz off the carrier and hoping the transmitter or receiver don't
drift? Not convinced that is workablea at 144MHz, its not how FSK data is normally handled. You modulation parameters
are worrying too, a frequency shift of 1kHz but a modulation rate of 1.2kbaud...

What demodulation technique is the radio using? It sounds like SSB rather than FM demodulation, which
would mean you only have the I part of an IQ demodulator so don't have phase information.

Those numbers, baud/low frq/high frq I got from my research. It appeared to be the standard for APRS communication. The radio is tuned to FM and the transmitter is transmitting in FM. The FM frequency shift is not 1kHz, it's probably quite a bit greater. The FSK part has the 1kHz difference. It's rather confusing to have two kinds of modulation like this, but I'm pretty sure that's how it works.

The HX1 might not be FSK modulating it at all and just sending out the digital signal as an FM wave.

FSK stands for Frequency shift keying. It is just a digital signal modulating an FM transmitter.

I'm going to draw a diagram of how I think it works, then you can let me know If I have it right or not.

edit:
The FSK might be square or sine, i'm not sure. But it goes through a buffer that makes it a square wave before getting to the arduino

Assuming that this is FSK then:-
Close - but there is no Audio out - if there was then it would be AFSK and you would have to feed two tones of audio into the transmitter.

On the receive side these would appear as two different voltage levels not tones. The voltages levels would be fed into a comparator to convert them into nice square logic levels which would be the binary data.

Grumpy_Mike:
Assuming that this is FSK then:-
Close - but there is no Audio out - if there was then it would be AFSK and you would have to feed two tones of audio into the transmitter.

On the receive side these would appear as two different voltage levels not tones. The voltages levels would be fed into a comparator to convert them into nice square logic levels which would be the binary data.

Then there's my problem. I thought the HX1 transmitter was automatically making it into a two tone signal before transmitting. The softmodem is looking for two tones, so if I look for just the square logic on the receiver, would it work?

The transmitted FM signal should be modulated such that two audio tones come out of the receiver.

The 1/0 information is encoded in which of these two audio tones is currently being transmitted. For APRS the tones are 1200 Hz and 2200 Hz.

jremington:
The transmitted FM signal should be modulated such that two audio tones come out of the receiver.

Ok, so I just need to put the SoftModem into the transmitting arduino as well and it should work. Ill try that now

I'm curious, in reply #12 there is block "radio" on a diagram, what is that?

Magician:
I'm curious, in reply #12 there is block "radio" on a diagram, what is that?

That's a handheld ham radio. It just takes the RF input from the antenna and outputs a line level audio signal.

GustavoMcSavy:
That's a handheld ham radio. It just takes the RF input from the antenna and outputs a line level audio signal.

What kind of a radio, AM or FM?