Morse Code Generator

Lets Beef-Up the ‘Blink’ Program

A blinking circuit may be useful as a signal to warn others of dangerous situations or to draw people’s attention. Another use for a blinking light is to communicate with someone over a distance. The following program makes use of the blinking light circuit to implement a Morse code generator.

Around 1837, the American Samuel F. B. Morse invented an early version of what was to become Morse code. Morse code is a method of transmitting information as a series of on-off tones, lights, or clicks. Basically, letters, numbers, and punctuation marks are translated to a variable length collection of dots and dashes, of shorter and longer bursts of sound or light. The duration of the dot, the short burst, is the unit of time by which all other elements of Morse code are defined. A dash, the long burst, is a signal whose duration is three times that of the dot. The time between dots and dashes within an encoded character is one unit of time. the time between characters is three units of time and the time between words is seven units of time.

International Morse code is thus composed of five elements:

  • short mark, dot or ‘dit’: one time unit long
  • longer mark, dash or ‘dah’: three time units long
  • gap between the dots and dashes within a character: one time unit long
  • gap between letters of a word: three time units long
  • gap between words: seven time units long

Following, is the international Morse code equivalent, in dot (.) and dash (-) notation for each alphabetical and numerical character:

315px-International_Morse_Code.svg

For instance, if we are to show the character sequence “PARIS” in Morse code, we can represent it in text as “.–.  .-  .-.  ..  …” and if we want to represent it as a series of on and off signals, arbitrarily represented by an equal sign “=” and an underscore “_” respectively, each one time unit in duration and we follow the rules stated above, we get the following signal:

___=_===_===_=___=_===___=_===_=___=_=___=_=_=___

The following program, written in “C” for the Arduino, converts a character string of alphabetical characters into a series of short and long blinking LED signals corresponding to their morse code equivalent. You can reconstruct the program in the Arduino IDE (Integrated Development Environment) by copying the code from this post and pasting it in sequence, as it appears in this text, in the text editing pane of the IDE.

The Program Header

The program header, a few paragraphs down, contains a comment describing the nature and purpose of the program as well as a copyright notice. I am the author of the code and I have put it in the public domain. Comments are character sequences ignored by the program interpreter or compiler. Comments can be formatted as any text between a slash-asterisk, ‘/*‘, and asterisk-slash, ‘*/‘, character sequences. This is the original way to enter comments in the ‘C’ language. Text enclosed between these two-character sequences can span several lines and are ignored. Comments can also be entered after a double-slash, ‘//‘, character sequence. All text after the double-slash character sequence, until the end of line, is considered a comment and is ignored by the program interpreter or compiler.

We define the digital output PORT as LED_BUILTIN, the digital output port corresponding to the Arduino’s built-in LED. The UNIT_TIME value corresponds to the time in milliseconds of the ‘on’ duration of the dot. The #define statement allows programmers to associate text to a name. When the program is compiled, the text replaces the name whenever it appears in the program. At compile time, PORT is replaced by the Arduino LED_BUILTIN  constant and UNIT_TIME is replaced by the integer value 100. Note that LED_BUILTIN is also a definition and it gets substituted by the appropriate integer value depending on the target Arduino board.

The characters String variable and codedCharacters String array variable work in tandem as the list of supported characters and their corresponding Morse code equivalent. The Morse code equivalent is encoded as a character string containing a series of period (‘.‘) and dashes (‘‘) representing the short and long bursts of Morse code. Each string in the codedCharacters array corresponds to the character at the same index in the characters string variable.

/* Morse Code Generator
   Blink an LED connected to pin LED_BUILTIN to display morse
   code corresponding to text entered. Repeats forever.
   This sketch was written by Michel Lagacé, 2018-09-02
   This code is in the public domain */

// Output port to display morse code
#define PORT LED_BUILTIN

// unit time length of the morse encoding
#define UNIT_TIME 100

// Characters to be encoded
static String characters = "abcdefghijklmnopqrstuvwxyz";

// Morse code sequences for each character
static String codedCharacters[] = { 
    ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....",
    "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.",
    "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-",
    "-.--", "--.." };

In ‘C++‘, an array is a collection of elements accessible through the use of an index. A String is a specialized array for collections of characters. Thus, each character in a String and each element of an array can be accessed through the use of an index. An index is an integer value enclosed in square brackets ([ ]) right after the variable name. The first character of a string or element in an array has index 0. The second character or element has index 1 and each successive character or element’s index is one more than the preceding index.

