Project tutorial
20bps Digital Data Wireless Transceiver (Laser)

20bps Digital Data Wireless Transceiver (Laser) © MIT

Extending Morse Code Transceiver to work with digital data. This project achieves a throughput of 20bps, 2x over Morse code.

  • 2,184 views
  • 1 comment
  • 9 respects

Components and supplies

About this project

Introduction

In my Digital Communications class, I am trying to help my students learn digital communication/computer networks by discovering the problems of the domain and solve them. In the last class we built a Morse code transmitter/receiver using Laser and LDR.

Today, I extended this to transfer digital data; data encoded in stream of 0 and 1. In Morse code, ‘dot’ and ‘dash’ are equivalent to 0 and 1 of digital data. However, we have explicit signal for 0/dot. Absence of signal is not interpreted as a zero. This makes the channel costlier. I could achieve ~18 words per minute (PARIS is generally used as a reference word for this calculation). This equates to 75 bytes per min or 10bps.

Transmitter

Since my transmitter is a laser diode with on and off states, switched off state can be considered to be a 0 while switched on state can be considered as 1. However, this poses a challenge as how to differentiate a set of 0 representing data from 0 representing silence (absence of data transmission).

Edit code

Since we are presented with this problem, I added a start message header/pattern (1011) and an end message header/pattern (1101). I continuously sample data on my LDR receiver and add read value 0/1 to my data. Then, I check for end pattern and if it is found, I check for start header before my 8 bit data.

1011<8_bit_data>1101

H: 1011010010001101
E: 1011010001011101
L: 1011010011001101
L: 1011010011001101
O: 1011010011111101

I could decode this pattern on my receiver.

However, this simple pattern to encapsulate a message is not foolproof. It can easily be cracked by a rogue data series.

So how do I verify that the data received is actually the data sent from the other end?

I added a small signature to the end of data; number of set bits. Since my data is 8 bits, I added another 4 bits to represent max 8 bits that could be set in the data.

1011<8_bit_data><4_sign_bits>1101

H: 10110100100000101101
E: 10110100010100111101
L: 10110100110000111101
L: 10110100110000111101
O: 10110100111101011101

I could decode this pattern as well. Result, I could filter some garbage out:

I do have data loss, but less garbage now. So how can I improve this further? Can I fix transmission errors? Can I make better use of sign bits? Loads of possible improvements, but we shall solve when we the problem hit us in face and we are convinced that the problem is worth solving. May be next class…

Transmitter:

#define PULSE 50
#define START_MSG one(); zero(); one(); one();
#define   END_MSG one(); one(); zero(); one();
#define MSG_PACK(x) START_MSG x END_MSG
void setup() {
  pinMode(13, OUTPUT);
}
void loop() {
  // <MSG_HEAD><8_Data_Bits><4_Sign_Bits><MSG_TAIL>
  //H: 2 set bits
  MSG_PACK(zero(); one(); zero(); zero(); one(); zero(); zero(); zero(); \
           zero(); zero(); one(); zero(); )
  //E: 3 set bits
  MSG_PACK(zero(); one(); zero(); zero(); zero(); one(); zero(); one(); \
           zero(); zero(); one(); one(); )
  //L: 3 set bits
  MSG_PACK(zero(); one(); zero(); zero(); one(); one(); zero(); zero(); \
           zero(); zero(); one(); one(); )
  //L: 3 set bits
  MSG_PACK(zero(); one(); zero(); zero(); one(); one(); zero(); zero(); \
           zero(); zero(); one(); one(); )
  //O: 5 set bits
  MSG_PACK(zero(); one(); zero(); zero(); one(); one(); one(); one(); \
           zero(); one(); zero(); one(); )
  //CR: 3 set bits
  MSG_PACK(zero(); zero(); zero(); zero(); one(); one(); zero(); one(); \
           zero(); zero(); one(); one(); )
  //LF: 2 set bits
  MSG_PACK(zero(); zero(); zero(); zero(); one(); zero(); one(); zero(); \
           zero(); zero(); one(); zero(); )
}
void zero()
{
  digitalWrite(13, LOW);
  delay(PULSE);
}
void one()
{
  digitalWrite(13, HIGH);
  delay(PULSE);
} 
Transmitter Device

Receiver:

#define SOM 0xB
#define EOM 0xD
#define PULSE 50
unsigned long data = 0; 
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}
void loop() {
  // put your main code here, to run repeatedly:
  int val = analogRead(4);
  unsigned long sign = 0;
  data = (data << 1);
  if(val >= 10){
    data |= 1;
  }else {
    data |= 0;
  }
  //check tail signature
  if(EOM == (data&EOM))
  {
    //check head signature
    if(SOM == ((data >> 16)&0xF)){
      sign = (data>>4)&0xF; // 4 bits of signature
      data = (data>>8)&0xFF;// 8 bits of data
      if(sign == getSetBits(data))
      {
        Serial.print((char)data);
      }
      //Diagnostics
      //if(data==72||data==69||data==76||data==79||data==13||data==10){
        //data
        //digitalWrite(13, HIGH);
      //}else{
        //error
        //digitalWrite(12, HIGH);
      //}
      data = 0;
    }
  }
  delay(PULSE);
  //digitalWrite(13, LOW);
  //digitalWrite(12, LOW);
}
unsigned long getSetBits(unsigned long n)
{
  unsigned long count = 0;
  while(n)
  {
    n &= (n-1);
    count++;
  }
  return count;
} 
Receiver Device

