For the project, we will need:

  • A microcontroller with an analog input. In this case, we will use the NodeMCU ESP8266.
  • A joystick module. It has 3 outputs, but we will only use the Y-axis output.
  • The clip of a Pilot pen or anything else that can extend the joystick lever.
  • A Buzzer

The idea is to attach the joystick lever to the clip or any other suitable item.

The most important part of the connection is to use the correct pin of the NodeMCU, which is A0.

The first step that was taken is to detect the dots and dashes based on the duration of the lever movements.

Once we figure that out, we gotta make it so that when we get that info, it gives us the correct character.

#include <Arduino.h>
//Pins
const int joystickPin = A0;
const int buzzerPin = 5;

// Dot and dashes
const int dotDuration = 100;
const int dashDuration = dotDuration * 3;

//State variables
bool isKeyPressed = false;
unsigned long pressStartTime = 0;
String currentMorseCode = "";

// Morse code table
const char* morseAlphabet[26] = {
  ".-",   // A
  "-...", // B
  "-.-.", // C
  "-..",  // D
  ".",    // E
  "..-.", // F
  "--.",  // G
  "....", // H
  "..",   // I
  ".---", // J
  "-.-",  // K
  ".-..", // L
  "--",   // M
  "-.",   // N
  "---",  // O
  ".--.", // P
  "--.-", // Q
  ".-.",  // R
  "...",  // S
  "-",    // T
  "..-",  // U
  "...-", // V
  ".--",  // W
  "-..-", // X
  "-.--", // Y
  "--.."  // Z
};
//Function
char decodeMorseCharacter(const String& morseCode);

void setup() {
  Serial.begin(9600);
  pinMode(buzzerPin, OUTPUT);
}

void loop() {
  int joystickYValue = analogRead(joystickPin);

  //Check
 //535 is the value I got when it is not 'press'
  if (joystickYValue < 535) { 
    digitalWrite(5, HIGH);
    //Start counting
    if (!isKeyPressed) {
      pressStartTime = millis();
      isKeyPressed = true;
    }
  } 
  else {
    digitalWrite(5, LOW);
    // Dot or dash
    if (isKeyPressed) {
      unsigned long pressDuration = millis() - pressStartTime;
      if (pressDuration < dotDuration) {
        currentMorseCode += ".";
      }
      else {
        currentMorseCode += "-";
      }

      isKeyPressed = false;
    }
  }

  // Verifying if it's enough to determine the output.
  if (currentMorseCode != "" && millis() - pressStartTime > dotDuration * 7) {
    char decodedCharacter = decodeMorseCharacter(currentMorseCode);
    Serial.print(decodedCharacter);

    currentMorseCode = "";
  }
}

char decodeMorseCharacter(const String& morseCode) {
  for (int i = 0; i < 26; i++) {
    if (morseCode.equals(morseAlphabet[i])) {
      return 'A' + i;
    }
  }

  return '?'; //Unknown character
}

One possible expansion is to create a game where you have to guess the proposed word, and the script would simply check the result.