Morse Master

by Arnov Sharma in Circuits > Raspberry Pi

213 Views, 1 Favorites, 0 Comments

Morse Master

MORSE CODE TRANSLATOR with RASPBERRY PI PICO W
28.gif
32.gif
31.gif
IMG_4498.JPG

Greetings everyone, and welcome back.

Morse code, a timeless art form, continues to be revered for its ingenuity and history. Imagine developing a device that bridges the gap between traditional communication methods and current technologies.

Meet Morse Master, a Morse Code translator that can be controlled with a sleek web app or a tactile push button. The Morse Master goes beyond utility by combining interactive LED displays, Wi-Fi connectivity, and manual input choices in a single attractive design.

This device is powered by the Raspberry Pi PICO W Dev Board, allowing us to connect it to the internet. We created a webapp that allows users to enter any message, which is subsequently translated and outputted via the four 5mm LEDs linked to the Raspberry Pi pico W.

Furthermore, we have included a mechanical switch on this device that allows us to manually enter the morse code.

We designed the 3D model of Morse master in Fusion 360, borrowing inspiration from real Morse Key devices used to type Morse code. The idea here was to create a device that could be easily 3D printed and assembled.

Using one of our previously designed Raspberry PI PICO Expansion board Circuit from a previous project, we used the custom board to create a simple Raspberry Pi PICO W and 5mm LED setup that would be used to display Morse code via RED LEDs.

This Instructable is about the build process of this Morse Master device, so let's get started with the build.

Supplies

These are the materials used in this build:

  1. Raspberry Pi PICO W
  2. Custom PICO Expansion Board PCB
  3. Header Pins
  4. 5mm RED LED
  5. 3D Printed Parts
  6. M2 Screws
  7. M3 Bolt
  8. DC Barrel Jack

MORSE CODE—History and Facts

bcd2d64b-fdb6-4e3b-85b1-da3e6cc64713.png
Morse_comparison.jpg
telegraph-transmitter-Morse-Code.jpg
11mOO6Lmh9ASEp_BRZvOJKQ.jpg

The Morse code was created in the early 1830s by Samuel Morse, an American artist and inventor, and his collaborator Alfred Vail. It was initially developed as a way to send communications over large distances using the telegraph, a revolutionary communication instrument at the time.

The first version, known as "American Morse Code," employed dots and dashes to represent letters, numerals, and punctuation.

In 1851, a more standardized form known as the "International Morse Code" was established to incorporate non-English characters and diacritical markings, making it appropriate for global use. This form became the universal norm, and it is still acknowledged today.

The Morse key, also referred to as a telegraph key, was a device for manually transmitting Morse code signals via telegraph lines. It consisted of a lever that could be depressed to complete an electrical circuit, letting current to flow and provide a signal. Operators would press the key to create short signals (dots) and hold it down for long signals (dashes). These messages were sent as electrical pulses across telegraph cables to a receiver, where they were decoded into letters, numbers, and symbols.

The Morse key required aptitude and precision since operators had to keep consistent timing for dots, dashes, and gaps between characters and sentences. Experienced telegraphers may convey messages at astounding rates, generally measured in words per minute. The device was widely employed in communication systems, particularly in railways, maritime operations, and military settings, where it played an important role in transmitting critical information rapidly and reliably. Over time, the Morse key came to represent early telecommunications and the era's innovation.

DESIGN

untitled.180.png
34.gif
Screenshot 2025-04-11 160956.png
untitled.182.png
untitled.181.png
08.gif
Screenshot 2025-04-11 160620.png

We modeled our design after the Morse key, creating an enclosure that holds the Pico W circuit within; this comprises of a main body and a lid, to which we have attached a lever holder.

We included a lever alongside the Lever holder, and on one side of the lever, we included a knob similar to the one found on a Morse key, which allows the user to correctly grip the lever and operate the device.

A mechanical Blue Switch has been added to the Lid part, and the Lever is positioned above the Mechanical Switch; when the lever is pressed down, the switch toggles, and a switch press is registered by the PICO W.

To hold the mechanical switch in place, we built a square opening to the lid; the mechanical switch slides into this slot and is kept in place with two locks on its body. These two locks enabled us to securely hold the switch in place on the lid section.

The circuit is mounted inside the main body and held in place with four M2 screws, each with its own screw boss.

