// morse-decode-encode
// by Oompah
// March 3 2023
// credit to "Programming Arduino" by Simon Monk, (c)2016
// for some of the code lines
//
// Either Key in a Morse code sequence using the button to decode,
// or click in the field in the Serial Monitor, and
// type letters followed by Enter to encode into Morse code.
// The LED and tone will sound while you key in the sequence.
// This sketch decodes sequences with letters or numbers
// and prints them to the serial monitor.
// A beep sounds and "?" prints for unrecognized sequences.
//
// To learn Morse Code, type a word in the Serial Monitor,
// Then try keying in the same word as you heard it.
// Tips:
// Keep dots short, and dashes long.
// Leave a short space after letters.
// Leave a longer space after words.
// Try to make nice clean presses and releases.
//
// Circuit:
// Piezo buzzer or speaker connects to pin 2 and ground
// Button connects between pin 8 and ground
// LED (+) to pin 13, (-) 220 Ohm resistor to ground
//
int tonePin = 2;
int toneFreq = 1000;
int ledPin = 13;
int buttonPin = 8;
int debounceDelay = 30;
int dotLength = 240;
// dotLength = basic unit of speed in milliseconds
// 240 gives 5 words per minute (WPM) speed.
// WPM = 1200/dotLength.
// For other speeds, use dotLength = 1200/(WPM)
//
// Other lengths are computed from dot length
int dotSpace = dotLength;
int dashLength = dotLength*3;
int letterSpace = dotLength*3;
int wordSpace = dotLength*7;
float wpm = 1200./dotLength;
int t1, t2, onTime, gap;
bool newLetter, newWord, letterFound, keyboardText;
int lineLength = 0;
int maxLineLength = 20;
char* letters[] =
{
".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", // A-I
".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", // J-R
"...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.." // S-Z
};
char* numbers[] =
{
"-----", ".----", "..---", "...--", "....-", //0-4
".....", "-....", "--...", "---..", "----." //5-9
};
String dashSeq = "";
char keyLetter, ch;
int i, index;
void setup()
{
delay(500);
pinMode(ledPin, OUTPUT);
pinMode(tonePin, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
Serial.println();
Serial.println("-------------------------------");
Serial.println("Morse Code decoder/encoder");
Serial.print("Speed=");
Serial.print(wpm);
Serial.print("wpm, ");
Serial.print("dot=");
Serial.print(dotLength);
Serial.println("ms");
// Test the LED and tone
tone(tonePin, toneFreq);
digitalWrite(ledPin, HIGH);
delay(2000);
digitalWrite(ledPin, LOW);
noTone(tonePin);
delay(600);
//flash to demonstrate the expected key speed
//A
Serial.print("A .- ");
index = 'A'-65;
flashSequence(letters[index]);
delay(wordSpace);
//B
Serial.print("B -... ");
index = 'B'-65;
flashSequence(letters[index]);
delay(wordSpace);
//C
Serial.print("C -.-. ");
index = 'C'-65;
flashSequence(letters[index]);
delay(wordSpace);
Serial.println();
Serial.println("-------------------------------");
Serial.println("Click field in Serial Monitor,");
Serial.println("type text and press Enter, or");
Serial.println("Key in Morse Code to decode:");
Serial.println("-------------------------------");
newLetter = false; //if false, do NOT check for end of letter gap
newWord = false; //if false, do NOT check for end of word gap
keyboardText = false;
}
void loop()
{
// Check to see if something has been entered on the keyboard
if (Serial.available() > 0)
{
if (keyboardText == false)
{
Serial.println();
Serial.println("-------------------------------");
}
keyboardText = true;
ch = Serial.read();
if (ch >= 'a' && ch <= 'z')
{ ch = ch-32; }
if (ch >= 'A' && ch <= 'Z')
{
Serial.print(ch);
Serial.print(" ");
Serial.println(letters[ch-'A']);
flashSequence(letters[ch-'A']);
delay(letterSpace);
}
if (ch >= '0' && ch <= '9')
{
Serial.print(ch);
Serial.print(" ");
Serial.println(numbers[ch-'0']);
flashSequence(numbers[ch-'0']);
delay(letterSpace);
}
if (ch == ' ')
{
Serial.println("_");
delay(wordSpace);
}
// Print a header after last keyboard text
if (Serial.available() <= 0)
{
Serial.println();
Serial.println("Enter text or Key in:");
Serial.println("-------------------------------");
keyboardText = false;
}
}
if (digitalRead(buttonPin) == LOW ) //button is pressed
{
newLetter = true;
newWord = true;
t1=millis(); //time at button press
digitalWrite(ledPin, HIGH); //turn on LED and tone
tone(tonePin, toneFreq);
delay(debounceDelay);
while (digitalRead(buttonPin) == LOW ) // wait for button release
{delay(debounceDelay);}
delay(debounceDelay);
t2 = millis(); //time at button release
onTime=t2-t1; //length of dot or dash keyed in
digitalWrite(ledPin, LOW); //torn off LED and tone
noTone(tonePin);
//check if dot or dash
if (onTime <= dotLength*1.5) //allow for 50% longer
{dashSeq = dashSeq + ".";} //build dot/dash sequence
else
{dashSeq = dashSeq + "-";}
} //end button press section
// look for a gap >= letterSpace to signal end letter
// end of letter when gap >= letterSpace
gap=millis()-t2;
if (newLetter == true && gap>=letterSpace)
{
//check through letter sequences to find matching dash sequence
letterFound = false; keyLetter = 63; //char 63 is "?"
for (i=0; i<=25; i++)
{
if (dashSeq == letters[i])
{
keyLetter = i+65;
letterFound = true;
break ; //don't keep checking if letter found
}
}
if(letterFound == false) //now check for numbers
{
for (i=0; i<=10; i++)
{
if (dashSeq == numbers[i])
{
keyLetter = i+48;
letterFound = true;
break ; //don't keep checking if number found
}
}
}
Serial.print(keyLetter);
if(letterFound == false) //buzz for unknown key sequence
{
tone(tonePin, 100, 500);
}
newLetter = false; //reset
dashSeq = "";
lineLength=lineLength+1;
}
// keyed letter has been identified and printed
// when gap is >= wordSpace, insert space between words
// lengthen the word space by 50% to allow for variation
if (newWord == true && gap>=wordSpace*1.5)
{
newWord = false;
Serial.print("_");
lineLength=lineLength+1;
// flash to indicate new word
digitalWrite(ledPin, HIGH);
delay(25);
digitalWrite(ledPin, LOW);
}
// insert linebreaks
if (lineLength >= maxLineLength)
{
Serial.println();
lineLength = 0;
}
}
void flashSequence(char* sequence)
{
int i = 0;
while (sequence[i] == '.' || sequence[i] == '-')
{
flashDotOrDash(sequence[i]);
i++;
}
}
void flashDotOrDash(char dotOrDash)
{
digitalWrite(ledPin, HIGH);
tone(tonePin, toneFreq);
if (dotOrDash == '.')
{ delay(dotLength); }
else
{ delay(dashLength); }
digitalWrite(ledPin, LOW);
noTone(tonePin);
delay(dotLength);
}
//--- end of sketch ---