BTW, I achieved about 1 byte data per second speed with the final code published here. Including headers, it comes to 20-bits per second!

Transmission at 1 char per second - 1Bps (data) or 20bps (message)

Edit

To detect errors in data, my signature mechanism of adding number of set bits in data wasn't proving good. I need a better and cheaper solution that does not add a lot of data overhead.

I XOR high nibble and low nibble to generate a 4-bit signature. This signature is less likely to fail since error (bit flip) has to happen at corresponding bits in both high nibble and low nibble.

// (sign == (right ^ left))
if(sign == ((data & 0xF) ^ ((data >> 4) & 0xF))){
       Serial.print((char)data);
}

The results, as expected are better than before. Very very rarely I see a rogue byte pass this test.

In ideal condition I do not get errors. I do not see rogue bytes (yet), but I do see packets dropped. How do I ensure that I have received all data in the correct order?

This is the next problem to solve. Build an ACK for each packet so that Sender can confirm what he sent has actually been received. I plan to send back the XOR sign as received. However I do not have another laser diode for the purpose...

Code

Encoded DataPlain text
H: 1011010010001101
E: 1011010001011101
L: 1011010011001101
L: 1011010011001101
O: 1011010011111101
Encoded Data with SignaturePlain text
H: 10110100100000101101
E: 10110100010100111101
L: 10110100110000111101
L: 10110100110000111101
O: 10110100111101011101
TransmitterArduino
#define PULSE 50

#define START_MSG one(); zero(); one(); one();
#define   END_MSG one(); one(); zero(); one();

#define MSG_PACK(x) START_MSG x END_MSG

void setup() {
  pinMode(13, OUTPUT);
}

void loop() {
  // <MSG_HEAD><8_Data_Bits><4_Sign_Bits><MSG_TAIL>
  //H: 2 set bits
  MSG_PACK(zero(); one(); zero(); zero(); one(); zero(); zero(); zero(); \
           zero(); zero(); one(); zero(); )
  //E: 3 set bits
  MSG_PACK(zero(); one(); zero(); zero(); zero(); one(); zero(); one(); \
           zero(); zero(); one(); one(); )
  //L: 3 set bits
  MSG_PACK(zero(); one(); zero(); zero(); one(); one(); zero(); zero(); \
           zero(); zero(); one(); one(); )
  //L: 3 set bits
  MSG_PACK(zero(); one(); zero(); zero(); one(); one(); zero(); zero(); \
           zero(); zero(); one(); one(); )
  //O: 5 set bits
  MSG_PACK(zero(); one(); zero(); zero(); one(); one(); one(); one(); \
           zero(); one(); zero(); one(); )
  //CR: 3 set bits
  MSG_PACK(zero(); zero(); zero(); zero(); one(); one(); zero(); one(); \
           zero(); zero(); one(); one(); )
  //LF: 2 set bits
  MSG_PACK(zero(); zero(); zero(); zero(); one(); zero(); one(); zero(); \
           zero(); zero(); one(); zero(); )
}

void zero()
{
  digitalWrite(13, LOW);
  delay(PULSE);
}

void one()
{
  digitalWrite(13, HIGH);
  delay(PULSE);
}
ReceiverArduino
#define SOM 0xB
#define EOM 0xD
#define PULSE 50

unsigned long data = 0; 

void setup() {
  Serial.begin(9600);
}

void loop() {
  int val = analogRead(4);
  unsigned long sign = 0;

  data = (data << 1);
  if(val >= 10){
    data |= 1;
  } else {
    data |= 0;
  }

  //check tail signature
  if(EOM == (data&EOM))
  {
    //check head signature
    if(SOM == ((data >> 16)&0xF)){
      sign = (data>>4)&0xF; // 4 bits of signature
      data = (data>>8)&0xFF;// 8 bits of data

      if(sign == getSetBits(data))
      {
        Serial.print((char)data);
      }

      //Diagnostics
      //if(data==72||data==69||data==76||data==79||data==13||data==10){
        //data
        //digitalWrite(13, HIGH);
      //}else{
        //error
        //digitalWrite(12, HIGH);
      //}
      data = 0;
    }
  }
  delay(PULSE);
  //digitalWrite(13, LOW);
  //digitalWrite(12, LOW);
}

unsigned long getSetBits(unsigned long n)
{
  unsigned long count = 0;
  while(n)
  {
    n &= (n-1);
    count++;
  }
  return count;
}

Schematics

Transmitter
morsetransmitter_DLiViLZSph.fzz
Receiver
morsereceiver_xGZ2F0EWZA.fzz

Comments

Similar projects you might like

Morse Code Transceiver

Project tutorial by Achindra Bhatnagar

  • 15,098 views
  • 13 comments
  • 88 respects

Wireless Magnetic Data Transfer

Project tutorial by Tomi Chen

  • 4,690 views
  • 4 comments
  • 18 respects

Arduino to VGA - Wireless Data Receiver

Project showcase by antiElectron

  • 2,596 views
  • 0 comments
  • 14 respects

Arduino & Python3 Temperature Data Visualizer

Project tutorial by reyadeetopee

  • 3,642 views
  • 0 comments
  • 22 respects

Create a People Counter Controlled by an Android App

Project tutorial by Kutluhan Aktar

  • 3,174 views
  • 2 comments
  • 7 respects

Menu Card To Speech, Reads And Writes Data On Thingspeak

Project tutorial by eric

  • 725 views
  • 0 comments
  • 2 respects
Add projectSign up / Login