Morse Code Project

I need help! My project is supposed to receive a Morse code input saying "hello" and output a Morse code output saying "howdy". Everything works well until it starts outputting the word "howdy". It only puts out the Morse code for the letter "h" then stops before it starts reading for a new input. What am I doing wrong here?

int tonePin = 2;  
int toneFreq = 1000;
int ledPin = 13;
int buttonPin = 8;
int debounceDelay = 30;

int dotLength = 440;  // dotLength = basic unit of speed in milliseconds
int dashLength = dotLength * 3;
int letterSpace = dotLength * 3;
int wordSpace = dotLength * 9;
float wpm = 1200. / dotLength;

int t1, t2, onTime, gap;
bool newLetter, newWord, letterFound, keyboardText;
int lineLength = 0;
int maxLineLength = 20;

char* letters[] = {
  ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..",    // A-I
  ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.",  // J-R
  "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."          // S-Z
};

char* numbers[] = {
  "-----", ".----", "..---", "...--", "....-",  //0-4
  ".....", "-....", "--...", "---..", "----."   //5-9
};

String dashSeq = "";
char keyLetter, ch;
int i, index;
String morseInput = "";  // Track the incoming Morse code sequence

unsigned long lastInputTime = 0;  // Track last input time for timeout
const unsigned long timeoutDuration = 20000;  // 20 seconds timeout for new word

void setup() {
  delay(500);
  pinMode(ledPin, OUTPUT);
  pinMode(tonePin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  
  Serial.begin(9600);
  Serial.println();
  Serial.println("-------------------------------");
  Serial.println("Morse Code decoder/encoder");
  Serial.print("Speed=");
  Serial.print(wpm);
  Serial.print("wpm, ");
  Serial.print("dot=");
  Serial.print(dotLength);
  Serial.println("ms");

  // Test the LED and tone
  tone(tonePin, toneFreq);
  digitalWrite(ledPin, HIGH);
  delay(2000);
  digitalWrite(ledPin, LOW);
  noTone(tonePin);
  delay(600);

  //flash to demonstrate the expected key speed
  //A
  Serial.print("A .-  ");
  index = 'A' - 65;
  flashSequence(letters[index]);
  delay(wordSpace);
  //B
  Serial.print("B -...  ");
  index = 'B' - 65;
  flashSequence(letters[index]);
  delay(wordSpace);
  //C
  Serial.print("C -.-.  ");
  index = 'C' - 65;
  flashSequence(letters[index]);
  delay(wordSpace);

  Serial.println();
  Serial.println("-------------------------------");
  Serial.println("Click field in Serial Monitor,");
  Serial.println("type text and press Enter, or");
  Serial.println("Key in Morse Code to decode:");
  Serial.println("-------------------------------");

  newLetter = false;  //if false, do NOT check for end of letter gap
  newWord = false;    //if false, do NOT check for end of word gap
  keyboardText = false;
}

void loop() {
  
  // Check if there has been any input for more than 30 seconds
  if (millis() - lastInputTime > timeoutDuration) {
    morseInput = "";  // Clear morseInput after timeout
    Serial.println("\nTimeout! Waiting for new Morse code input...");
  }

  // Wait for Morse code input
  if (digitalRead(buttonPin) == LOW) {  // Button pressed (start of Morse input)
    newLetter = true;
    newWord = true;
    t1 = millis();  // Time at button press
    digitalWrite(ledPin, HIGH);  // Turn on LED and tone
    tone(tonePin, toneFreq);
    delay(debounceDelay);
    while (digitalRead(buttonPin) == LOW) {  // Wait for button release
      delay(debounceDelay);
    }
    delay(debounceDelay);

    t2 = millis();  // Time at button release
    onTime = t2 - t1;  // Length of dot or dash keyed in
    digitalWrite(ledPin, LOW);  // Turn off LED and tone
    noTone(tonePin);

    // Check if dot or dash
    if (onTime <= dotLength * 1.5) {
      dashSeq = dashSeq + ".";  // Dot
    } else {
      dashSeq = dashSeq + "-";  // Dash
    }

    lastInputTime = millis();  // Reset input time
  }

  // Look for a gap >= letterSpace to signal end of letter
  gap = millis() - t2;
  if (newLetter == true && gap >= letterSpace) {

    // Check through letter sequences to find matching dash sequence
    letterFound = false;
    keyLetter = 63;  // char 63 is "?"
    for (i = 0; i <= 25; i++) {
      if (dashSeq == letters[i]) {
        keyLetter = i + 65;
        letterFound = true;
        break;  // Don't keep checking if letter found
      }
    }
    if (letterFound == false) {  // Now check for numbers
      for (i = 0; i <= 10; i++) {
        if (dashSeq == numbers[i]) {
          keyLetter = i + 48;
          letterFound = true;
          break;  // Don't keep checking if number found
        }
      }
    }

    Serial.print(keyLetter);
    if (letterFound == false) {  // Buzz for unknown key sequence
      tone(tonePin, 100, 500);
    }

    // Add the received sequence to morseInput
    morseInput += dashSeq + " ";
    dashSeq = "";  // Reset dashSeq after each letter

    // Check if "HELLO" was received in Morse code
    if (morseInput == ".... . .-.. .-.. --- ") {
      Serial.println("\nDetected 'HELLO' in Morse code. Flashing 'HOWDY'...");
      flashSequence(".... --- .-- -.. -.-- ");  // Morse code for "HOWDY"
    }

    newLetter = false;  // Reset
    lineLength = lineLength + 1;
  }

  // Insert line breaks
  if (lineLength >= maxLineLength) {
    Serial.println();
    lineLength = 0;
  }
}

void flashSequence(char* sequence) {
  int i = 0;
  while (sequence[i] == '.' || sequence[i] == '-') {
    flashDotOrDash(sequence[i]);
    i++;
  }
}

void flashDotOrDash(char dotOrDash) {
  digitalWrite(ledPin, HIGH);
  tone(tonePin, toneFreq);
  if (dotOrDash == '.') {
    delay(dotLength);
  } else {
    delay(dashLength);
  }

  digitalWrite(ledPin, LOW);
  noTone(tonePin);
  delay(dotLength);  // Small gap between flashes
}

The code looks good overall, but I found a few things.

for (i = 0; i < 10; i++) { Should be I < 9

You flash sequence does not accept spaces. I believe they cause a break.You have a delay, that is not good. I suggest going to 115200 on the baud so it does not appears sluggish.

That function makes no sense to me. I can't see how it would work. I think this is bourn out by the fact that it doesn't .

It is the while loop that worries me. Put some debug serial prints in there to see exactly what is going on.

flashSequence has loop, which flash dots and dashes and stops when next input is none of this two.

The sequence contains code for 'h' then space, then code for 'o' ... so this function outputs the 'h' and stops as space is out of its working range.

If you want this function to output the spaces between characters, you have to write there how to do it. (And as you may know, string ends with character \0 which is different from dots, dashes and spaces, so it will end at this character then)

This line lets you have dits, dahs and spaces...

  while (sequence[i] == '.' || sequence[i] == '-' || sequence[i] == ' ') {

[edit]

This should be "7"

dit = 1, dah = 3, intra-element gap = 1, inter-character gap= 3, inter-word gap = 7

Mark the "solution" for this topic.

Other topic with same subject: