In der Welt der Datenübertragung gibt es viele verschiedene Technologien, die verwendet werden können. Eine davon ist die Übertragung von Daten mittels gebündelten Licht – dem LASER. LASER ist eine Abkürzung und steht für Light Amplification by Stimulated Emission of Radiation

In diesem kleinen Projekt werde ich mich damit beschäftigen, wie man Zeichencode (ASCII-Code) mithilfe von Lasern und einem Licht-abhängigen Widerstand (LDR) zwischen zwei voneinander getrennten Arduino Boards übertragen kann. Der darin auch ablesbare Dezimalwert (0 bis 127) möchte ich als Leuchtdauer der Lichtquelle in Millisekunden nutzen.
Warnung vor Laserstrahlen! NICHT in das Licht blicken.
Vor Inbetriebnahme die Anweisungen der Hersteller lesen und folge leisten!
Zunächst einmal ist es wichtig zu verstehen, was ASCII-Code ist.
ASCII steht für American Standard Code for Information Interchange und bezieht sich auf einen Standard, der jedem Buchstaben, Zahl und Sonderzeichen einen eindeutigen 7-Bit-Code zuweist. Dies ermöglicht es Computern, Text und andere Daten in einer gemeinsamen Sprache auszutauschen.
ASCII Tabelle (Auszug) und die zugewiesenen binären Werte:

Um für ein Zeichen, die benötigte Zeichenkodierung zu finden, suche zuerst oben den entsprechenden Spaltennamen für die ersten 4 Bit und hänge dann den entsprechende Zeilenname hinten dran.
Beispiel Fragezeichen: ? = 0011xxxx + xxxx1111 = 00111111 (Binär in Dezimal 32+16+8+4+2+1) = 63
Bei den hier zu sehenden 128 Zeichensätze, ist der erste (0000000) und der letzte Wert (1111111) ein Sonderzeichen. Die nicht druckbaren Steuerzeichen (Wert 2 bis 31) enthalten Ausgabezeichen wie Zeilenvorschub oder Tabulatorzeichen, Protokollzeichen wie Übertragungsende oder Bestätigung und Trennzeichen wie Datensatztrennzeichen. Und welche darüber hinaus sonst noch existieren, sowie weitere Details ist hier bei Wiki nachzulesen.
Hardware:
2 x Microcontroller Entwicklungsboard oder Arduino Uno
Laser Modul KY-008 650nm 3,3V bis 5V
IS0203 Laser/Infrared Receiver Sensor
Verdrahtung:

Entwicklungsumgebung:
Um ASCII-Code mithilfe von Lasern und LDRs zu übertragen, benötigen wir zwei Arduino Boards, einen 5Volt 650nm Laser und einen LDR. Der Laser wird verwendet, um die ASCII-Codes in Form von Lichtimpulsen zu senden, während der LDR verwendet wird, um diese Impulse zu empfangen, die Dauer in Millisekunden zu messen und in die ursprünglichen ASCII-Codes zurück zu wandeln.
Das erste, was wir tun müssen, ist das Sendesketch auf dem Arduino Board zu programmieren, das die Nachricht senden soll. Das Sketch verwendet die digitalWrite()-Funktion, um den Laser ein- und auszuschalten und die delayMicroseconds()-Funktion, um die Dauer des Lichtimpulses zu steuern. Die Dauer des Impulses entspricht dem dezimalen Wert ASCII-Code des jeweiligen Buchstabens oder Zeichens.
Auf dem Empfänger-Arduino Board programmieren wir das Empfängersketch. Es verwendet die pulseIn()-Funktion, um die Dauer des Lichtimpulses zu messen, die von dem LDR empfangen wird. Dieser Wert wird dann in den entsprechenden ASCII-Code umgewandelt und das Zeichen wird über die serielle Kommunikation ausgegeben.
Bevor wir jedoch die Übertragung starten, müssen wir die Laser-Empfänger-Kombination aufeinander abstimmen. Anfangs keine große Entfernung zwischen den beiden Arduino Boards wählen.
Das Laserlicht sollte sichtbar auf dem Empfänger auftreffen und das Umgebungslicht keinen störenden Einfluss haben.
Dann im Sketch einwenig mit dem Multiplikator Wert experimentieren, bis die umgerechneten Dezimalzahlen mit den tatsächlichen ASCII-Werten übereinstimmen. Je kürzer die Impulsdauer, um so schneller die Übertragung, aber auch Fehleranfälliger.
Zum ersten Kalibrieren habe ich mit nur einem Zeichen begonnen, das im Sekundentakt gesendet wurde.
Beispiel für das Zeichen „?“ = 63
Erhöhung der Sendedauer mal 10 = 630ms
Danach habe ich einfach ein Teil des Alphabet genommen, so konnte ich nicht nur prüfen ob die Zeichen korrekt übertragen wurden, sondern auch ob ein Zeichen fehlte. Hatte dabei bei mir die Sendedauer noch etwas erhöht und die Sendepause verringert.
Ausrichtung des Lasers:
Um mir die Höhenausrichtung des Lasers zu erleichtern, wurde nach dieser präzisen Skizze 😀 mit Fischertechnik ein mit einer Drehschraube verstellbarer Ständer gebaut.


