Кодировщик Морзе работает не так, как ожидалось на Arduino UNO

Я начну с того, что у меня нет большого опыта работы с Arduino и программирования на C. У меня есть клон Elegoo Arduino UNO.

Недавно я пытался создать кодировку Морзе, которая преобразует текст в азбуку Морзе, а затем мигает светодиодом для передачи кода Морзе. Код выглядит следующим образом

#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);
}

Часть кода, которая преобразует текст в строку Морзе, ведет себя правильно при запуске на ноутбуке, но когда я загружаю ее на Arduino, UNO ведет себя странно, и индикатор Морзе вообще не мигает.


ОБНОВЛЕНИЕ:

кажется, что Arduino UNO просто запускает только функции start_comm и end_comm, как будто между ними ничего нет. Он изменил поведение и не всегда ведет себя одинаково, прежде чем напечатать какой-то мусор на последовательный монитор, но теперь он просто пропускает весь код между двумя упомянутыми выше функциями.

, 👍1

Обсуждение

Итак, как именно функция "text_to_morse ()" ведет себя в Uno? Печатает ли он правильный текст Морзе? Если нет: что это на самом деле печатает? Нам нужно сузить круг источников ошибок здесь, @chrisl

@chrisl вы правы, я обновлю, как только смогу, и приведу пример, @luigi

"ведет себя правильно при запуске на моем ноутбуке, но" не на "моем Arduino UNO". вы используете " malloc ()", он работает на вашем ноутбуке, потому что у вашего ноутбука много памяти, но в Arduino только 2 кб оперативной памяти. Вы должны проверить, успешно ли ваша "malloc ()" выделила память в куче с помощью " if (text_morse != NULL) { // остальная часть вашего кода};", или лучше не использовать статическую выделенную память, чем динамическую выделенную память., @hcheung


1 ответ


Лучший ответ:

1

Я вроде как решил эту проблему, я неправильно использовал malloc и получал доступ к неинициализированным битам, что приводило к неопределенному поведению. Приведенный ниже код должен работать правильно

#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);
}
,