Regarding the design of the lid section and main body assembly, we have added four screw holes in each corner, as well as four screw bosses next to each screw hole. We'll be using four M2 screws here as well.

To secure the lever to the lever holder, we just use a Long 30mm M3 Bolt.

Our design follows the design language of prior Morse Keys that have been used in the past.

We printed the main body with transparent PLA to diffuse the red color glow. The lid part was printed with brown PLA, the lever and lever holder were printed with grey PLA, and the knob was printed with black PLA.

PCBWAY SERVICE

F6TSB1ZLBNNZUIX.jpg

Let's have a look at the Expansion Board PCB which was designed from scratch and then sent to PCBWAY for samples.

Expansion board order was placed for White Soldermask and Black silkscreen.

After placing the order, the PCBs were received within a week, and the PCB quality was pretty great.

Their commitment to quality and customer satisfaction has been unwavering, leading to significant growth and expansion.

Also, PCBWAY is organizing a PCB badge-making competition to mark their 11th anniversary, inviting designers and makers to showcase their creativity by designing badges that celebrate the company's legacy and envision a bold future. Participants must incorporate the elements "PCBWay" and the number "11" in their designs and can use PCB, PCB+SMT/THT, or PCB+3D printing techniques. Submissions can be posted in the comments, emailed, or shared on social media with the hashtag #PCBWay11BadgeContest.

Prizes include cash, PCBway coupons, and free prototyping services for all qualifying entries.

You guys can check out PCBWAY if you want great PCB service at an affordable rate.

RASPBERRY PI PICO W SETUP

Raspberry-Pi-Pico-W_Raspberry-Pi-Boards-amp-Official-Accessories_51556_1-1.png
IMG_4448.JPG
Screenshot 2025-04-12 013609.png
IMG_4449.JPG

The Raspberry Pi Pico W, a compact and versatile microcontroller that adds wireless connectivity to the already popular Pico series, will be used as the project's brain. It is powered by the Raspberry Pi's RP2040 chip and has a dual-core Arm Cortex-M0+ processor that can run at up to 133 MHz, making it both efficient and powerful for a variety of applications. This microcontroller, which includes built-in 2.4 GHz Wi-Fi, was ideal for our Morse Code Translator devices project, that utilizes a WEB APP.

We coupled the PICO W with our previously created PICO Expansion board, which breaks out all of PICO's GPIO pins and adds extra pins that may be used to pair sensors and other electronic devices with PICO. In our case, we added four 5mm RED LEDs to PICO W's GPIO pins.

The anode of the LEDs is linked to GPIO0, GPIO15, GPIO16, and GPIO17, while the cathode of all LEDs is connected in parallel and then coupled with the GND of PICO W.

BOARD ASSEMBLY

02.gif
03.gif
04.gif
05.gif
06.gif
07.gif
  1. The board assembly process begins with the installation of two CON20 Female header pin connectors in place of PICO W. We will use these header pin connectors in place of PICO.
  2. Next, we place four 5mm LEDs near each corner of the expansion board.
  3. By flipping the board over, we use a soldering iron to solder each through-hole pad, securing all THT components in place.
  4. Using pliers, we align the excess legs of a 5mm LED and attach them to the PICO GPIO pins. We built connections and linked all of the LED anode pins to GPIO0, GPIO15, GPIO16, and GPIO17. The cathode of all LEDs is linked to GND.
  5. After finishing the soldering, we installed PICO W over the CON20 header pin connector.

TEST SKETCH

09.gif
10.gif

For testing the LEDs, we uploaded a Sample Chaser sketch to our PICO W, which turns ON and OFF each LED in a Chaser Sequence in a Loop.

// Define the GPIO pins for the LEDs
const int ledPins[] = {0, 15, 16, 17};
const int numLeds = sizeof(ledPins) / sizeof(ledPins[0]);
void setup() {
// Initialize each LED pin as an output
for (int i = 0; i < numLeds; i++) {
pinMode(ledPins[i], OUTPUT);
digitalWrite(ledPins[i], LOW); // Make sure LEDs are off initially
}
}
void loop() {
// Iterate through each LED, turning it ON and then OFF in sequence
for (int i = 0; i < numLeds; i++) {
digitalWrite(ledPins[i], HIGH); // Turn ON the current LED
delay(200); // Wait for 200 milliseconds
digitalWrite(ledPins[i], LOW); // Turn OFF the current LED
}
}

After making sure that our Setup is working electrically, lets move to the assembly process.

