If anyone is interested in communicating over a laser, here is some code I wrote to achieve communication from one photon to another.
It uses a modified version of RS232 and a 38KHz carrier frequency.
It works pretty well, although there is no error correction or acknowledgement.
Hope it’s useful to others.
Sorry - every time I put code in a code block it spills out and goes everywhere… :
// TRANSMITTER CODE
/*
Code written by Lindsay Fowler
This project will be in two parts:
*A Transmitter Tx (this code is for the Transmitter)
*A Reciever Rx
It will transmit a signal with a RS232 protocol.
Using special PWM feature of AnalogWrite function, the RS232 is modulated onto a 38KHz carrier (kicks in when applied to digital pins) to achieve 38KHz
This way we can use an off the shelf IR receiver, and red laser.
Tx Circuit:
-------|
| 5V
Phton | |
| |
| 10K Ohms ||D-
D0 |---------/\/\/\/\---G|| Laser Diode Module (1mW)
| ||S----|>|------
-------| |
2N7000 |
MOSFET |
|
|
GND
Protocol:
Basically RS232 Except l have a normally low Idle,
with an active high start bit, high 1s, low 0s, then high stop bit:
IDLE start 0 1 2 3 4 5 6 7 stop (rising edge on pulseWidth*10)
|---|---|---| |---|---| |---|---|
------| | 1 | 1 | 0 0 | 1 | 1 | 0 | 1 | |-----------
*/
byte byteToSend = 0xAC;
int pulseWidth = 5;//pulse width in milliseconds
void setup() {
pinMode(D0, OUTPUT); //Connected to Laser
pinMode(D7, OUTPUT); //Blue transmission indicator LED
pinMode(D1, OUTPUT);// debug - to mark the start of transmission
Serial.begin(9600); //turn on the serial monitor
}
void loop() {
//wait a second
delay(pulseWidth*15);
sendByte(byteToSend); //Send byte
byteToSend+=1;
//delay(pulseWidth*15);
//sendByte(0x55); //Send byte
}
void sendByte(byte dataByte){
Serial.println("sending 0x"+String(dataByte, BIN)); //debug
//send start bit
analogWrite(D0,128,38000);//Switch on the 38KHz to IR LED
digitalWrite(D7,HIGH);//Switch on the Blue Indicator LED
delay(pulseWidth); //wait until stop bit is over.
for (int bitNumber=0;bitNumber<=7;bitNumber++){
if(dataByte & (1 << bitNumber)){
analogWrite(D0,128,38000);//Switch on the 38KHz to IR LED
digitalWrite(D7,HIGH);//Switch on the Blue Indicator LED
//Serial.println(String("bitPos:") + String(bitNumber) + " Data: 1"); //debug
}else{
analogWrite(D0,0,38000);//Switch off the 38KHz to IR LED
digitalWrite(D7,LOW);//Switch off the Blue Indicator LED
//Serial.println(String("bitPos:") + String(bitNumber) + " Data: 0"); //debug
}// end if
delay(pulseWidth); //wait to send the next bit
}// end for loop
analogWrite(D0,128,38000);//Switch on the 38KHz to IR LED
digitalWrite(D7,HIGH);//Switch on the Blue Indicator LED
delay(pulseWidth); //wait until stop bit is over.
analogWrite(D0,0,38000);//Switch off the 38KHz to IR LED
digitalWrite(D7,LOW);//Switch off the Blue Indicator LED
}// end sendByte
//RECEIVER CODE
/*
Code written by Lindsay Fowler
This project will be in two parts:
- A Transmitter (Tx)
- A Receiver (Rx) This is the receiver
It will monitor the laser receiver photo diode
Use RS232-like protocol
1 Start bit
8 Data bits
1 Stop bit
Protocol:
Basically RS232 Except l have a normally low Idle,
with an active high start bit, high 1s, low 0s, then high stop bit:
IDLE start 0 1 2 3 4 5 6 7 stop
|—|---|—| |—|---| |—|---|
------| | 1 | 1 | 0 0 | 1 | 1 | 0 | 1 | |-------------
Receiver Circuit for connection to Particle Photon:
IR Detector (front)
____________
| ____ |
| / \ |
| | | |
| \____/ |
| |
|Out GND VCC |
-------------
| | |
| | |
| | |
D0 D1 D2
*/
//pin constants
const int powerPin = D2;
const int gndPin = D1;
const int dataIn = D0;
int debugPin = D3; // pin to highlight the reading time
int value_recieved;
int pulseWidth = 5; //milliseconds
void setup() {
Serial.begin(19200); //turn on the serial monitor
Serial.println(“Setting up Receiver. Expected pulse width is “+ String(pulseWidth)+“ms.”);
Serial.println(””);
pinMode(gndPin, OUTPUT); //make a ground for detector
digitalWrite(gndPin, LOW);
pinMode(powerPin, OUTPUT); //make a supply for detector
digitalWrite(powerPin, HIGH);
pinMode(D7, OUTPUT); //turn on indicator LED
digitalWrite(D7,HIGH);
pinMode(debugPin, OUTPUT); //turn on indicator LED
digitalWrite(debugPin,LOW);
pinMode(dataIn, INPUT);
}
void loop() {
//wait for start bit (rising edge)
if(digitalRead(dataIn)==0){//the IR detector is active low.
//Serial.println(“Start bit detected”); //debug
Serial.println("Byte received: " + String(receiveByte()));//blocking function, hopefully
}
}
byte receiveByte (){
byte data = 0x00;
byte bitPos = 0x01;
//delay half of pulse width because rising edge detected and we should be in the middle of next pulse
//Serial.println("Waiting 1.5 pulse widths"); //debug
delay(pulseWidth*1.5);
for (int bitPos=0;bitPos<=7;bitPos++){
//debugPulse();//send a debug pulse to see when the bit value reading is occuring
if(digitalRead(dataIn)==0){ //the IR detector is active low.
data = data | (1 << bitPos); // "|" is bitwise Or; data|00000001 sets bit 0
//Serial.println("bitPos:" + String(bitPos) + " Data: 1"); //debug
}else{
//Serial.println("bitPos:" + String(bitPos) + " Data: 0"); //debug
data = data & ~(1 << bitPos); // "|" is bitwise Or; "~" is a bitwise not: data|11110111 clears bit 3
}
delay(pulseWidth); //wait to read the next bit
}
delay(pulseWidth/2); //wait until stop bit is over.
return data;
}
void debugPulse(){
digitalWrite(debugPin,HIGH);
delay(0.9);
digitalWrite(debugPin,LOW);
}
