Search code examples
arduinoarduino-unoarduino-idemorse-code

Don't get proper output


I code a program for encode and decode a morse code, this code is for decode a morse code.

i use 2 arduino board, 1st Arduino is for encode the text into morse and 2nd is for receiving the morse and decode into text.Connection of 2 arduino board is using IR sensors.

in 1st arduino board This ARDU INO is a input of my code,then convert like this .-|.-.|-..|..-| |..|-.|---|, in this | is a end of word. Then transmit this morse code

in 2nd Arduino board it receives .-|.-.|-..|..-| |..|-.|---|, but its Decode like this "ARDUU INOO ",it print the same word twice which is before the space

why this happen? please help me

#define SIZE 26

const int btnPin=7;
String morseCode="";


String text="";
int characterAscii=0;
int startPos=0, endPos=0;
int startPos1=0, endPos1=0;
String characterCode="";

int btnState=0;
unsigned long int  duration = 0;

//Array of MorseCode for letters of English Language A to Z
String letters[SIZE]={

// A to I
".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..",
// J to R 
".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.",
// S to Z
"...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.." 
};


void setup() {
  
pinMode(btnPin, INPUT_PULLUP);

Serial.begin(9600);

//Serial.println("*********************");
Serial.println("                    Demonstration of Morse Code              ");
Serial.println("********************* ");
//Serial.println("\nInstructions");
Serial.println("1. First Write Your Morse code");
Serial.println("2. When you are done  Write 1 on above input box and Press Enter or click Send Button ");
Serial.println("3. For Space between letters write 2 and Press Enter ");
Serial.println("4. For Space between words   write 3 and Press Enter ");

Serial.println("5. Thats all Translation of Morse Code  will then be Shown ");

Serial.println("\n\nEnter Your Morse Code Here  ");

}


void loop() {

while(Serial.available() > 0 ) {
      int ascii=Serial.read();

      switch(ascii)
      {
        case 49: // 49 is Ascii value of 1

        Serial.print("\n");
        morseCode.concat('#');// Placeing # at the end of morseCode to simplify further processing

         Serial.print("\nYour Morse code Translation :  ");
         
        endPos1=morseCode.indexOf('#');

        while(endPos1 < morseCode.length() ){
            extractLetters(morseCode.substring(startPos1, endPos1)); // This function would extract Letter as name suggest and would convert  code to text SIMPLE!
            startPos1=endPos1+1;
           if(startPos1 == morseCode.length() ){
              break; 
           }
           endPos1= morseCode.indexOf('#', startPos1);
        }
        startPos1=0;
        endPos1=0;

        text=""; //  For New Translation   
        morseCode="";
        Serial.println("\n\nEnter Your Morse Code Here ");
        
              
        break;
      
}

process();

}

void process(){
  
  while(digitalRead(btnPin) == LOW ) {
         delay(150);  //if you want more resolution, lower this number
         duration = duration + 150;  
    }

 switch(duration){
    
    case 450:
    morseCode.concat("-"); // Storing code in variable morseCode with the help of concatenation function
    Serial.print("-");//Prints User entered Code
    //Serial.print(duration);
    break;
    
    case 150:
    morseCode.concat(".");
    Serial.print(".");
    //Serial.print(duration);
    break;

    case 300:
    morseCode.concat("@");
    Serial.print("|");
    //Serial.println(duration);
    break;

    case 1050:
    morseCode.concat("#");
    Serial.print(" |");
    //Serial.println(duration);        
    break;
  }

 duration = 0;
}

char convertIntoText(String characterCode)
{
  characterAscii=65;
  
  for(int index=0; index<SIZE; index++)
  {
    if(characterCode == letters[index])
    {
      return characterAscii;   
    }
    characterAscii++;  
  }

}

void extractLetters(String words)
{
        words.concat('@'); // Placeing @ at the end of word to simplify further processing

        endPos=words.indexOf('@');

        
        //Loop to extracting single character morse Code from string of word        
        while( endPos<words.length() )
       {
         characterCode=words.substring(startPos, endPos);
         
         //Now CharacterCode will now convert in text

         text.concat(convertIntoText(characterCode));
         
         startPos=endPos+1;
         characterCode="";
         
          // if condition is just to terminate loop when our extracting single character code is complete thats all
         if(startPos == words.length() )
         {
           break;
         }
         
         endPos=words.indexOf('@', startPos);   
       
       }
                
        
        Serial.print(text);
        Serial.print(" ");
        startPos=0;
        endPos=0;
        text="";    
  
}

Solution

  • The issue seems to be in your extracting logic, there is no accounting for the # to break the words, then because convertIntoText does not have a default return path, when the input character is NOT in the expected 26 characters the response from the function used in the sketch is actually the previous response from that function call (this is an error state)

    First rule, make sure all logic paths in your functions return a value, either inject a known error value, or deliberately raise an error. In this case a non-alpha character is good enough:

    char convertIntoText(String characterCode)
    {
      characterAscii=65;
      
      for(int index=0; index<SIZE; index++)
      {
        if(characterCode == letters[index])
        {
          return characterAscii;   
        }
        characterAscii++;  
      }
      return '!'; // error code
    }
    

    If you see any ! characters in your output, then you know that there is an issue mapping the input... but that doesn't help debugging, you should probably output the entire characterCode value, so maybe try this:

    return "(" + characterCode + ")";
    

    But you would also need to change the response type of this function to a String as well.

    The actual issue, make sure you take # into account in extractLetters, there are a number of ways to do this, the easiest to fit into this current logic might be at the start of the loop, just check the next character:

       //Loop to extracting single character morse Code from string of word        
       while( endPos<words.length() )
       {
         // check for word break
         if(words.substring(startPos,startPos+1) == '#')
         {
           text.concat(' ');
           // advance 1 char
           startPos++;
         }
         characterCode=words.substring(startPos, endPos);
    
         //Now CharacterCode will now convert in text
         text.concat(convertIntoText(characterCode));
         
         startPos=endPos+1;
         characterCode="";
         
         // if condition is just to terminate loop when our extracting single character code is complete thats all
         if(startPos == words.length() )
         {
           break;
         }
         
         endPos=words.indexOf('@', startPos);   
       }
    

    Some general code feedback:

    1. When building morseCode you use @ as a delimiter, but you output to the serial stream |. Having two meanings for the same thing makes parsing code and explaining to colleagues much more complicated than it needs to be. Try to avoid having an internal representation as well as a debugging or external one. Pick pipe or at and be consistent.

      When testing this, it wasn't obvious at first, but your input to extractLetters is actually:

      [email protected].@[email protected]@#..@-.@---@
      
    2. (Actually this is more of the same) In process(), to simplify debugging, you should write the same characters that you are interpreting and processing to the serial out as you are recording internally.