BUTTON ASSEMBLY

11.gif
12.gif
  1. We place the mechanical switch in its slot on the lid section, pushing it downwards to secure it in place.
  2. Next, we solder wires from GPIO1 to one terminal of the switch, while the other terminal is linked to the GND terminal.

DC JACK ASSEMBLY

13.gif
14.gif

DC barrel The jack is then inserted in its mounting hole on one face of the main body and fastened in place with its nut.

BASE BODY & LID ASSEMBLY

15.gif
16.gif
17.gif
18.gif
19.gif
  1. The PICO W Circuit is then installed within the Main body, over four screw bosses, and tightened with four M2 screws.
  2. Next, we connected two wires to the PICO's VBUS and GND terminals, then connected the VBUS wire to the DC jack's VCC and the GND wire to the DC jack's ground.
  3. We then install the lever holder on top of the lid by aligning the mounting holes and secure both of them with two m2 screws.
  4. The Lid Part is then installed from the top side of the Main Body, and four m2 screws are used to attach both of them together.

LEVER ASSEMBLY

20.gif

For the Lever Assembly, we placed the 3D Printed Knob over the lever and secured it with an M2 screw.

FINAL ASSEMBLY

21.gif
22.gif
23.gif
  1. For the final assembly, the lever is attached to the lever-holding part, and a Long M3 Bolt is utilized to connect them both.
  2. We tighten the M3 bolt with a secure driver, and the assembly is now complete.

MAIN CODE

Here's the code used in this build and it's a simple one.

