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:

Beispiel mit Buchstaben A:
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: A = 0100xxxx + xxxx0001 = 01000001 (Binär in Dezimal 64+1) = 65
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.

Überlegung:
Mit dieser Information habe ich zunächst gedacht, dass man den Buchstaben „a“ durch eine Folge von Laser‑Signalen wie aus, an, an, aus, aus, aus, aus und einmal an übertragen könnte – also ähnlich wie eine Bitfolge.
Dabei habe ich jedoch nicht an den Start‑ und Endpunkt des Signals gedacht, und auch die genaue Geschwindigkeit wäre kritisch. Um die Übertragung einfacher und robuster zu machen, verwende ich stattdessen einen einzigen Laserimpuls, dessen Dauer dem dezimalen ASCII‑Wert des jeweiligen Buchstabens entspricht.
Also werde ich in diesem Projekt die asynchrone (kein gemeinsamer Takt) serielle Kommunikation nutzen.
Aber wie genau funktioniert das?
- Kein gemeinsamer Taktgeber
Sender und Empfänger arbeiten mit eigenen, unabhängigen Uhren.
Sie müssen also nicht exakt synchron laufen.- Start‑ und Stopp‑Impulse
Der Sender signalisiert dem Empfänger den Beginn und das Ende eines Datenpakets durch einen einzigen Lichtimpuls.
Der Moment, in dem der Laser eingeschaltet wird, markiert den Start, und der Moment, in dem der Laser ausgeschaltet wird, markiert das Ende.
Die Dauer zwischen Start und Ende enthält die Information (ASCII‑Wert) und übernimmt gleichzeitig die Selbstsynchronisation, da der Empfänger sich nur für diesen einen Impuls zeitlich ausrichten muss.- Robustheit trotz unterschiedlicher Geschwindigkeiten
Die Methode funktioniert auch dann, wenn Sender und Empfänger nicht perfekt abgestimmt sind.- Ideal für sporadische Übertragungen
Da kein dauerhafter Takt benötigt wird, eignet sich die Methode besonders für gelegentliche Datenübertragungen, wie in deinem Laserprojekt.
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 Skizze mit Fischertechnik ein mit einer Drehschraube verstellbarer Ständer gebaut.


Quellcode:
Vorbereitung: 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);
}
Finaler 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
}
}Finaler 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
}Youtube Video:
Info:
Der Link zur im Video vorgestellter DLR Animation zum Thema Datenübertragung in Höchstgeschwindigkeit – Laserkommunikation im All
Nachtrag:
Empfänger mit OLED Anzeige
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();
}
Projekt Idee:
Um dieses Projekt was die Übertragungsgeschwindigkeit anbetrifft zu verbessern, habe ich ein Jahr später im Beitrag Umgebungslicht präzise messen das Modul TEMT6000 vorgestellt. Es ist nicht so träge wie eine LDR (Reaktionszeit: Mikrosekunden) und könnte die Übermittlung deutlich beschleunigen. Ich werde dann berichten.
