1

I'll start saying that I don't have much experience working with Arduino and programming in C. I have an Elegoo Arduino UNO clone.

Recently I was trying to build a morse encode which converts a text to morse and then flashes a LED to communicate the morse code. The code is as follows

#define OUT_PIN 8
#define END_PIN 7

const short dot_time = 200; // Time LED is ON for dot
const short dash_time = dot_time*3; // Time LED is ON for dash
const short same_letter_space = dot_time; // Time LED is OFF between dots/dashes of the same letter
const short letter_space = dot_time*3; // Time LED is OFF between letters
const short word_space = dot_time*5; // Time LED is OFF between words
const char letter_separator[] = "_";
const char word_separator[] = "/";

typedef struct {
  char * morse;
  char letter;
}morse_pair;

morse_pair morse_table_letters[] = {{".-", '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'}};
morse_pair morse_table_digits[] = {{"-----", '0'}, {".----", '1'}, {"..---", '2'}, {"...--", '3'}, {"....-", '4'}, {".....", '5'}, {"-....", '6'}, {"--...", '7'}, {"---..", '8'},//
{"----.", '9'}};

char test_text[] = "aaa";

morse_pair letter_encoder(char letter){
  int letter_value = (int) letter;
  if(letter_value >= 97){
    //lowercase
    return morse_table_letters[letter_value-97];
  }
  else if (letter_value>=65){
    //uppercase
    return morse_table_letters[letter_value-65];
  }
  else {
    //digits
    return morse_table_digits[letter_value];
  }
}

char* word_to_morse(char* word, size_t len){
  Serial.print("Encoding word: ");
  Serial.println(word);
  size_t len_morse = 0;
  char* letters[len];
  for(size_t l=0;l<len;l++){
    letters[l] = letter_encoder(word[l]).morse;
    len_morse += strlen(letters[l])+1;
  }
  char* morse_string = malloc(len_morse*sizeof(char));
  for(size_t l=0;l<len;l++){
    strcat(morse_string, letters[l]);
    if(l<len-1){
      strcat(morse_string, letter_separator);
    }
  }
  strcat(morse_string, word_separator);
  Serial.print("Result: ");
  Serial.println(morse_string);
  return morse_string;
}

char* text_to_morse(char* text){
  Serial.print("Encoding text: ");
  Serial.println(text);
  size_t len = strlen(text);
  char* text_morse = malloc((4*len+len)*sizeof(char));
  char* swp = text;
  for(char* ewp = text;ewp!=(text+len);ewp++){
    if(*(ewp+1)==' ' || *(ewp+1) == '\0'){
      char * wtm = word_to_morse(swp, ewp-swp+1);
      strcat(text_morse, wtm);
      swp=ewp+2;
      free(wtm);
    }
  }
  Serial.print("Result: ");
  Serial.println(text_morse);
  return text_morse;
}

void morse_to_pin(char* text_morse){
  Serial.println("Playing with pins");
  size_t len = strlen(text_morse);
  for(size_t l=0;l<len;l++){
    char letter = text_morse[l];
    Serial.println(letter);
    if(letter == '.'){
      digitalWrite(OUT_PIN, HIGH);
      delay(dot_time);
    }
    else if(letter=='-'){
      digitalWrite(OUT_PIN, HIGH);
      delay(dash_time);
    }
    else if(letter=='_'){
      digitalWrite(OUT_PIN, LOW);
      delay(letter_space);
    }
    else if(letter=='/'){
      digitalWrite(OUT_PIN, LOW);
      delay(word_space);
    }
    else {
      digitalWrite(OUT_PIN, LOW);
      delay(same_letter_space);
    }
  }
}

void start_comm(){
  Serial.println("Start comm.");
  digitalWrite(END_PIN, HIGH);
  delay(2000);
  digitalWrite(END_PIN, LOW);
}

void end_comm(){
  Serial.println("End comm.");
  digitalWrite(END_PIN, HIGH);
  delay(500);
  digitalWrite(END_PIN, LOW);
  delay(500);
  digitalWrite(END_PIN, HIGH);
  delay(500);
  digitalWrite(END_PIN, LOW);
}

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

void loop ()
{
  start_comm();
  delay(1000);
  char* ttm = text_to_morse(test_text);
  morse_to_pin(ttm);
  free(ttm);
  delay(1000);
  end_comm();
  delay(1000);
}

The part of the code that converts text to a morse string behaves correctly when run on my laptop, but when I upload it to my Arduino UNO behaves weirdly and the morse LED doesn't flashes at all.


Edit:

the Arduino UNO just seems to run only the start_comm and end_comm functions, as if there's nothing inbetween. It changed behaviour and doesn't behaves always the same, before it printed some garbage to the serial monitor, but now it just skips the whole code inbetween the two functions mentioned above.

