Construye un transceptor de código Morse con Arduino UNO: Proyecto práctico de comunicaciones
Componentes y materiales
| Arduino UNO | × | 2 |
| LED (genérico) | × | 2 |
| Fotorresistencia (LDR) | × | 1 |
| Zumbador (Buzzer) | × | 1 |
Sobre este proyecto

Estaba dando una clase sobre Sistemas de Comunicación y quería que mis estudiantes aprendieran visualizando y experimentando. Hicimos algunos experimentos partiendo de la Edad de Piedra para entender la necesidad de comunicación y qué significan lenguaje y gramática, qué es comunicación fiable, señales, mensajes, etc.
Al discutir todo esto, llegamos a un punto donde queríamos definir nuestro propio lenguaje para comunicación visual, ¡y allí ideamos el código Morse!
Era obvio que aprender código Morse sería una tarea tediosa para cada uno, así que necesitábamos una máquina. Decidimos escribir un pequeño programa que pueda codificar una cadena dada a su equivalente en código Morse y otro decodificador que devuelva la cadena original para un flujo de código Morse dado.
Para encontrar el código Morse de un carácter, me referí a la siguiente tabla:

Para traducir código Morse a carácter equivalente, puede organizarse en un árbol binario como se muestra. Con cada 'punto' moviéndose al subárbol izquierdo y 'raya' al derecho.

Esto me permitió codificar rápidamente una cadena a su respectivo código Morse y viceversa.
Escribí un programa en C# como prueba de concepto:

Salida del codificador
Hello World .... . .-.. .-.. --- .-- --- .-. .-.. -..
Sin embargo, como la comunicación debe ocurrir entre dos partes, quise transmitir este código Morse codificado a otro dispositivo y decodificarlo allí.
Usé dos placas Arduino para construir un transmisor y un receptor.
Transmisor
En la placa transmisora, conecté un diodo láser de Keyes. Fácilmente disponible y barato. Para la distancia que trabajo, 3V era suficiente, pero con 5V veo el láser alcanzando al menos 200m.

Mi transmisor está conectado a una computadora con interfaz Serial (por USB). Lee carácter por carácter cualquier dato en el puerto Serial, encuentra el código Morse equivalente y genera un flujo de luz de 'puntos' y 'rayas'.
Creé un pulso de 50ms, donde cada 'punto' es un haz de luz de 50ms y una 'raya' de 150ms. Cada 'punto' y 'raya' se separan por 50ms de silencio. Cada carácter va seguido de otros 100ms de silencio.
Código del Transmisor
const char* MorseTable[] = {
// Tabla completa de códigos Morse para caracteres ASCII
// Índices 0-31: caracteres de control (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,
// 32: espacio, 33: !, 34: ", 35: #, 36: $, 37: %, 38: &, 39: '
NULL, "-.-.--", ".-..-.", NULL, NULL, NULL, NULL, ".----.",
// 40: (, 41: ), 42: *, 43: +, 44: ,, 45: -, 46: ., 47: /
"-.--.", "-.--.-", NULL, ".-.-.", "--..--", "-....-", ".-.-.-", "-..-.",
// 48: 0, 49: 1, 50: 2, 51: 3, 52: 4, 53: 5, 54: 6, 55: 7
"-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...",
// 56: 8, 57: 9, 58: :, 59: ;, 60: <, 61: =, 62: >, 63: ?
"---..", "----.", "---...", "-.-.-.", NULL, "-...-", NULL, "..--..",
// 64: @, 65: A, 66: B, 67: C, 68: D, 69: E, 70: F, 71: G
".--.-.", ".-", "-...", "-.-.", "-..", ".", "..-.", "--.",
// 72: H, 73: I, 74: J, 75: K, 76: L, 77: M, 78: N, 79: O
"....", "..", ".---", "-.-", ".-..", "--", "-.", "---",
// 80: P, 81: Q, 82: R, 83: S, 84: T, 85: U, 86: V, 87: W
".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--",
// 88: X, 89: Y, 90: Z, 91: [, 92: \, 93: ], 94: ^, 95: _
"-..-", "-.--", "--..", NULL, NULL, NULL, NULL, "..--.-",
// 96: ', 97: a, 98: b, 99: c, 100: d, 101: e, 102: f, 103: g
NULL, ".-", "-...", "-.-.", "-..", ".", "..-.", "--.",
// 104: h, 105: i, 106: j, 107: k, 108: l, 109: m, 110: n, 111: o
"....", "..", ".---", "-.-", ".-..", "--", "-.", "---",
// 112: p, 113: q, 114: r, 115: s, 116: t, 117: u, 118: v, 119: w
".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--",
// 120: x, 121: y, 122: z, 123: {, 124: |, 125: }, 126: ~, 127: DEL
"-..-", "-.--", "--..", NULL, NULL, NULL, NULL, NULL
};
int dotLength = 50;
int dashLength = dotLength * 3;
void setup() {
pinMode(13, OUTPUT);
Serial.begin(9600);
}
void loop() {
char ch;
if (Serial.available()) {
ch = Serial.read();
flashDashDot(MorseTable[ch]);
delay(dotLength * 2); // pausa entre caracteres
}
}
void flashDashDot(const char* morseCode) {
int i = 0;
while (morseCode[i] != 0) {
if (morseCode[i] == '.') dot();
else if (morseCode[i] == '-') dash();
i++;
}
}
void dot() {
digitalWrite(13, HIGH);
delay(dotLength);
digitalWrite(13, LOW);
delay(dotLength);
}
void dash() {
digitalWrite(13, HIGH);
delay(dashLength);
digitalWrite(13, LOW);
delay(dotLength);
}
Receptor
En la placa receptora, conecté una LDR, un zumbador piezoeléctrico y un LED. El LED y el zumbador son redundantes, solo dan retroalimentación audio y video y se siente bien ver que funciona ;)

