Morse Code Translator
2024-08-16 | By Lucy Camblin
License: See Original Project Pushbutton Arduino
For the last several months, I’ve been interested in completing an embedded systems project to further develop my C++ programming skills and to refresh my knowledge of circuit design. Embedded projects are very interesting to me because I love figuring out how to make hardware and software interact to achieve a straightforward, specific task. I recently came up with the idea of a Morse code translator – this would include input and output components that receive Morse code sequences and display their translations. It also would require a more complex C++ program to monitor the physical inputs and map them to letters in the English alphabet. This seemed like an interesting combination of challenges in hardware and in software, so I thought it would be a useful embedded project for practicing my electrical engineering skills.
To provide a little background, Morse code is a way to represent letters and numbers as dots (.) or dashes (-). Every character has a unique sequence of dots and/or dashes assigned to it, which allows Morse code to behave like its own language. Typically, Morse code is used for telecommunication applications because the dots and dashes represent short and long signals, respectively [1]. More information on the history and applications of Morse code can be found here https://en.wikipedia.org/wiki/Morse_code.
For my project, I wanted to build a system where a user could either press or hold a button to input “dots” or “dashes” in a particular sequence, then use another button to submit that sequence of dots and dashes for translation, so that one letter is displayed at a time on physical hardware. This task would require some sort of microcontroller to handle the Morse code translation as well as the input/output interface of the system. This project would also require electrical components such as push buttons and resistors. For displaying the translated letter, I wanted to use a 7-segment LED display to add complexity to the system instead of just using the microcontroller’s serial monitor.
To build this system, I started with the circuitry and connecting I/O components to the microcontroller. After reading this blog post from DigiKey, I decided to use Tinkercad Circuits to build a circuit virtually. Tinkercad Circuits is a free online circuit simulator that I believe makes testing much easier, which then makes circuit design more seamless and straightforward. I ended up building this entire system within Tinkercad.
I decided to use the following components from DigiKey to create this project:
- Arduino Uno R3
- 7-Segment LED Display
- Resistor kit (0 ohm – 4M ohm)
- Pushbutton
These components (or very similar ones) were all represented in Tinkercad, and they are included in my final design, shown below.
Tinkercad Circuit for Morse Code Translator
The leftmost button is where the user can press or hold to input a dot or dash, respectively. The rightmost button is where the user should press when they are ready to submit the sequence for translation. The translated letter will appear on the 7-segment display, which is the rightmost non-resistive component on the breadboard.
The pushbuttons are configured as analog input signals A4 and A5 on the Arduino – these signals are how the system knows what sequence to translate and when. They are connected to power with 10k-ohm resistors.
The 7-segment display has a less straightforward configuration. I found a helpful blog post that explained how to interface an Arduino with a 7-segment display, which helped me understand the role that this component played in my system. Essentially, there are 7 signals that need to be sent to the display to accurately depict each letter. These 7 signals control the 7 different edges that comprise the “8” shown on the display in the image below.
7-Segment LED Display and Edge Assigments
The system controls which edges (A-G) are turned on at different times. Different edge configurations represent different characters. For example, if all edges are turned on, the number 8 is shown on the display. If all edges except D are turned on, the letter A is shown. I consulted that same blog post when determining the edge configurations for all the letters in the alphabet, as well as for determining how the 7-segment display should be wired in the circuit. Each signal in the display is wired to a 470-ohm resistor to ensure that the proper amount of current is delivered to each edge’s LED in the display.
After assembling this circuit on Tinkercad, I began to develop a C++ program to perform translations. First, I assigned numerical values to all the letters in the English alphabet by following the image below [1].
Wikipedia [1]
In my program, I specified that dots are represented by the digit of 1, and dashes are represented by the digit of 2. Each letter has a unique integer associated with it, where each digit in the integer corresponds to the dash or dot at the same index within the Morse code pattern shown above. For instance, “DigiKey” includes the letters D, I, G, K, E, and Y. The integer corresponding to D in my program is 211, 11 for I, 221 for G, 212 for K, 1 for E, and 2122 for Y.
I ran into a few problems while trying to programmatically differentiate between when a button is pressed and when a button is held down. The simplest way to do this that I found was to take two analog readings for the value of the input button just 100 milliseconds apart and then compare them. If the readings are both nonzero, then the button was likely held down. If the first reading is nonzero, the second reading is zero, and it’s known that the button was not already being held down, then the button was likely pressed. The timing on this is a little finicky since there’s technically one cycle delay between determining if the button was pressed or held and then adding that input to the current sequence (this is shown in more detail in the code below). For this reason, I added the button to “submit” a sequence for translation to ensure that the proper inputs were captured for each letter. A more robust solution would probably involve using a different microcontroller and utilizing its interrupt functionality. However, the approach I used to address timing and pressing versus holding of a button was satisfactory for my project.
I manually assigned the sequences for each letter to a 7-segment LED configuration with a switch statement. After a sequence of up to 4 characters has been submitted, the 7-segment LED display will flash the translated letter for 1.5 seconds, and then the system prompts the user for another sequence using the Arduino’s serial monitor. In the case that a letter cannot be represented by the 7 edges in the 7-segment display (for example, K, V, and Z), the letter is printed onto the serial monitor. I also configured the system to display each pattern using “.” and “-” characters as they’re entered into the system for each sequence.
The C++ program I created for the Morse code to English translator is included below.
int button = A4; // button for morse code inputs
int submit = A5; // button for when a sequence is complete
// variables used to differentiate between pressed and held button
int read1 = 0;
int read2 = 0;
int val = 0; // 1 for dot, 2 for dash
// used to keep track of sequence length
int idx = 0;
// signals for the edges in 7-segment display
int a_pin = 4;
int b_pin = 5;
int c_pin = 7;
int d_pin = 8;
int e_pin = 9;
int f_pin = 3;
int g_pin = 2;
// alphabet to morse code mapping
// a 1 digit indicates a dot
// a 2 digit indicates a dash
// a 0 digit indicates that fewer than 4 digits were needed to represent that number
const int a = 12;
const int b = 2111;
const int c = 2121;
const int d = 211;
const int e = 1;
const int f = 1121;
const int g = 221;
const int h = 1111;
const int i = 11;
const int j = 1222;
const int k = 212;
const int l = 1211;
const int m = 22;
const int n = 21;
const int o = 222;
const int p = 1221;
const int q = 2212;
const int r = 121;
const int s = 111;
const int t = 2;
const int u = 112;
const int v = 1112;
const int w = 122;
const int x = 2112;
const int y = 2122;
const int z = 2211;
int input = 0; // current sequence
void setup() {
// enable serial communication
Serial.begin(9600);
// set signals to 7-segment display as output
pinMode(a_pin, OUTPUT);
pinMode(b_pin, OUTPUT);
pinMode(c_pin, OUTPUT);
pinMode(d_pin, OUTPUT);
pinMode(e_pin, OUTPUT);
pinMode(f_pin, OUTPUT);
pinMode(g_pin, OUTPUT);
// initialize all edges to off in 7-segment display
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, HIGH);
digitalWrite(g_pin, HIGH);
}
void loop() {
if (analogRead(submit) > 0) { // check if sequence has been submitted
Serial.println("");
// check if input matches a letter
switch(input) {
case a:
digitalWrite(a_pin, LOW);
digitalWrite(b_pin, LOW);
digitalWrite(c_pin, LOW);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, LOW);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, LOW);
break;
case b:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, LOW);
digitalWrite(d_pin, LOW);
digitalWrite(e_pin, LOW);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, LOW);
break;
case c:
digitalWrite(a_pin, LOW);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, LOW);
digitalWrite(e_pin, LOW);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, HIGH);
break;
case d:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, LOW);
digitalWrite(c_pin, LOW);
digitalWrite(d_pin, LOW);
digitalWrite(e_pin, LOW);
digitalWrite(f_pin, HIGH);
digitalWrite(g_pin, LOW);
break;
case e:
digitalWrite(a_pin, LOW);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, LOW);
digitalWrite(e_pin, LOW);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, LOW);
break;
case f:
digitalWrite(a_pin, LOW);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, LOW);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, LOW);
break;
case g:
digitalWrite(a_pin, LOW);
digitalWrite(b_pin, LOW);
digitalWrite(c_pin, LOW);
digitalWrite(d_pin, LOW);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, LOW);
break;
case h:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, LOW);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, LOW);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, LOW);
break;
case i:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, LOW);
digitalWrite(c_pin, LOW);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, HIGH);
digitalWrite(g_pin, HIGH);
break;
case j:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, LOW);
digitalWrite(c_pin, LOW);
digitalWrite(d_pin, LOW);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, HIGH);
digitalWrite(g_pin, HIGH);
break;
case k:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, HIGH);
digitalWrite(g_pin, LOW); // print out letter in terminal
Serial.println("K");
break;
case l:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, LOW);
digitalWrite(e_pin, LOW);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, HIGH);
break;
case m:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, HIGH);
digitalWrite(g_pin, LOW);
Serial.println("M");
break;
case n:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, LOW);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, LOW);
digitalWrite(f_pin, HIGH);
digitalWrite(g_pin, LOW);
break;
case o:
digitalWrite(a_pin, LOW);
digitalWrite(b_pin, LOW);
digitalWrite(c_pin, LOW);
digitalWrite(d_pin, LOW);
digitalWrite(e_pin, LOW);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, HIGH);
break;
case p:
digitalWrite(a_pin, LOW);
digitalWrite(b_pin, LOW);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, LOW);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, LOW);
break;
case q:
digitalWrite(a_pin, LOW);
digitalWrite(b_pin, LOW);
digitalWrite(c_pin, LOW);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, LOW);
break;
case r:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, LOW);
digitalWrite(f_pin, HIGH);
digitalWrite(g_pin, LOW);
break;
case s:
digitalWrite(a_pin, LOW);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, LOW);
digitalWrite(d_pin, LOW);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, LOW);
break;
case t:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, LOW);
digitalWrite(e_pin, LOW);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, LOW);
break;
case u:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, LOW);
digitalWrite(c_pin, LOW);
digitalWrite(d_pin, LOW);
digitalWrite(e_pin, LOW);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, HIGH);
break;
case v:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, HIGH);
digitalWrite(g_pin, LOW);
Serial.println("V");
break;
case w:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, HIGH);
digitalWrite(g_pin, LOW);
Serial.println("W");
break;
case x:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, HIGH);
digitalWrite(g_pin, LOW);
Serial.println("X");
break;
case y:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, LOW);
digitalWrite(c_pin, LOW);
digitalWrite(d_pin, LOW);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, LOW);
digitalWrite(g_pin, LOW);
break;
case z:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, HIGH);
digitalWrite(g_pin, LOW);
Serial.println("Z");
break;
default:
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, HIGH);
digitalWrite(g_pin, HIGH);
break;
}
// flash letter for 1.5 seconds then return to off
delay(1500);
digitalWrite(a_pin, HIGH);
digitalWrite(b_pin, HIGH);
digitalWrite(c_pin, HIGH);
digitalWrite(d_pin, HIGH);
digitalWrite(e_pin, HIGH);
digitalWrite(f_pin, HIGH);
digitalWrite(g_pin, HIGH);
// reset for next sequence
idx = 0;
input = 0;
//delay(500);
Serial.println("Enter next sequence:");
} else { // if sequence is not finished
// take two readings of the input button 100 ms apart
read1 = analogRead(button);
delay(100);
read2 = analogRead(button);
// if readings are nonzero and the same, then the button was held down
// if readings are not the same, and the button has not been held, then it must have been pressed
if (read1 > 0) {
if (read1 == read2) {
val = 2; // 2 for dash
} else if (val != 2) { // ensures that the button was not held down in the previous iteration before determining the button was just pressed
val = 1; // 1 for dot
}
} else {
if (val != 0) { // update sequence with previous iteration's value
if (idx < 4) { // update sequence with up to 4 values per character
if (val == 1) {
Serial.print(".");
} else {
Serial.print("-");
}
input = 10*input + val; // add value into last digit of sequence
idx = idx + 1;
}
}
val = 0; // reset value for next reading
}
}
}
I am definitely interested in modifying this project to make it more advanced. Some avenues to do this may include going from a pushbutton and 7-segment display to using an LCD touch screen that could be tapped with Morse code sequences, and then the letters are displayed immediately on the same screen. Some other interesting functionality that could be incorporated might be translating English to Morse code and then displaying the translation using a blinking LED. I also would like to explore a system that can decode entire words or even sentences that are delivered in Morse code.
To summarize, in this project I explored how to convert physical button presses in the form of Morse code sequences into letters from the English alphabet. I would recommend trying what I’ve done in this project if you have an interest in embedded systems, microcontrollers, or just circuit design in general. This project was a great way for me to refine my electrical engineering skills and to indirectly memorize a little bit of Morse code!
References:
[1] - https://en.wikipedia.org/wiki/Morse_code
[3] - https://circuitdigest.com/microcontroller-projects/interfacing-seven-segment-display-with-Arduino
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.
Visit TechForum