3
  • 1
    So how exactly is the text_to_morse() function behaving on the Uno? Is it printing the correct morse text? If not: What is it actually printing? We need to narrow down the error source here
    – chrisl
    Dec 2, 2021 at 8:12
  • @chrisl you're right, I'll update as soon as I can with and example
    – luigi
    Dec 2, 2021 at 9:03
  • "behaves correctly when run on my laptop, but" not on "my Arduino UNO". you use malloc(), it works on your laptop because your laptop have plenty of memory, but only has 2k RAM in Arduino. You should check whether your malloc() allocated memory successfully in the heap with if (text_morse != NULL) { // rest of your code };, or better off, not to use static allocated memory than dynamic allocated memory.
    – hcheung
    Dec 3, 2021 at 2:17

1 Answer 1

1

I kind of solved it, I was using malloc incorrectly and was accessing uninitialized bits, thus causing undefined behaviour. The code below should work correctly

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define OUT_PIN 8
#define END_PIN 7

const short dot_time = 200; // Time LED is ON for dot
const short dash_time = dot_time * 3; // Time LED is ON for dash
const short same_letter_space = dot_time; // Time LED is OFF between dots/dashes of the same letter
const short letter_space = dot_time * 3; // Time LED is OFF between letters
const short word_space = dot_time * 5; // Time LED is OFF between words
const char letter_separator[] = "_";
const char word_separator[] = "/";
const char unkown_letter[] = "?";

typedef struct {
  char * morse;
  char letter;
} morse_pair;

const morse_pair morse_table_letters[] = {{".-", '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'}
};
const morse_pair morse_table_digits[] = {{"-----", '0'}, {".----", '1'}, {"..---", '2'}, {"...--", '3'}, {"....-", '4'}, {".....", '5'}, {"-....", '6'}, {"--...", '7'}, {"---..", '8'},//
  {"----.", '9'}
};

const char* letter_encoder(char letter) {
  int letter_value = (int) letter;
  if (letter_value >= 97 && letter_value <= 122) {
    //lowercase
    return morse_table_letters[letter_value - 97].morse;
  }
  else if (letter_value >= 65 && letter_value <= 90) {
    //uppercase
    return morse_table_letters[letter_value - 65].morse;
  }
  else if (letter_value>=48 && letter_value<=57) {
    //digits
    return morse_table_digits[letter_value].morse;
  }
  else {
    //Boh
    return unkown_letter;
  }
}

void word_to_morse(char* morse_word, char* word, int len) {
  Serial.print("Encoding word: ");
  Serial.println(word);
  for (int l = 0; l < len; l++) {
    strcat(morse_word, letter_encoder(word[l]));
    if (l < len - 1) {
      strcat(morse_word, letter_separator);
    }
  }
  strcat(morse_word, word_separator);
  Serial.print("Word result: ");
  Serial.println(morse_word);
}

void text_to_morse(char* morse_text, char* text, int len) {
  Serial.print("Encoding text: ");
  Serial.println(text);
  char* swp = text;
  int morse_len = 0;
  for (char* ewp = text; ewp != (text + len); ewp++) {
    if (*(ewp + 1) == ' ' || *(ewp + 1) == '\0') {
      int w_len = ewp - swp + 1;
      char * morse_word = (char*) malloc((5*w_len+w_len)*sizeof(char));
      strcpy(morse_word, "");
      word_to_morse(morse_word, swp, w_len);
      morse_len += strlen(morse_word);
      Serial.print("Word result: ");
      Serial.println(morse_word);
      Serial.print("Word len: ");
      Serial.println(morse_len);

      strcat(morse_text, morse_word);
      swp = ewp + 2;
      free(morse_word);
    }
  }
  morse_text = (char*) realloc(morse_text, ++morse_len*sizeof(char));
  Serial.print("Text result: ");
  Serial.println(morse_text);
}

void morse_to_led(const char* text_morse, int len) {
  Serial.println("Flashing morse with pins");
  for (int l = 0; l < len; l++) {
    char letter = text_morse[l];
    Serial.println(letter);
    switch(letter){
      case '.':
        digitalWrite(OUT_PIN, HIGH);
        delay(dot_time);
        break;
      case '-':
        digitalWrite(OUT_PIN, HIGH);
        delay(dash_time);
        break;
      case '_':
        digitalWrite(OUT_PIN, LOW);
        delay(letter_space);
        break;
      case '/':
        digitalWrite(OUT_PIN, LOW);
        delay(word_space);
        break;
      default:
        digitalWrite(OUT_PIN, LOW);
        delay(same_letter_space);
        break;
    }
  }
}

void start_comm() {
  Serial.println("Start comm.");
  digitalWrite(END_PIN, HIGH);
  delay(dash_time);
  digitalWrite(END_PIN, LOW);
}

void end_comm() {
  Serial.println("End comm.");
  digitalWrite(END_PIN, HIGH);
  delay(dot_time);
  digitalWrite(END_PIN, LOW);
  delay(dot_time);
  digitalWrite(END_PIN, HIGH);
  delay(dot_time);
  digitalWrite(END_PIN, LOW);
}

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

void loop ()
{
  //Start
  start_comm();
  delay(2000);

  //Convert
  char test_text[] = "test";
  int len = strlen(test_text);
  char * morse_text = (char*) malloc((5*len+len)*sizeof(char));
  strcpy(morse_text, "");
  text_to_morse(morse_text, test_text, len);
  morse_to_led(morse_text, strlen(morse_text));
  free(morse_text);
  delay(2000);
  
  //End
  end_comm();
  delay(2000);
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.