Quellcode:
Hier ist ein Beispiel für das Sender Sketch zum Kalibrieren:
void setup() {
Serial.begin(9600);
pinMode(3, OUTPUT); // Pin 3 für den Laser
}
void loop() {
char data = '?'; //Beispiel mit dem Fragezeichen
int asciiValue = data; // umwandeln in Dezimalen Wert
digitalWrite(3, HIGH); // Schalte den Laser ein
delayMicroseconds(asciiValue*10); // Dez Wert mal 10 als Leuchtzeit
digitalWrite(3, LOW); // Schalte den Laser aus
Serial.print(asciiValue*10); //in diesem Beispiel Ausgabe im Seriellen Monitor: 630
delay(1000);
}
Sketch für Sender:
const int laserPin = 3; // Pin, an dem der Laser angeschlossen ist
void setup() {
Serial.begin(9600); // Starte die serielle Kommunikation
pinMode(laserPin,OUTPUT); // LaserPin auf Ausgang stellen
}
void loop() {
String message = "abcdefghijklm"; // Nachricht, die gesendet werden soll
Serial.print("Folgende Zeichen werden gesendet: ");
Serial.println(message);
for (int i = 0; i < message.length(); i++) { // Arbeitet mit der Länge der Zeichenfolge
char c = message.charAt(i); // Greift auf ein bestimmtes Zeichen des Strings zu
int asciiValue = int(c); // Konvertiere das Zeichen in seinen ASCII-Code
Serial.print(c);
Serial.print(" = ");
Serial.println(asciiValue);
digitalWrite(laserPin, HIGH); // Schalte den Laser ein
delayMicroseconds(asciiValue*20); // Warte die Dauer des ASCII-Codes
digitalWrite(laserPin, LOW); // Schalte den Laser aus
delay(200); // Warte eine kurze Pause damit ich auch was sehen kann
}
}
Sketch für Empfänger:
int empfPin = 4; // Pin, an dem das EmpfängerModul angeschlossen ist
unsigned long dauer;
void setup() {
Serial.begin(9600); // Starte die serielle Kommunikation
pinMode(empfPin,INPUT);
}
void loop() {
int dauer = pulseIn(empfPin, HIGH); // Messe die Dauer des Laserimpulses
int asciiwert = (dauer/20)-2; // Setze die Dauer als ASCII-Code (bei mir minus 2ms Kalibrierkorrektur)
Serial.print("Dauer: ");
Serial.print(dauer/20);
Serial.println(" ms"); // Gib das empfangene Zeichen aus
Serial.print("Echte Dauer: ");
Serial.print(dauer);
Serial.println(" ms"); // Gib das empfangene Zeichen aus
char c = char(asciiwert); // Konvertiere den ASCII-Code in ein Zeichen
Serial.print("Zeichen: ");
Serial.println(c); // Gib das empfangene Zeichen aus
Serial.println("------------"); // Gib das empfangene Zeichen aus
}
Video:
Info:
Der Link zur im Video vorgestellter DLR Animation zum Thema Datenübertragung in Höchstgeschwindigkeit – Laserkommunikation im All
Nachtrag:
Nicht im Video zu sehen, die OLED Display Erweiterung, um auch ohne seriellen Monitor die empfangenen Buchstaben zu sehen.

Empfänger Erweiterung mit einem OLED Display:
Hardware:
OLED 0,96 Zoll Display I2C
Verdrahtung:
SDA = A4
SCL = A5
VCC = 3,3 Volt
GND = GND
Quellcode:
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
int empfPin = 4; // Pin, an dem das EmpfängerModul angeschlossen ist
unsigned long dauer;
void setup() {
Serial.begin(9600); // Starte die serielle Kommunikation
pinMode(empfPin,INPUT);
display.display();
delay(2000); // Pause for 2 seconds
// Clear the buffer
display.clearDisplay();
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
}
void loop() {
int dauer = pulseIn(empfPin, HIGH); // Messe die Dauer des Laserimpulses
int asciiwert = (dauer/20)-2; // Setze die Dauer als ASCII-Code (bei mir minus 2ms Kalibrierkorrektur)
Serial.print("Dauer: ");
Serial.print(dauer/20);
Serial.println(" ms"); // Gib das empfangene Zeichen aus
Serial.print("Echte Dauer: ");
Serial.print(dauer);
Serial.println(" ms"); // Gib das empfangene Zeichen aus
char c = char(asciiwert); // Konvertiere den ASCII-Code in ein Zeichen
Serial.print("Zeichen: ");
Serial.println(c); // Gib das empfangene Zeichen aus
Serial.println("------------"); // Gib das empfangene Zeichen aus
display.setTextSize(5);
display.setTextColor(SSD1306_WHITE);
display.setCursor(40,20); //Erster Wert = Anzahl Pixel von links, bis Schrift beginnt
// Zweiter Wert = Anzahl Pixel von oben, bis Schrift beginnt
display.println(c);
display.display();
delay(100);
display.clearDisplay();
}