Project tutorial # 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.

• 5,307 views
• 1 comment
• 13 respects

## Components and supplies

### 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() {
//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);
}
``````

``````#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:
unsigned long sign = 0;
data = (data << 1);
if(val >= 10){
data |= 1;
}else {
data |= 0;
}
//check tail signature
if(EOM == (data&EOM))
{
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;
}
``````

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!

### 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() {
//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);
}
```
```#define SOM 0xB
#define EOM 0xD
#define PULSE 50

unsigned long data = 0;

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

void loop() {
unsigned long sign = 0;

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

//check tail signature
if(EOM == (data&EOM))
{
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

morsetransmitter_DLiViLZSph.fzz

• 15,248 views
• 6 respects

#### Wireless Magnetic Data Transfer

Project tutorial by Tomi Chen

• 9,689 views
• 24 respects

#### Morse Code Transceiver

Project tutorial by Achindra Bhatnagar

• 34,061 views
• 109 respects

• 7,263 views
• 5 respects

• 43,184 views