1

I have the following strings which are stored in the program memory. They are basically just morse code definitions, with another array of characters where each character in the array has the same index as the morse code definitions:

const char a[] PROGMEM = ".-";
const char b[] PROGMEM = "-...";
const char c[] PROGMEM = "-.-.";
const char d[] PROGMEM = "-..";
const char e[] PROGMEM = ".";
const char f[] PROGMEM = "..-.";
const char g[] PROGMEM = "--.";
const char h[] PROGMEM = "....";
const char i[] PROGMEM = "..";
const char j[] PROGMEM = ".---";
const char k[] PROGMEM = "-.-";
const char l[] PROGMEM = ".-..";
const char m[] PROGMEM = "--";
const char n[] PROGMEM = "-.";
const char o[] PROGMEM = "---";
const char p[] PROGMEM = ".--.";
const char q[] PROGMEM = "--.-";
const char r[] PROGMEM = ".-.";
const char s[] PROGMEM = "...";
const char t[] PROGMEM = "-";
const char u[] PROGMEM = "..-";
const char v[] PROGMEM = "...-";
const char w[] PROGMEM = ".--";
const char x[] PROGMEM = "-..-";
const char y[] PROGMEM = "-.--";
const char z[] PROGMEM = "--..";
const char one[] PROGMEM = ".----";
const char two[] PROGMEM = "..---";
const char three[] PROGMEM = "...--";
const char four[] PROGMEM = "....-";
const char five[] PROGMEM = ".....";
const char six[] PROGMEM = "-....";
const char seven[] PROGMEM = "--...";
const char eight[] PROGMEM = "---..";
const char nine[] PROGMEM = "----.";
const char zero[] PROGMEM = "-----";

const char* const morse_table[] PROGMEM = {a, b, c, d, e, f, g, h, i, j, k, l, m, 
    n, o, p, q, r, s, t, u, v, x, y, z, one, two, three, four, five, six, 
    seven, eight, nine, zero};

const char alphabet[] PROGMEM = {'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','1','2','3','4','5','6','7','8','9','0'};

I am then creating a function which is supposed to be able to take in the morse code definition and spit out a character. This function is below:

void checkString(char * compare) {
  //Unwrap the pointer to the array into a "real" array
  char buf[7];
  for (int i = 0; i < 6; i++) {
    buf[i] = compare[i];
  }

  int correctIndex = -1;

  for (int iterator = 0; iterator < 35; iterator++) {

    char buf2[7];
    strcpy_P(buf2, (char*)pgm_read_word(&(morse_table[iterator])));

    if ((buf[0] == buf2[0]) && (buf[1] == buf2[1]) && (buf[2] == buf2[2]) && (buf[3] == buf2[3]) && (buf[4] == buf2[4])) {
      correctIndex = iterator;
    }
  }

  if (correctIndex == -1) {
    Serial.println("Failed!");
  }

  else {
    Serial.print("Success! Index: ");
    Serial.println(correctIndex);
  }

  char characterBuffer = alphabet[correctIndex];
  Serial.println(alphabet[correctIndex]);
}

The strcpy_p line of code was essentially copied from the PROGMEM reference for Arduino. I don't understand much about it, but from my tests it appears to work in getting an actual string object out of the pointer.

If I input any of the morse code definitions given, the correctIndex integer does contain the correct location of that definition in the morse_table 2d array. However, when I pass this integer into the alphabet array hoping to get out the character at that location I am given a seemingly random character. Is there something that I'm doing wrong with this code to produce such a result? Thanks for your help.

  • 2
    This code cries for optimization... 1. Using binary code, letters could be stored as single byte instead of 2-5 bytes (+1 zero byte for string termination). 2. Comparisons could be as simple as comparing two bytes instead of multiple "&&" on string characters. 3. There is no need to store whole alphabet as string, just use ASCII table: numbers are codes 48-57, small letters are bytes 97-122 (en.wikipedia.org/wiki/ASCII) – madneon May 27 '17 at 21:09
  • @madneon thanks for the feedback - I'm new to c++. By letters, do you mean the morse code definitions? How is it possible to store multiple characters as one byte? I thought that each character had to be stored as one byte. I do see how storing them as null-terminated strings essentially wastes a byte though. That is helpful. – Alex Wulff May 29 '17 at 13:46
  • Sorry for late response. You can store Morse chars in bytes assuming eg. dashes are "ones" and dots are "zeroes", storing in lower bits, this way letter "a" would be 01, "b" would be "100" and so on. Im not sure if its needed, but you can also store the length of Morse code in eg. 3 higest bits. – madneon Jun 5 '17 at 7:32
1

You can't access arrays that are in PROGMEM as if they were normal variables. The compiler can't tell the difference and just interprets it as a RAM address, which is wrong.

Instead you have to use pgm_read_byte to get the data:

char characterBuffer = pgm_read_byte(alphabet + correctIndex);
  • 1
    Thanks, it appears that doing this solved my problem! Also removing PROGMEM and leaving my original code seemed to work as well. So by adding the location of the alphabet array to the offset the microcontroller is accessing the specific character at that location? – Alex Wulff May 27 '17 at 19:44
  • 1
    pgm_read_byte just reads a byte from a given address in flash. An array is just an address - usually a RAM address. Adding a number to a number yields a bigger number, which is the address that your requested byte lies at. – Majenko May 27 '17 at 19:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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