#include <WiFi.h>
#include <WebServer.h>
// Replace with your Wi-Fi credentials
const char* ssid = "YOUR SSID";
const char* password = "YOUR PASS";
// Set up GPIO pins
const int LED_PINS[] = {0, 15, 16, 17}; // Array of GPIO pins for LEDs
const int BUTTON_PIN = 1; // Push button for manual input
// Morse code timings
const int dotDuration = 200; // Duration of a dot in milliseconds
const int dashDuration = 600; // Duration of a dash in milliseconds
const int pauseDuration = 200; // Pause between symbols
const int wordPause = 800; // Pause between words
const int buttonThreshold = 500; // Threshold for differentiating dot/dash
// Web server instance
WebServer server(80);
String morseMessage = "";
// Morse code dictionary (simplified)
String translateToMorse(char c) {
switch (toupper(c)) {
case 'A': return ".-";
case 'B': return "-...";
case 'C': return "-.-.";
case 'D': return "-..";
case 'E': return ".";
case 'F': return "..-.";
case 'G': return "--.";
case 'H': return "....";
case 'I': return "..";
case 'J': return ".---";
case 'K': return "-.-";
case 'L': return ".-..";
case 'M': return "--";
case 'N': return "-.";
case 'O': return "---";
case 'P': return ".--.";
case 'Q': return "--.-";
case 'R': return ".-.";
case 'S': return "...";
case 'T': return "-";
case 'U': return "..-";
case 'V': return "...-";
case 'W': return ".--";
case 'X': return "-..-";
case 'Y': return "-.--";
case 'Z': return "--..";
case ' ': return " ";
default: return ""; // Ignore unsupported characters
}
}
// Function to initialize LEDs
void initializeLEDs() {
for (int i = 0; i < 4; i++) {
pinMode(LED_PINS[i], OUTPUT);
digitalWrite(LED_PINS[i], HIGH); // Ensure LEDs are ON initially
}
}
// Function to set the state of all LEDs
void setLEDState(bool state) {
for (int i = 0; i < 4; i++) {
digitalWrite(LED_PINS[i], state ? HIGH : LOW); // Set LEDs ON or OFF
}
}
// Function to blink LEDs for Morse code
void blinkMorse(String morseCode) {
for (int i = 0; i < morseCode.length(); i++) {
char c = morseCode[i];
if (c == '.') {
setLEDState(false); // Turn LEDs OFF
delay(dotDuration);
setLEDState(true); // Turn LEDs ON
delay(pauseDuration);
} else if (c == '-') {
setLEDState(false); // Turn LEDs OFF
delay(dashDuration);
setLEDState(true); // Turn LEDs ON
delay(pauseDuration);
} else if (c == ' ') {
delay(wordPause);
}
}
}
// Updated Function to handle button presses
void manualMorseInput() {
static unsigned long pressStartTime = 0;
static bool buttonPressed = false;
if (digitalRead(BUTTON_PIN) == LOW) { // Button is pressed
if (!buttonPressed) { // Button was not already pressed
pressStartTime = millis();
buttonPressed = true;
}
setLEDState(false); // Keep LEDs off while the button is pressed
} else { // Button is released
if (buttonPressed) { // Only process if button was previously pressed
unsigned long pressDuration = millis() - pressStartTime;
if (pressDuration < buttonThreshold) {
blinkMorse("."); // Short press = dot
} else {
blinkMorse("-"); // Long press = dash
}
buttonPressed = false;
}
setLEDState(true); // Turn LEDs back on when button is not pressed
}
}
// Convert text to Morse and blink it
void displayMorseCode(String text) {
for (int i = 0; i < text.length(); i++) {
String morseCode = translateToMorse(text[i]);
blinkMorse(morseCode);
delay(pauseDuration); // Pause between letters
}
}
// Handle root page
void handleRoot() {
server.send(200, "text/html",
"<!DOCTYPE html>"
"<html>"
// (HTML content omitted for brevity)
"</html>");
}
// Handle message submission
void handleSend() {
if (server.hasArg("message")) {
morseMessage = server.arg("message");
server.send(200, "text/plain", "Message received: " + morseMessage);
displayMorseCode(morseMessage);
} else {
server.send(400, "text/plain", "Invalid Request");
}
}
void setup() {
Serial.begin(115200);
initializeLEDs(); // Initialize multi-LED setup
pinMode(BUTTON_PIN, INPUT_PULLUP); // Configure the button as input
// Connect to Wi-Fi
WiFi.begin(ssid, password);
Serial.println("Connecting to Wi-Fi...");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("\nConnected to Wi-Fi!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
// Start the web server
server.on("/", handleRoot);
server.on("/send", handleSend);
server.begin();
Serial.println("Web server started!");
}
void loop() {
server.handleClient(); // Handle web server requests
manualMorseInput(); // Monitor button presses for Morse input
}

We first added the required WiFi.h and WebServer.h library which enable the Raspberry Pi Pico W to connect to a Wi-Fi network and serve a webpage for remote control of the device.

const char* ssid = "UR SSID";
const char* password = "UR PASS";

Replace these with your Wi-Fi network's SSID and password. This allows the device to connect to your network and function as a web server.

Hardware Setup

const int LED_PINS[] = {0, 15, 16, 17};
const int BUTTON_PIN = 1;

GPIO pins connected to four LEDs. The LEDs will blink together to represent Morse code signals. GPIO pin connected to a push button, which allows users to manually input Morse code.

const int dotDuration = 200;
const int dashDuration = 600;
const int pauseDuration = 200;
const int wordPause = 800;
const int buttonThreshold = 500;

These constants define the timings for Morse code signals-

A dot is shorter than a dash and Pauses between symbols, words, and button press detection are precisely timed.

Morse Code Translator

String translateToMorse(char c) {
switch (toupper(c)) {
case 'A': return ".-";
case 'B': return "-...";
// Additional cases for other characters...
default: return "";
}
}

Converts a character into its Morse code representation (e.g., "A" becomes ".-")

Handles letters and spaces; unsupported characters are ignored

LED Control

void initializeLEDs() {
for (int i = 0; i < 4; i++) {
pinMode(LED_PINS[i], OUTPUT);
digitalWrite(LED_PINS[i], HIGH);
}
}

void setLEDState(bool state) {
for (int i = 0; i < 4; i++) {
digitalWrite(LED_PINS[i], state ? HIGH : LOW);
}
}

initializeLEDs(): Sets up the LEDs as output and ensures they are initially ON.

setLEDState(bool state): Controls all LEDs at once, turning them ON or OFF.

Manual Button Input

void manualMorseInput() {
static unsigned long pressStartTime = 0;
static bool buttonPressed = false;

if (digitalRead(BUTTON_PIN) == LOW) {
if (!buttonPressed) {
pressStartTime = millis();
buttonPressed = true;
}
setLEDState(false);
} else {
if (buttonPressed) {
unsigned long pressDuration = millis() - pressStartTime;
if (pressDuration < buttonThreshold) {
blinkMorse(".");
} else {
blinkMorse("-");
}
buttonPressed = false;
}
setLEDState(true);
}
}

This Detects button presses and determines whether the user is inputting a dot or a dash based on how long the button is held.

The LEDs provide immediate visual feedback during and after a button press.

Blink Morse Code

void blinkMorse(String morseCode) {
for (int i = 0; i < morseCode.length(); i++) {
char c = morseCode[i];
if (c == '.') {
setLEDState(false);
delay(dotDuration);
setLEDState(true);
delay(pauseDuration);
} else if (c == '-') {
setLEDState(false);
delay(dashDuration);
setLEDState(true);
delay(pauseDuration);
} else if (c == ' ') {
delay(wordPause);
}
}
}

This Controls the LEDs to blink according to the provided Morse code sequence.

Dots, dashes, and pauses are visually represented using precise durations.

Remote Control via Web Server

void handleRoot() {
server.send(200, "text/html",
"<html><body>"
"<h1>Morse Code Translator</h1>"
"<form action=\"/send\" method=\"POST\">"
"<input type=\"text\" name=\"message\" placeholder=\"Enter message\">"
"<button type=\"submit\">Send</button>"
"</form>"
"</body></html>");
}

void handleSend() {
if (server.hasArg("message")) {
morseMessage = server.arg("message");
server.send(200, "text/plain", "Message received: " + morseMessage);
displayMorseCode(morseMessage);
} else {
server.send(400, "text/plain", "Invalid Request");
}
}

handleRoot(): Displays a simple web interface where users can submit text messages for translation.

handleSend(): Processes the submitted message, translates it to Morse code, and blinks the LEDs.

Display Morse Code

void displayMorseCode(String text) {
for (int i = 0; i < text.length(); i++) {
String morseCode = translateToMorse(text[i]);
blinkMorse(morseCode);
delay(pauseDuration);
}
}

This Converts a full text message into Morse code and uses LEDs to display it.

Setup Function

void setup() {
Serial.begin(115200);
initializeLEDs();
pinMode(BUTTON_PIN, INPUT_PULLUP);

WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
}

server.on("/", handleRoot);
server.on("/send", handleSend);
server.begin();
}