In the code above, character ‘c’ is at index 2 in the characters String. The corresponding Morse code sequence, “-.-.”, is a String at index 2 in the codeCharacters String array. The characters variable is declared as static meaning that the variable’s memory is allocated once at the start of the program and remains for the duration of the program. Non-static variables in functions are allocated in memory only for the duration of the execution of the function, then released back to the pool of memory a program can use. This is very useful for very large programs as only the necessary memory is used at any time. The characters String is initialized with the character string “abcdefghijklmnopqrstuvwxyz”. codedCharacters is also declared as a static String, but the variable name is followed by square brackets. These square brackets indicate that the variable is an array. The size of the array is set to the number of elements it is initialized with. In this case, 26 elements. If an uninitialized array is to be created, the size can be specified as a value within the square brackets.

Digital Output Setup

The setup of the digital output to blink an LED is identical to the setup in the ‘BLINK’ circuit demonstration. We set the pin mode to OUTPUT.

// Setup the board. Digital port LED_BUILTIN in output mode
void setup() {
    pinMode(PORT, OUTPUT);
}

Outputting Dots and Dashes

Code can be, and should be, segregated into functions that provide specific well-defined functionality to a program. Functions, also called subroutines, are sequences of code that can be called by name. In the ‘C’ language, functions must be defined before they are used and thus must appear in the code before any code that uses them. The simplest functions have the following structure:

void functionName() {
    // Sequence of code the function performs when called
}

The void reserved word specifies that the function does not return any value. The we have the function name, followed by a sequence of code enclosed in curly braces, ‘{‘ and ‘}‘. Elsewhere in the program, if we want to call up the sequence of code contained i the function, we simply use the function name, followed by parentheses and a semicolon:

    functionName();

In the Morse code program, we first define two functions, one to output a dot, put the LED on for one time unit, then off for one time unit; and the other to output a dash, put the LED on for three time units, then off for one time unit. In the following code, you will find both functions. They are very similar to the code found in the original ‘BLINK’ program: lights on, lights off.

/* Function to output a dot: one unit on, one unit off */
void outputDot() {
    digitalWrite(PORT,HIGH);
    delay(UNIT_TIME);
    digitalWrite(PORT,LOW);
    delay(UNIT_TIME);
}

/* Function to output a dash: three units on, one unit off */
void outputDash() {
    digitalWrite(PORT,HIGH);
    delay(UNIT_TIME*3);
    digitalWrite(PORT,LOW);
    delay(UNIT_TIME);
}

Encoding a Character in Morse Code

Next, we have a function that outputs a character as a series of dots and dashes. Before having a look at this function, let’s go through a few concepts that will help people unfamiliar with ‘C++’ understand the code better.

‘C++’ Classes

In ‘C++’, functions can be attached to data structures called classes. I will not delve on classes, but suffices to say that these functions are called methods. The String data type is actually a class called String. Variables created with a class are usually called objects. In the case of the String class, because it is used as a data type, I will still call them variables. The String class has several methods associated with it. in the following function, we use the indexOf() and length() methods. The indexOf() method returns the index of the first occurrence of the character passed as an argument in the String. The length() method returns the number of characters in the String. To use a method associated to a variable, use the variable name followed by a period, followed by the method name, parentheses, and any parameter required by the method. It is like calling a function, but preceded by the variable name. Thus, to get the index of the position of letter ‘f’ within the characters String and initialize the index variable with it, use the following code:

    int index = characters.indexOf('f');

index will be initialized with the value 5, the index of the letter ‘f’ in the String characters.

The outputCharacter function introduces us to two fundamental programming structures. The for-loop, and the if-then-else structures.

if-then-else Control Structure

The if-then-else control structure allows a program to conditionally execute a portion of a program. It has the following structure:

    if (condition) {
        // Code to execute if condition is true
    }
    else if (other condition) {
        // Code to execute if other condition is true
    }
    else {
        // Code to execute if all preceding conditions are false
    }

Only the first if block is mandatory; the else if and else blocks are optional. The execution flow is as follows: if the condition specified within parenthesis after the first if is true, then the code within the curly braces following the if statement is executed; if the condition within the first if statement is false then the condition in the else if statement is checked; if the condition in the else if statement is true, then the code within the curly braces following the else if statement is executed; if the condition in the else if statement is false, then the code contained within the curly braces after the else statement is executed. There can be several else if statements, each testing a different condition.

