Introduction: Arduino Morse Decoder
This device reads hand keyed Morse code from a signal key (or an ordinary switch) and translates it to plain text and show the Morse code you're keying on an LCD. I use it to train my own Morse keying skills.
The decoder automatically corrects itself for your keying speed.
Step 1: Requirements
Step 2: Hardware Setup
Setup the hardware by hooking up everything as shown in the schematic diagram.
Connect the buzzer between GND and pin 8 of the Arduino and the Morse key (I use a tactile switch) between GND and pin 7.
Besides the GND and +5V pins the LCD has an SCL and SDA connection that you connect to the pins with the same names on the Arduino. I didn't use pull-up's to connect the LCD, but you could if you want to.
Step 3: Software
Upload the sketch (Seinsleutel2.ino) in the Arduino. I also included the library that I needed to use to control the LCD.
And start keying (see the video for a demonstration).
39 Comments
6 years ago
Hi Hackertie,
I am studying your source code and I have a question about the algorithm you use to identify a Pause and start decoding the "Kar"achter. Why do you use
if (tijd > StreepDuur - StreepDuur / 40 ) ? is it a spece between two letters?
and
if (tijd > StreepDuur * 2) ? is it the space between two words?
Many thanks
Fabio
Reply 6 years ago
StreepDuur == the duration of a dash
tijd == time
The statement "if (tijd > StreepDuur - StreepDuur / 40): decodes a space between two letters.
And "(tijd > StreepDuur * 2)" is for decoading a space between words.
Som more explanation:
PuntDuur == Duration of a dot
starttijd == Start time
Reply 10 days ago
Would you please explain how the following statements work?
(1) if (tijd > StreepDuur - StreepDuur / 40 )
(2) if (tijd > StreepDuur * 2)
(3) if ((tijd > (StreepDuur + PuntDuur) / 1.9) && tijd <= StreepDuur)
Reply 6 years ago
thanks a lot.
Fabio
6 years ago
i have a error in the part of the code: LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); its told me that POSITIVE is not declared
Reply 2 months ago
Me too.
I need how to fix it.
2 years ago
for those with an LCD 1602. I adapted the code:
// Morse-decodeerder
// (C) 2016 Demented hacker
#include <Wire.h>
#include <LiquidCrystal.h> // https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads ==> LiquidCrystal_V1.2.1.zip
// Verbind een tactile schakelaar (of seinsleutel) tussen pen 7 van de Arduino en GND.
// En sluit een buzzer aan tussen Arduino pen 8 en GND.
// Dan kun je met de schakelaar seinen. Bekijk de gedecodeerde Morse-code in de serial monitor.
#define SLEUTEL 7 // Seinsleutel van pen 7 naar GND
#define BUZZER 8 // Buzzer van pen 8 naar GND
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
pinMode(SLEUTEL, INPUT_PULLUP);
pinMode(BUZZER, OUTPUT);
Serial.begin(115200);
lcd.begin(16, 2);
// lcd.backlight();
}
float StreepDuur = 300.0;
boolean PrevS = false;
long tStartTeken, tStartPauze;
boolean S;
String kar = "";
void loop() {
S = !digitalRead(SLEUTEL);
if (S) {
if (S != PrevS) {
tStartTeken = millis();
DecodeerPauze(tStartPauze);
}
digitalWrite(BUZZER, HIGH);
}
else {
if (S != PrevS) {
tStartPauze = millis();
Decodeer(tStartTeken);
}
digitalWrite(BUZZER, LOW);
}
if (abs(millis() - tStartPauze) > StreepDuur * 10) {
DecodeerPauze(tStartPauze);
}
PrevS = S;
}
void Decodeer(long starttijd) {
char teken = '?';
long tijd = abs(millis() - starttijd); // Tijdsduur van het geseinde teken (een punt of een streep)
float PuntDuur = StreepDuur / 3.0;
if (tijd <= 2) return; // Denderonderdrukking
if (tijd <= PuntDuur) teken = '.';
else if (tijd > StreepDuur) teken = '-';
else if ((tijd > (StreepDuur + PuntDuur) / 1.9) && tijd <= StreepDuur) teken = '-';
else teken = '.';
if (teken == '-') {
if (tijd > StreepDuur) StreepDuur++;
if (tijd < StreepDuur) StreepDuur--;
}
else if (teken == '.') {
if (tijd > StreepDuur / 3.0) StreepDuur++;
if (tijd < StreepDuur / 3.0) StreepDuur--;
}
kar += teken;
//Serial.println(teken);
}
void DecodeerPauze(long starttijd) {
if (kar == "") return;
char teken = '?';
long tijd = abs(millis() - starttijd);
if (tijd > StreepDuur - StreepDuur / 40) {
DecodeerKar();
//Serial.print();
}
if (tijd > StreepDuur * 2) {
DecodeerKar();
Print(" "); Serial.print(" ");
}
//else DecodeerKar();
//Serial.println(teken);
}
void DecodeerKar() {
static String letters[] = {
".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-",
".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", "E"
};
int i = 0;
while (letters[i] != "E") {
if (letters[i] == kar) {
Print((char)('A' + i));
Serial.print((char)('A' + i));
break;
}
i++;
}
if (letters[i] == "E") {
Print(kar);
Serial.print(kar);
}
kar = "";
}
int y = 0, x = 0;
void Print(String &s) {
for (int i = 0; i < s.length(); i++) {
upd(); lcd.print(s[i]);
}
}
void Print(char s) {
upd();
lcd.print(s);
}
void Print(char *s) {
for (int i = 0; i < strlen(s); i++) {
upd();
lcd.print(s[i]);
}
}
void upd() {
lcd.setCursor(x, y);
x++; if (x >= 16) {
x = 0;
y++;
}
if (y >= 2) {
lcd.clear();
x=y = 0;
}
}
6 years ago
Leuk project, ik ga dit eens uitproberen. Ik ben bezig voor het Museum Engelandvaarders waar we een seinsleutel hebben uit de 2e wereldoorlog. De bezoeker mag straks letter voor letter morsecode nadoen in de hoop dat er wat leesbaars op het scherm komt. Ik heb wel de timing een beetje aangepast. Een dot is 200ms.
Reply 3 years ago
"Nice project, I'm going to try this out. I am working for the Museum Engelandvaarders where we have a key from the 2nd World War. The visitor may later copy letter by letter morse code in the hope that something readable on the screen. I have adjusted the timing a bit. A dot is 200ms."
I had to translate it to understand this
4 years ago
Funny story... I tried to burn this to a Wemos board ESP-WROOM-02 without thinking enough. On that board, pins 7 & 8 aren't brought out but actually used to communicate with the module's flash. Setting buzzer(8) to an output led to a shoving match that the flash lost. I replaced the flash and the Wemos talks again.. Lesson learned: sometimes software problems aren't fixed by powering down. (that and I should think more)
4 years ago
Hi Sir, Thanks a lot for this lesson, can you send me the code? because i did not find it
Reply 4 years ago
the code inside the .ino file. Download the file-> open the arduino IDE -> file-> open-> chose the file that you had been downloaded
5 years ago
May I use this code as the basis for a geocache? I will, of course, refer to your name and work in my modified code. The object of the cache would be for the finder to translate a specific word into the dots and dashes of morse code. When the program recognizes the correct word, a servo will release a lock and provide access to the cache container. Please let me know if I may do this.
6 years ago
For those who do not have the I2C type liquid crystal display it should be easy to change this to use a standard 1602 style parallel interfaced LCD. Also possible to use Serial.print() to send text information to either the terminal screen that is built into the IDE or to an attached PC running a terminal emulator that is capable of connecting via tty/USB mode.
The I2C LCD library is in the zip file and can be installed in your IDE once the file has been unzipped.
It makes no difference whether variables are named in German or some other language. The compiler just converts them to numeric tokens and compiles them as defined. An example of this might be the define "int x = 5", where x is neither English or German, or both, and the compiler handles this variable name with no problem.
Reply 5 years ago
Just to be more precise, I had to use a different library for the 1602A:
#include <LiquidCrystal.h>
Initializing the LCD with pins:
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
Then take into account it has 2 rows and 16 columns in the setup
lcd.begin(16, 2);
And also in the upd function
x++; if (x >= 16) {
if (y >= 2) {
I hope it helps!
Reply 5 years ago
Are you able to post the entire code with your updates? I am new to this and am not sure why nothing is coming up on the LCD. Thanks!!!
Reply 5 years ago
Hi kangetsu
sorry for late reply, I am not sure how to upload the entire code, check the connections between the Arduino and the LCD, they should be smthg like:
LCD Arduino/protobrd
K GND
A 100ohm resistor to vcc (5V)
D7 D2
D6 D3
D5 D4
D4 D5
E D11
RW GND
RS D12
V0 100ohm resistor to GND
VDD Vcc - 5V
VSS GND
Resistor values could be changed to adjust the backlight and char light to your needs
hope it helps!!
6 years ago
im getting more questionmarks than letters - is something wrong with my setup ?
6 years ago
I dont have the lcd display, so how can I display the reading into the monitor serial?
Reply 6 years ago
Serial.print(variable_name); or Serial.print("text string");