This Initializes LEDs, button, Wi-Fi, and the web server.

Main Loop

void loop() {
server.handleClient();
manualMorseInput();
}

This Continuously processes web server requests and monitors button presses for manual Morse input.

After uploading the sketch, the IP address for the Web app is obtained via Serial Monitor.

POWER SOURCE

24.gif

For the power source, we will use a 5V power bank, and to connect the power bank's 5V to our device, we will use a modified USB cable. One end of the cable will have a regular USB port, and the other end will have a barrel jack connector with 5V of USB linked with the barrel jack's 5V and GND to ground.

RESULT

MORSE CODE TRANSLATOR with RASPBERRY PI PICO W
25.gif
26.gif
33.gif

The ultimate result of this Build is a Functional Morse Code Translator device that can be operated via a web app or by using the onboard Key Mechanism to input Morse code, which will be displayed via the LED.

Using this device, one can access the webpage and translate whatever message he wants by entering the message into the Enter Message Bar and then clicking the Submit button, which will start the translation process. The LED blinks in response to each letter in Morse code.

MORSE CODE TRANSLATION

28.gif
29.gif
30.gif
32.gif

Let's have a look at some of the alphabets we attempted inputting into the website. We'll start with the letter A, which is represented by a dot followed by a dash. In our case, a short Blink (dot) is immediately followed by a longer Blink (dash).

Next, we tried Letter B, which is represented by a dash followed by three dots. In our example, it begins with a longer Blink (dash), followed by three short Blinks (dots) in rapid succession.

We then entered Letter C, which consists of a dash, a dot, another dash, and a final dot. In our case, the sequence would be a long blink (dash), a short blink (dot), another long blink (dash), and finally a short blink (dot).

After mastering the code, we were able to pronounce HI in Morse code, which consists of H (four rapid blinks) followed by I (two quick blinks), with tiny intervals between each blink and a somewhat longer break between the two letters.

This device allows you to translate sentences, characters, and alphabets into Morse code by accessing the WEB PAGE or manually entering the Morse code using the onboard Morse key configuration.

Please let me know if you require any additional assistance; all the documents, files, and code are included in the article.

In addition, we appreciate PCBWAY's support of this project. Visit them for a variety of PCB-related services, such as stencil and PCB assembly services, as well as 3D printing services

Thanks for reaching this far, and I will be back with a new project pretty soon.

Peace.