Skip to content

Week 4: Embedded Programming

hero shot

*Morse code input decoder.

Group Assignment

Please find the complete group assignment here.

Tinkercad

Arduino

Arduino IDE

things to know: setup() and loop(), void

Arduino UNO

datasheet

Onik giving us LCDs with no potentiometers, us asking AIs and convincing it thatwe don’t need a potentiometer.

Individual Assignment

Years ago, before I’d even know how to write code, I came across the binary tree representation of the Morse Code. It looked a bit complicated, but once I knew how to traverse through tree nodes, the tree representation was more than logical.

The Morse Code is comprised of dots and dashes, whereas the parent nodes are prioritezed to have the most frequently occuring letters. Naturally we start with E and T. To get a letter/characters we traverse down the tree as follows: dots to the left, dashes to the right.

*Prompt4.1

To get my name I would go down all the way to the right, to the 4th level:

H → •••• // left > left > left > left
R → •-• // left > right > left
A → •– // left > right
C → -•-• // right > left > right > left
H → •••• // left > left > left > left

After much thinking, an interesting, yet useful project with simple I/O devices was a Morse Code decoder.

The make a Morse Code decoder you need:

1x Arduino UNO
1x LCD
1x LED
2x 220Ω resistors
1x 10kΩ resistor
1x 100kΩ potentioemeter
1x 0.03Ω button
?x male-to-male jumper wires
C++

#include <LiquidCrystal.h>

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
const int ledPin = 8;
const int buttonPin = 9;

int inputCol = 7;   // Start after "Input: "
int outputCol = 8;  // Start after "Output: "
String outputText = "";  // Store all decoded letters


LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

unsigned long dotDuration = 0;
unsigned long dashDuration;
unsigned long nextCharDuration;
unsigned long spaceDuration;

unsigned long startTime;
unsigned long pressTime;
unsigned long releaseTime;

String currentMorse = "";

// Morse table
struct MorseMap {
  const char* code;
  char letter;
};

MorseMap morseTable[] = {
  {".-", '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'}
};

char decodeMorse(String code) {
  for (int i = 0; i < 26; i++) {
    if (code == morseTable[i].code) {
      return morseTable[i].letter;
    }
  }
  return '?';
}

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);

  lcd.begin(16, 2);
  lcd.print("Press 3 dots.");

  unsigned long totalDuration = 0;

  // --- Calibration ---
  for (int i = 0; i < 3; i++) {

    while (digitalRead(buttonPin) == LOW);
    digitalWrite(ledPin, HIGH);
    startTime = millis();

    while (digitalRead(buttonPin) == HIGH);
    digitalWrite(ledPin, LOW);

    pressTime = millis() - startTime;
    totalDuration += pressTime;
  }

  dotDuration = totalDuration / 3;
  dashDuration = dotDuration * 3;
  nextCharDuration = dotDuration * 3;
  spaceDuration = dotDuration * 7;

  lcd.clear();
  lcd.print("Input:");
  lcd.setCursor(0, 1);
  lcd.print("Output:");
}

void loop() {

  if (digitalRead(buttonPin) == HIGH) {
    digitalWrite(ledPin, HIGH);
    startTime = millis();

    while (digitalRead(buttonPin) == HIGH);

    digitalWrite(ledPin, LOW);
    pressTime = millis() - startTime;

    // Add dot or dash to Morse input
    lcd.setCursor(inputCol, 0);
    if (pressTime < dashDuration) {
        lcd.print(".");
        currentMorse += ".";
    } else {
        lcd.print("-");
        currentMorse += "-";
    }
    inputCol++;  // Move cursor forward
    releaseTime = millis();
  }

  // Detect gaps
  if (currentMorse.length() > 0) {
      unsigned long gapTime = millis() - releaseTime;

    // End of character
    if (gapTime > nextCharDuration && gapTime < spaceDuration) {
        char decoded = decodeMorse(currentMorse);
        outputText += decoded;

        lcd.setCursor(outputCol, 1);
        lcd.print(decoded);
        outputCol++;  // Move cursor forward

        currentMorse = "";
    }

    // Word space
    if (gapTime >= spaceDuration) {
        outputText += " ";

        lcd.setCursor(outputCol, 1);
        lcd.print(" ");
        outputCol++;

        currentMorse = "";
    }
  }
}

*Prompt4.2

An issue I had faced with this was button debouncing, which later we covered with one of our local instructor, Onik.

Output

Please watch the demo video

Conclusion

This was my first time ever coming close to embedded programming. Years ago, I tried “learning” electronics on my own, but that ending very quickly, as I was bad at Googling sources.

At first, when we began the group assignment, the local lecture was very interesting and digestable, but when it came down to putting the knowledge into action I did not know what to do.

The very last minute, during our regional review, when I got the code working I regained my hope in learning electronics.

Resources

Source files:



Prompts

Prompt4.1 Create a minimalist, monochrome visual of a binary tree representing the Morse Code alphabet. The design should be neat avoiding any color highlights as it will be on a website with light and dark modes. The tree should be organized by starting with E and T at the top. To find a character, the user will traverse the tree: a dot indicates a move to the left child, while a dash indicates a move to the right.

Prompt4.2 Create an Arduino program that merges a button-controlled LED with a 16x2 LCD display [pins 12, 11, 5, 4, 3, 2] to build a Morse code input decoder. The program should begin with a calibration phase in setup() where the user performs three button presses to define and store an average dot duration using millis(). In the main loop(), the code must measure subsequent button presses to control an LED and classify inputs as either a dot or a dash, where based on the initial calibration three dot durations are equal to a dash.