Arduino UNOで作るモールス信号送受信機 - 光通信による実践的プロジェクト
必要な部品と用品
| 部品 | 数量 |
|---|---|
| Arduino UNO | 2台(送信機・受信機各1台) |
| レーザーダイオード(Keyes製など) | 1 |
| LED(汎用) | 2 |
| フォトレジスタ(LDR / CdSセル) | 1 |
| ピエゾブザー | 1 |
プロジェクト概要
通信システムの授業で、学生がモールス信号を視覚的・体験的に学べるよう、Arduinoを用いた送受信システムを構築しました。石器時代の通信から言語・文法・信頼性・信号・メッセージの概念を学び、最終的にモールス信号を独自言語として定義、エンコーダー/デコーダーを実装しました。
モールス符号表と2分木によるデコード
文字→モールス符号の変換はルックアップテーブルで、モールス符号→文字の変換は2分木(ドット=左、ダッシュ=右)で高速化しています。
送信機(トランスミッター)
PCとシリアル接続(USB)し、シリアル入力文字を1文字ずつ読み取り、対応するモールス符号をレーザーダイオードの点滅パターンで出力します。
- ドット: 50ms 点灯 + 50ms 消灯
- ダッシュ: 150ms 点灯 + 50ms 消灯
- 文字間: 100ms 無信号
レーザーは3Vで十分な距離、5Vなら200m以上到達可能です。
送信機スケッチ
const char* MorseTable[] = {
// インデックス = ASCIIコード
NULL, NULL, ..., ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", // A-G
"....", "..", ".---", "-.-", ".-..", "--", "-.", "---", // H-O
".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", // P-W
"-..-", "-.--", "--..", NULL, NULL, NULL, NULL, "..--.-", // X-Z, _, etc.
// 小文字も同一コード割り当て
NULL, ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", // a-g
"....", "..", ".---", "-.-", ".-..", "--", "-.", "---", // h-o
".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", // p-w
"-..-", "-.--", "--..", NULL, NULL, NULL, NULL, NULL // x-z, {|}~DEL
};
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[ch]);
delay(dotLength * 2); // 文字間スペース
}
}
void flashDashDot(const char* morseCode) {
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);
}
受信機(レシーバー)
LDRでレーザー光を検出し、点灯継続時間からドット/ダッシュを判定、2分木をたどって文字を復元します。LEDとブザーで音声・視覚フィードバックも出力。
- LDRを長いチューブで覆い、外光を遮断
- 光検出時のループカウントでパルス幅を測定(約400サイクル = 50ms相当)
- ドット: 400〜800サイクル、ダッシュ: 800サイクル以上
- 無信号が800サイクル継続で文字確定、2分木から文字出力
受信機スケッチ
// モールス2分木(配列インデックス: 左=2n+1, 右=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',
// 以下、記号類...
};
int val = 0;
int ctrHigh = 0, ctrLow = 0;
int codePtr = 0;
int dotLen = 400; // ループカウント閾値
void setup() {
Serial.begin(9600);
pinMode(13, OUTPUT); // LED
pinMode(9, OUTPUT); // ブザー
}
void loop() {
val = analogRead(A4); // LDR接続ピン
if (val >= 10) { // 光検出
ctrHigh++; ctrLow = 0;
digitalWrite(13, HIGH);
tone(9, 1000);
} else { // 光なし
ctrLow++;
if (ctrHigh >= dotLen && ctrHigh < dotLen * 2) {
Serial.print("."); codePtr = codePtr * 2 + 1;
} else if (ctrHigh >= dotLen * 2) {
Serial.print("-"); codePtr = codePtr * 2 + 2;
} else {
if (ctrLow == dotLen * 2) { // 文字区切り
Serial.print(MorseTree[codePtr]);
codePtr = 0;
}
}
ctrHigh = 0;
digitalWrite(13, LOW);
noTone(9);
}
}
動作例
送信: "Hello World" 出力: .... . .-.. .-.. --- .-- --- .-. .-.. -.. 受信側シリアル出力: ....H.E.-..L.-..L---O.--W---O.-.R.-..L-..D-.-.--!
回路図
- モールス信号送信機回路(レーザーダイオード駆動)
- モールス信号受信機回路(LDR、LED、ブザー)
Fritzingファイル(.fzz)も提供されています。
製造プロセス
- バーコードスキャナ:技術、設計、将来動向
- ArduinoだけでDTMFデコーダーを構築 – 外付けIC不要
- SERENA:Arduino Mega 2560とTFT LCDタッチスクリーン搭載カスタムアラームシステム
- レーザーモジュールでモールス信号通信 – Arduino二台で送受信
- モールス信号と二重恐喝:高度マルウェア脅威の現在地
- データマトリックスとQRコードの選び方:あなたのビジネスに最適なのはどっち?
- CNC Gコード解説:CNCプログラマー必須の基礎知識
- 完全版 Fanuc Gコード リファレンス – 全コマンド解説
- Fanuc制御向けCNC Gコード総合ガイド
- ADCコードエラー率(CER)を理解する:知っておくべきポイント
- C++コメント完全ガイド:読みやすく保守しやすいコードのためのベストプラクティス