Morse Code Translator

My last project in this course, is a Morse Code Translator that I assembled with an Arduino Uno coupled with LCD display. This project gives the user opportunity to enter words in Morse code through a button and to instantly see the converted letters on a screen. I selected this concept because I have always been interested in how the communication systems developed, especially the Morse code as one of the first kinds of digital signaling. It also was an excellent way of integrating timing-based interaction, output verifications, and troubleshooting of real-life situations with the help of Arduino framework. This project is also very code heavy and requires minimal circuitry which is a good thing for me as I believe that is one of my biggest strengths.
This project allowed me to put to practice all that I learned this semester: circuits and components such as buzzers and buttons, as well as how to write well-structured Arduino programs. It is also practical and informative and makes something historical into a project that can be extended digitally.
Downloads
Supplies

IDEATE



My Project Idea: Morse Code Translator with Arduino
Why I chose it:
I wanted to build a project that uses real input (like a button press) and translates it into readable output (on an LCD). Morse code was the perfect system because it's based on short and long button presses — and it’s a great challenge that combines timing logic, LCD output, and code structure. I was also inspired by how early telegraphs worked, and I thought it would be fun to recreate something similar using modern tools.
Components I planned to use:
Component & Purpose
Arduino Uno Main - microcontroller
Pushbutton - Input Morse code (short/long presses)
LCD I2C Display (16x2) - Display translated letters
Breadboard + Jumper Wires - Building the circuit
Resistors (10kΩ) - For button pull-down
USB Cable - To power and upload code to Arduino
Buzzer - To make audio feedback on button press
Worklog Entry (for Step 1):
- I reviewed past Arduino projects we did (like LED blinkers, buzzer feedback, sensors).
- I decided I wanted something that uses timing and message display.
- I explored ideas like password systems, reaction timers, and Morse code.
- I picked Morse code because it's a challenge, it’s creative, and it allows me to use both analog timing logic and digital output.
- I listed components I’ll need and confirmed I have them available.
RESEARCH


Programming of the Morse code translator would require me to research how to work with buttons, timing manage and LCD display in Arduino.
The main problem was how to code a dot and a dash by means of a single button. I found out that I could count the duration of the button press by comparing it with millis(): when it took less than 200ms, I could construct dots, and when more than 200ms, dashes. This interpreting of Morse code depends on this timing based input.
I also read about the means of identifying spaces between letters and words by timing the time of releasing the button. As an individual example, in case of the pause duration more than 1.5s the program exits letter and converts the stored dot/dash sequence to a letter. There is a space between words as the pause is longer (e.g. 5 seconds).
I learnt to operate an I2C LCD display with Arduino in order to present the decoded text. Working with LiquidCrystal_I2C library helped me to wire easier and print characters and easily control the cursor location.
- I gained knowledge in organizing the code as follows:
- Saving Morse entries in coded form: as strings of dots and dashes.
- Developing procedures to decode to letters in Morse strings.
- Controlling editing of cursor and blacking screen.
- Monitoring both button presses and releases, using state variables, without code blocking.
Some of these ideas appeared in other Arduino tutorials, such as on debouncing the button, non-blocking time-based in milliseconds () and algorithm to translate Morse Code to text. A combination of them allowed me to create clean and efficient code that would be good when applied to real-time Morse code input.
BUILD & CODE


The Build:
Physical arrangement contains:
- Arduino Uno (mind of the project)
- A single button that is used to enter Morse code (by short or long presses)
- A single clear button which cleans the LCD screen
- Output- 16x2 I2C LCD display to output translated text
- Clean and neat connections are done by using breadboard, wires and resistors
Its parts have been hooked up easily:
- The Morse entry button is connected to pin 8 digital.
- The clear button gets connected to pin 9 digital
- The A4 and A5 are utilized to I2C with the LCD
The Code
The most difficult and exciting was the code. I organized it into a number of functions and they each had a specific feature:
void setup()
- Initial Censor LCD and set up modes of the pins.
- Starts serial transmission (to debug it).
- Positioning is the first cursor on the LCD.
- Initialize both buttons as input
void loop()
- The loop is repeated and takes care of everything that goes on in the real-time. It:
- Reads both the Morse on and clear buttons.
- Pressed to start a timer by pressing the Morse button.
- Computes the length of a press to know whether it is a dot or a dash.
- Inserts the Morse code in a string buffer (buff).
- Identifies gaps to determine the time to convert the buffer into a letter.
- Returns the buffer to be translated and showing the character.
- Can add space in case the pause lasts so long to convey word break.
- Clears the screen when reset button is pressed.
Function Seperation:
void updateState()
- Invoked upon a depression of the morse button.
- Records the duration that the button was pressed.
- Short press tacked on a -.- (dot, dot, dot).
- Adds a -, in case of long presses (dash).
- To accurately time things non-blocking, used millis().
String retBuf()
- Transforms the Morse buffer to the readable letter morseToChar().
- Returns the resulting character as an ascii string.
String morseToChar(String& morse)
- Scans an already defined Morse array (letters[]) to find a match.
- Returns the the A-Z character corresponding to it should it be found.
- Makes a call to the printToLCD and prints the result.
- Returns "ERROR" in case the MorseCode is not valid.
void clearBuf()
- Resets the Morse buffer string so a new letter can be entered.
char void printToLCD(char c)
- Position a character at the character position of a current LCD cursor.
- Chooses right after characters.
- Resets and clears the screen and cursor in case of a filled up screen.
void clearScreen()
- Clears the LCD and restores the cursor at the top-left.
What I Learned In Coding:
The project made me learn:
- About how to use millis() to track input real-time as opposed to delay()
- The programming of how to read the press of the buttons and accumulation of the hold time
- The next question is how to employ arrays to map from inputs to outputs (Morse to English)?
- I2c and cursor control on how to manage an LCD screen
- The methods of creating and cleaning up the modular code by breaking functions into tasks
REFINE

Once having created the basic build and code, I was able to find some areas to optimize that boosted the consistency and overall usability of the Morse code translator in a major way.
Code Optimizations
Fixed Timing Bug Unsigned long
Initially I had int variables to hold the values of time of millis() which caused results to be found incorrect with value overflowing. These bugs were fixed by changing all time variables to unsigned long and the results were much better with button presses being detected much more accurately.
Better Dot/Dash Decoding Depth
Initially, the code would have difficulty differentiating a short and a long press. By experiment I was able to optimize its timing threshold a bit ( e.g. 300ms ) which was a significant enhancement in the accurateness with which it interpreted dots and dashes.
Functions in Modular Code
I broke down repeated code into specific functions such as morseToChar () and clearLCD () so as to make the program more readable and easy to maintain and modify. It also cleared up the loop() and made it less cluttered.
Physical Improvements
New Clear Button
The second button was included to reset the LCD, and due to it, users could easily clear their typing and start over without restarting Arduino.
Neat Wiring Diagram
I rewired the breadboard with color-coded jumper wire. This turned the circuit more presentable, simpler to debug and document as well as demo.