for-loop Control Structure

The for-loop control structure allows the program to iterate through code several times until a condition is met. It has the following structure:

    for (initialization; condition; post-processing {
        // Code to execute until condition is met
    }

where initialization is a statement executed just before entering the loop; condition is a test performed at the beginning of the loop, if true, code within the for-loop curly braces is executed, if false, execution continues after the loop; and post-processing, is a statement executed after each iteration through the code within the curly brackets. For instance, in the following for-loop control structure:

    for (int i = 0; i < 10; i++) {
        // Code executed 10 times
    }

Variable i is initialized to 0 before entering the loop; i is tested if smaller than 10, since it is, the code within the curly braces is executed and i is available for use within this code; after the code within the curly braces is executed, the variable i is incremented by 1. A second iteration of the loop then starts and i is tested if smaller than 10. The loop continues until the condition i < 10 is false. The loop executes 10 times with values of i from 0 to 9.

outputCharacter Function

Looking at the function header, we find that it is similar to the previous functions, but has a parameter within the parentheses: char c. This defines a single character parameter to the function. Parameters allows the calling program to pass values to the function. In this case, the character to be output as Morse code. Within the outputCharacter function, variable index is set to the index of character c in the characters String. If the character is found, that is if index is greater or equal to 0, then we output the Morse code. To do so, we get the Morse code associated with the character using index to retrieve the Morse code string from codedCharacters. We then iterate through each character of the Morse code and output a dash, if the character is a hyphen or a dot otherwise using the outputDash() and outputDot() functions respectively. At the end of the character output, we wait an extra 2 units of time, totaling the 3 units of time required at the end of a Morse code character. The wait totals 3 units of time since we already introduced a single unit of time delay at the end of the dash or dot.

/* Function to output a single character */
void outputCharacter(char c) {

    // Find index of character to encode
    int index = characters.indexOf(c);
 
    // Ignore unencodable characters
    if (index >= 0) {

        // Encode Morse code and output it
        String code = codedCharacters[index];
        for (int i = 0; i < code.length(); i++) {
            if (code[i] == '-') {
                outputDash();
            }
            else { // if not '-', must be '.'
                outputDot();
            }
        }

        // wait 3 units at the end of the letter
        // (2 units assuming previous dot or dash)
        delay(UNIT_TIME*2);
    }
}

Encoding Text into Morse Code

The sentence function’s purpose is to output text as Morse code. It accepts the single String parameter: text. First, the function gets the length of the text and stores it in the len variable. It then iterates through the whole text String using i as the index in a for-loop structure from 0 until len – 1. It gets the character indexed by i and turns it to lowercase using the tolower() built-in function. If the character is not a space, it is output using outputCharacter(). If the character is a space, we wait an extra 4 units of time, totaling the 7 units of time required at the end of a word. The wait amounts to 7 units of time since we already added 3 units of time at the end of the previous Morse code character output.

// Function to encode a whole string
void sentence (String text) {
    // Compute length of character string
    int len = text.length();

    // Output each character in turn
    for (int i = 0; i < len; i++) {

        // Only lower case characters are encoded
        char c = tolower(text[i]);
        if (c != ' ') {
            outputCharacter(c);
        }
 
        // Spaces are encoded as 7 units,
        // (4 units assuming a previous character)
        else {
            delay(UNIT_TIME*4);
        }
    }
}

The Main Loop

Finally, this is the main loop(). This code is repeated over and over. It outputs the text “Mikes Electro Shack” in Morse code, then waits 28 units of time corresponding to 4 spaces between words. The delay is actually specified as 25 units of time since the last character output already added a 3 units of time delay. You can of course replace the text by any text you see fit.

void loop() {
    sentence("Mikes Electro Shack");
    delay(UNIT_TIME*25); // Wait 4 spaces at the end
}

What Next?

Through the implementation of this fairly simple program, we have seen two extremely important control structures, the if-then-else control structure and the for-loop control structure. We have seen that the String data type is implemented as a class and that there are methods associated with it. We also have seen a few String methods such as indexOf() and length().

This program can be put to use to learn Morse code, which is required to get one’s ham radio (amateur radio) license. Complete the list of characters to include numbers and punctuation marks and their equivalent Morse code to complete the experience.

Published by

Michel Lagacé

40 years working in the high technology sector, I now share tips and tricks on software and electronics. I also write in my spare time.

3 thoughts on “Morse Code Generator”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s