Morse-Transceiver mit Arduino UNO bauen – Optische Kommunikation per Laser & LDR
Komponenten und Materialien
| Komponente | Anzahl |
|---|---|
| Arduino UNO | 2 |
| Laserdiode (z. B. Keyes KY-008) | 1 |
| LED (beliebig) | 2 |
| Fotowiderstand (LDR) | 1 |
| Piezo-Summer (aktiv) | 1 |
Projektidee
Im Rahmen eines Kommunikationssysteme-Kurses sollte Morse-Code nicht nur theoretisch, sondern erlebbar vermittelt werden. Statt den Code manuell zu lernen, bauten wir ein Gerät, das Text in Morse umwandelt, per Laser überträgt und auf der Empfängerseite wieder in Text decodiert.
Funktionsprinzip
Codierung: Lookup-Tabelle
Jedes ASCII-Zeichen wird über ein Array (MorseTable) auf seine Morse-Darstellung (Punkte und Striche) abgebildet. Die Tabelle deckt Ziffern, Buchstaben (Groß-/Kleinschreibung identisch) und gängige Satzzeichen ab.
Decodierung: Binärer Baum
Morse-Code lässt sich als binärer Baum darstellen: Punkt = links, Strich = rechts. Der Baum wird als Array MorseTree abgelegt (Index 0 ungenutzt, Kind-Indizes: 2n+1 / 2n+2). Beim Empfang wird der Baum durchlaufen, bis eine Pause das Zeichen beendet.
Timing (Sender)
- Basispuls (Punkt): 50 ms Licht an, 50 ms aus
- Strich: 3× Basispuls = 150 ms an, 50 ms aus
- Zeichenpause: 2× Basispuls = 100 ms
Empfang & Erkennung
Der LDR wird in einer abgedunkelten Röhre vor Fremdlicht geschützt. Die Analogwert-Schwelle (≥ 10) trennt „Licht“ von „Dunkel“. Die Dauer des Hochpegels wird in Zyklen gezählt (ca. 400 Zyklen ≈ 50 ms bei 16 MHz).
ctrHigh ≥ 400 && < 800→ PunktctrHigh ≥ 800→ Strich- Pause
ctrLow == 800→ Zeichenende → Baum-Ausgabe & Reset
Sender-Schaltung
- Laserdiode an Pin 13 (Digital Out)
- USB-Seriell für Texteingabe (Serial Monitor)
Empfänger-Schaltung
- LDR an A4 (Analog In), mit Pull-Down-Widerstand (z. B. 10 kΩ)
- LED an Pin 13 (visuelles Feedback)
- Piezo-Summer an Pin 9 (akustisches Feedback,
tone(9, 1000)) - USB-Seriell für Textausgabe
Sender-Code (Transmitter)
const char* MorseTable[] = {
// Indizes 0-31: Steuerzeichen, Leerzeichen, ! " # $ % & '
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, "-.-.--", ".-..-.", NULL, NULL, NULL, NULL, ".----.", // ( ) * + , - . /
"-.--.", "-.--.-", NULL, ".-.-.", "--..--", "-....-", ".-.-.-", "-..-.",
// 0-9
"-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...",
"---..", "----.", "---...", "-.-.-.", NULL, "-...-", NULL, "..--..",
// @ A-Z
".--.-.", ".-", "-...", "-.-.", "-..", ".", "..-.", "--.",
"....", "..", ".---", "-.-", ".-..", "--", "-.", "---",
".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--",
"-..-", "-.--", "--..", NULL, NULL, NULL, NULL, "..--.-",
// ` a-z (identisch mit A-Z)
NULL, ".-", "-...", "-.-.", "-..", ".", "..-.", "--.",
"....", "..", ".---", "-.-", ".-..", "--", "-.", "---",
".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--",
"-..-", "-.--", "--..", NULL, NULL, NULL, NULL, NULL
};
int dotLength = 50;
int dashLength = dotLength * 3;
void setup() {
pinMode(13, OUTPUT);
Serial.begin(9600);
}
void loop() {
if (Serial.available()) {
char ch = Serial.read();
flashDashDot(MorseTable[(int)ch]);
delay(dotLength * 2); // Zeichenpause
}
}
void flashDashDot(const char* morseCode) {
if (!morseCode) return;
for (int i = 0; morseCode[i]; i++) {
if (morseCode[i] == '.') dot();
else if (morseCode[i] == '-') dash();
}
}
void dot() {
digitalWrite(13, HIGH);
delay(dotLength);
digitalWrite(13, LOW);
delay(dotLength);
}
void dash() {
digitalWrite(13, HIGH);
delay(dashLength);
digitalWrite(13, LOW);
delay(dotLength);
}
Empfänger-Code (Receiver)
// Morse Binärbaum: Index 0 = Root, Links=2n+1, Rechts=2n+2
const char MorseTree[] = {
'\0','E','T','I','A','N','M','S','U','R','W','D','K','G','O',
'H','V','F','U','L','A','P','J','B','X','C','Y','Z','Q',
'\0','\0','5','4','\0','3','\0','\0','\0','2',
'\0','\0','+','\0','\0','\0','\0','1','6','=','/','\0','\0','\0','(',
'\0','7','\0','\0','\0','8','\0','9','0',
// ... weitere Zeichen (?, _, ", ., @, -, ;, !, ), ,, :) ...
// Vollständiges Array siehe Originalcode
};
int val = 0;
int ctrHigh = 0;
int ctrLow = 0;
int codePtr = 0;
int dotLen = 400; // Zyklen für einen Punkt
void setup() {
Serial.begin(9600);
pinMode(13, OUTPUT);
pinMode(9, OUTPUT); // Summer
}
void loop() {
val = analogRead(A4); // LDR an A4
if (val >= 10) { // Licht erkannt
ctrHigh++;
ctrLow = 0;
digitalWrite(13, HIGH);
tone(9, 1000);
} else { // Dunkel
ctrLow++;
if (ctrHigh >= dotLen && ctrHigh < dotLen * 2) {
Serial.print(".");
codePtr = (2 * codePtr) + 1; // Links
} else if (ctrHigh >= dotLen * 2) {
Serial.print("-");
codePtr = (2 * codePtr) + 2; // Rechts
} else {
if (ctrLow == dotLen * 2) { // Zeichenpause
Serial.print(MorseTree[codePtr]);
codePtr = 0;
}
}
ctrHigh = 0;
digitalWrite(13, LOW);
noTone(9);
}
}
Beispielausgabe
Sender-Eingabe: Hello World
Sender-Serial: .... . .-.. .-.. --- .-- --- .-. .-.. -..
Empfänger-Serial: ....H.E.-..L.-..L---O.--W---O.-.R.-..L-..D-.-.--!
Tipps & Erweiterungen
- Reichweite: Mit 5 V Versorgung erreicht der Laser ~200 m. Für größere Distanzen Optik (Linse) verwenden.
- Störlicht: LDR in dunkler Röhre (z. B. Kugelschreiberhülse) einbauen.
- Baudrate: 9600 reicht; bei schnellerer Übertragung Timing anpassen.
- Fehlerkorrektur: Parity/Checksumme für kritische Anwendungen ergänzen.
Schaltpläne
Fritzing-Dateien für Sender- und Empfänger-Schaltung liegen bei (morsetransmitter.fzz, morsereceiver.fzz).
Herstellungsprozess
- Strichcodescanner: Technologie, Design und Zukunftstrends
- C++-Kommentare: Best Practices für lesbaren, wartbaren Code
- ADC Code Error Rates meistern: Was Sie wissen müssen
- Morse-Code und Double Extortion: Aktuelle Landschaft fortgeschrittener Malware-Bedrohungen
- DTMF-Decoder mit Arduino bauen – ganz ohne zusätzlichen IC
- SERENA: Eigenes Arduino Mega 2560 Alarmsystem mit TFT-LCD-Touchscreen
- Data Matrix vs. QR Codes: Welcher ist am besten für Ihr Business?
- CNC G-Codes erklärt: Essentieller Leitfaden für CNC-Programmierer
- Komplette Fanuc G-Code Referenz – Alle Befehle erklärt
- Umfassender Leitfaden zu CNC G-Codes für Fanuc Steuerungen