Mi receptor también está conectado a una computadora para leer la cadena resultante.
En el dispositivo, en un bucle, leo cualquier luz que incida en la LDR conectada al puerto analógico 4. La protegí de luz ambiente encapsulándola en un tubo largo. Cuando la luz de mi diodo láser golpea esta LDR, el valor resultante sube y enciendo el altavoz y el LED. Cuando baja, los apago.
Calculo la longitud del haz de luz para determinar si fue un 'punto' o una 'raya'. Contabilizando todos los delays, resultó en ~400 ciclos para un pulso en mi procesador Atmel de 16MHz.
Código del Receptor
// Árbol binario de código Morse
// Hijo izquierdo en 2n+1, derecho en 2n+2
// <.|-> .E -T .I -A .N -M
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',
'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','?','_','\0','\0','\0',
'\0','"','\0','\0','.','\0','\0','\0','\0','@','\0','\0','\0','\0','\0','\0',
'-','\0','\0','\0','\0','\0','\0','\0','\0',';','!','\0',')','\0','\0','\0',
'\0','\0',',','\0','\0','\0','\0',':','\0','\0','\0','\0','\0','\0','\0'
};
int val = 0; // Valor de luz de la LDR
int ctrHigh = 0; // Contador nivel alto
int ctrLow = 0; // Contador nivel bajo
int codePtr = 0; // Puntero en árbol Morse
int dotLen = 400; // Longitud de punto en ciclos
void setup() {
Serial.begin(9600);
Serial.print(codePtr);
}
void loop() {
val = analogRead(4);
if (val >= 10) { // Luz detectada
ctrHigh++;
ctrLow = 0;
digitalWrite(13, HIGH);
tone(9, 1000);
} else { // Sin luz
ctrLow++;
// Determinar si fue punto o raya
if ((ctrHigh >= dotLen) && (ctrHigh < dotLen * 2)) {
Serial.print(".");
codePtr = (2 * codePtr) + 1; // Izquierda
} else if (ctrHigh >= dotLen * 2) {
Serial.print("-");
codePtr = (2 * codePtr) + 2; // Derecha
} else {
// Fin de carácter: silencio de 2*dotLen
if (ctrLow == dotLen * 2) {
Serial.print(MorseTree[codePtr]);
codePtr = 0;
}
}
ctrHigh = 0;
digitalWrite(13, LOW);
noTone(9);
}
}
Salida en el Receptor
....H.E.-..L.-..L---O.--W---O.-.R.-..L-..D-.-.--!
Código completo
Los códigos completos para Transmisor y Receptor están disponibles en la sección de código del proyecto original.
Esquemáticos
Circuito Receptor de Código Morse
Circuito Transmisor de Código Morse
Archivos Fritzing disponibles: morsereceiver_1JpG6jZ6yv.fzz y morsetransmitter_sOKvrIbOv3.fzz
Proceso de manufactura
- Escáner de código de barras: Tecnología, diseño y tendencias futuras
- Construye un Decodificador DTMF Solo con Arduino – Sin CI Externos
- SERENA: Sistema de Alarma Personalizado Arduino Mega 2560 con Pantalla TFT LCD Táctil
- Comunicación Código Morse con Módulo Láser – Proyecto Arduino de Doble Lado
- Código Morse y Doble Extorsión: Panorama Actual de Amenazas Avanzadas de Malware
- Elección entre Data Matrix y Códigos QR: ¿Cuál es Mejor para su Negocio?
- Códigos G CNC Explicados: Guía Esencial para Programadores
- Referencia Completa de Códigos G Fanuc – Todos los Comandos Explicados
- Guía Completa de Códigos G CNC para Controles Fanuc
- Dominando las tasas de error de código en ADC: Lo que necesita saber
- Comentarios en C++: Mejores Prácticas para Código Legible y Mantenible