Incredibly mind-boggling issue involving string handling [Solved]

Hiya! First post. Love my Arduboy(kickstarter edition), and this community, and have been totally without issues. But, now…

I am trying to print characters from a string one at a time, for dialogue boxes. It’s simple enough. But, I’m in a corner. (My code will be using Tinyfont functions, but it’s the same result with Arduboy2’s print func.) If I try to print my string (a normal char array, not a pointer array), I get garbage characters:

tf.print(first_convo);

However, if I try to print a character from that string, that doesn’t happen:

tf.print(first_convo[3]);

The result is a single ‘y’ in the top-left.
(character is ‘y’; correct)

Okay, so I’m lead to assume that print functions only accept chars, and not char arrays. I know they don’t, but here I am, and that would actually be totally fine for my purpose of typing out individual characters, anyway.

BUT :<
If I do so much as perform the same function within any sort of loop, (well, ‘for’ and ‘while’) the characters are garbage again.

for(int i=0;i<6;i++)
  tf.print(first_convo[i]);

Same garbage as the first image, but only 6 characters.

I’ve considered that maybe I’ve run out of memory, but after commenting out a bulk of my strings, and attempting to run the code in the main ‘loop()’, with no fix, I’m really out of options.

So, I hope you can help me! This is incredibly baffling, but I feel like it’s probably a very simple fix. I’d greatly appreciate somebody making me feel like a huge idiot. :blush:

I should clarify: By ‘garbage characters’, I mean simply mismatched characters. They’re actual characters, not video garbage, but they’re not the characters I want. >n<

Hi,

is first_convo a list of pointers to other strings in program space? If so then this link might solve your issue:

https://www.arduino.cc/en/Reference/PROGMEM

1 Like

Thanks! No, first_convo is simply a string(or char array), and it is stored in flash memory.

Flash memory is another name for program space. Variables stored in flash are usually done so using the PROGMEM keyword.

Please post your code that defines first_convo.

Can you post more of your code (including the text you’re trying to print)? It would probably make it easier to see what’s happening.

Here is the string’s definition:

const char first_convo[]PROGMEM="*2:you... you picked up.";
(shortened; the full string is 717 characters.)

I define it in a header file which I include at the start of my main file.
#include"dialogue/first_conversation.h"

Though, to speed things up, here is everything executed immediately, with the string defined directly above:

int i;
const char first_convo[]PROGMEM="*2:you... you picked up.";

void setup() {
  ab.setFrameRate(40);
  ab.boot();

  for(i=0;i<6;i+=1){
    ab.print(first_convo[i]);
    ab.display();
    delay(100);
  }

  while(true){}

I get the same result.

(‘ab’ points to Arduboy2)

1 Like

So you are putting the string in program memory by using the PROGMEM keyword. The Print class can’t handle this. It will think pointer to first_convo that you pass it is in RAM, which is why it prints garbage (actually the contents of RAM at the pointer offset specified).

The easiest way to print a constant string stored in program memory is to use the F() macro, as described in the link that @veritazz referred to in the first response in this topic.

ab.print(F("*2:you... you picked up."));

If you really want to print a string stored in program memory that’s passed to print() as a pointer, instead of using the F() macro with the string used directly as a parameter, you can cast the string as type __FlashStringHelper*

ab.print((__FlashStringHelper*) first_convo);

If you do this a lot you can create a function to do the casting:

// Print a string in program memory
void printPROGMEMstring(const char* str) {
  ab.print((__FlashStringHelper*)(str));
}
1 Like

Looking at your code closer, I see that you want to print each character of the string one at a time, with a delay between each character. To do this you can use the pgm_read_byte() function

  for(i=0;i<6;i+=1){
    ab.print(pgm_read_byte(&first_convo[i]));
    ab.display();
    delay(100);
  }

This article provides useful information on dealing with data stored in program memory:
http://www.nongnu.org/avr-libc/user-manual/pgmspace.html

3 Likes

Thank you very much! Very informative posts, and I definitely understand my problem now.

I suppose I skimmed the PROGMEM reference page a little too quickly. I thought I understood it, but didn’t think to read closer it when it was linked to me again. So, I feel slightly dumb now. :slight_smile: I’ll certainly pay more attention when reading the reference.

Thanks, again! :heart:

3 Likes

Don’t feel dumb, you now learned something new, that’s the opposite! :smiley:
I’ve learned a lot during arduboy coding.

1 Like

It’s slightly embarrassing to myself, since I have good experience in coding, and I should know very well to read documentation closely. Obviously not well enough, though, so you’re right. :stuck_out_tongue_closed_eyes: Lesson learned. Thanks for the nice words! :>

2 Likes

One more lesson to take away from this:
Always post as much relevant code as possible when asking a question, it makes it much easier for people to see what you’re doing and usually means you get an answer to your problem quicker.

2 Likes