Int to Char issue SOLVED

So in the code below, both the sprintf and the itoa versions of the conversion work. However, when I print them to the LCD, in both the Conc form and the individual form, it prints the first conversion for both numbers. In other words, if I set timemin = 15 and timesec = 0, if I convert the minutes first I get 15:15 if I convert the seconds first, I get 0:0.

int timesec = 0;
int timemin = 15;
char* timesectext = "";
char* timemintext = "";

void updatetime()
{
  //sprintf(timemintext, "%d", timemin);
  itoa(timemin,timemintext,10);
  //sprintf(timesectext, "%d", timesec);
  itoa(timesec,timesectext,10);
  char timetext[255];
  memset(timetext,0,sizeof(timetext));
  strcat(strcat(strcat(timetext, timemintext),":"),timesectext);
  writetext(20,70,2,fontcolor,2,2,timetext);                              //This prints 0:0 or 15:15 depending on which I convert first
  writetext(70,60,0,fontcolor,1,1,timemintext);                         //Same thing, will print min as long as I convert it first but sec will also print the min value
  writetext(90,60,0,fontcolor,1,1,timesectext);                          //Same thing, will print sec as long as I convert it first but min will also print the sec value
 
}

Obviously I am doing something wrong. And before anyone asks, I have the time library but I don't need the bulk of the functionality, I only need a simple countdown.

Thanks,

Wade

It's actually the one I convert last not first.

I have tried everything to make this work and I am lost.

Have you thought about where the two strings get stored? That would be the root cause of the problem.

I am fairly new to Arduino programming and I am not entirely sure what you mean. They are stored in RAM memory.

Do you mean the that the memory location is being over-written by the second string?

Do I need to pad the strings to make sure the next string moves to the next storage location? If so, I am not at all sure how to do that.

Thanks,

Wade

Ok, this code declares a pointer to a string, and initializes it with the address of a one character empty string (""):

    char *str = "";

This code declares a character string (an array of characters) that can hold a null terminated string of 9 characters:

    char str[10];

There's a good write up here: http://arduino.cc/en/Reference/String

More to the point its just plain incorrect C - you are not allowed to overwrite compile-time constants (the empty strings) in this way - on some architectures this would crash the program as the strings might be in read-only memory. The compiler is also allowed (as here) to share the memory for two identical string constants (in the knowledge that you won't be altering either).

Okay, to fix the issue, I declared the variable with some arbitrary value and moved it to within the updatetime function and as long as I declare them with different values this works fine.

In other words this doesn't work:

 char* timesectext = "59";
  itoa(timesec,timesectext,10);
  char* timemintext = "59";
  itoa(timemin,timemintext,10);

But this does:

 char* timesectext = "11";
  itoa(timesec,timesectext,10);
  char* timemintext = "59";
  itoa(timemin,timemintext,10);

And this was completely broken:

 char* timesectext;
  itoa(timesec,timesectext,10);
  char* timemintext";
  itoa(timemin,timemintext,10);

I actually find it fascinating that it uses the same memory space if I declare them the same or if I don't give them a starting value.

Coming from a VB.Net background, I was taught that you should always declare a variable with some starting value even if it is a 0 or an empty string.

I am confused by what you mean when you say

MarkT:
you are not allowed to overwrite compile-time constants (the empty strings) in this way

Where else, or how else, would I declare a global variable? While I ultimately can get away in this case with declaring that particular one in the function, what if I needed it outside of that function. I am used to declaring global variables of all types exactly as I had done here and had every expectation that I could use and abuse them as needed throughout the code.

Your code declares two pointers and assigns them the address of some string literals. As MarkT pointed out, it's a bad idea to try writing to string literals, and as you demonstrated with the first "59" attempt, the compiler will optimize the generated code by only using one string literal when there are multiple references to it.

If the intent was to get me to figure this out on my own then thanks!

Only the smallest amount of sarcasm there.

So take a look back at my original code.

Here is what I have now:

  char timetext[255];
  sprintf(timetext,"%d:%02d", timemin, timesec);
  writetext(20,70,2,fontcolor,2,2,timetext);

The only thing I need to change is I obviously don't need the time text to be 255. I think it needs to be 5 (5 for the actual characters plus one for the null) but I don't want to break it. :slight_smile:

So thanks for the input and the help steering me in the right direction!

Almost thought I had this solved.

Why does this work:

  char timetext[255];
  sprintf(timetext,"%d:%02d", timemin, timesec);
  writetext(20,70,2,fontcolor,2,2,timetext);

On the display I get 10:10 or whatever I have assigned to the timesec and timemin integers.

But this gives me errors. All I have changed is to pad the timemin:

  char timetext[255];
  sprintf(timetext,"%02d:%02d", timemin, timesec);
  writetext(20,70,2,fontcolor,2,2,timetext);

I have tried to pad with spaces and zeros and both of them give me errors on the LCD. The padding on the timesec works fine in the first bit of code.
I can't explain what it is doing to the GLCD because it really doesn't make sense but I have noticed that anytime I have something wrong in the code, I will get really weird output to the display.

That does seem a bit strange. Try using %2.2d for both quantities...

I didn't want the burden of sprintf() just for times, so I wrote the following for use with times and dates:

/*----------------------------------------------------------------------------*/
/* Convert unsigned value to 2-digit decimal string, return pointer to next   */
/*----------------------------------------------------------------------------*/
char *u2t(char *b,unsigned x,char c)
{  x %= 100;                           /* Remove all but final two digits     */
   *b++ = x / 10 + '0';                /* Output the high-order digit         */
   *b++ = x % 10 + '0';                /* Output the low-order digit          */
   *b++ = c;                           /* Output the following character      */
   return b;                           /* Return pointer to next available    */
}                                      /*  end: u2t()                         */

where b is a pointer to the destination, x is the value to convert, and c is a character to append to the output. u2t() returns a pointer to the next available buffer location so that, for example, I can code:

   b = u2t(buffer,hour,':');
   b = u2t(b,minute,'\0');

to do the conversion/formatting I think you're after.

But this gives me errors. All I have changed is to pad the timemin:

Care to tell us WHAT the errors are?

It truly is difficult to describe. I have a screen that simply displays Startup... In the final version this screen will not exist. Once I push and hold a button for at least 3 seconds, it goes to a second screen the displays two further lines of text. From there it goes to the final screen where it draws a picture as a background and draws very text items over it, including my countdown timer. With added code, it just does random odd stuff that looks like the wrong bytes are being sent like it will not display some text but will draw odd shaped polygons on the screen instead. There is probably a pattern to it's really not important.

I should note that I am using the 4D systems 144 display with the SGC firmware.

This all works great until i do something wonky in the code.

But I have now figured out a BIG part of my problem. I was reading another post last night and began to wonder if it was a memory issue. So I eliminated one of the intermediate strings that serves no real purpose and everything worked as expected.

This is very troublesome as I have a lot more code to write. My sketch as it stands is only 7K bytes but I am using a lot of variables. I am going to have to do some research into memory management and possibly re-think some of my code.

I think I can move some of them to flash but as I understand it, the sketch still writes a pointer to ram so I don't know if that saves me any ram memory.

Lots of research to do.

Thanks everyone for the help!

Wade

I think I can move some of them to flash but as I understand it, the sketch still writes a pointer to ram so I don't know if that saves me any ram memory.

A pointer is two bytes. It is unlikely that any of your strings are that short. So, yes, it will save SRAM by moving the strings to PROGMEM.

I moved several things like pin assignments and some of the fixed strings to Flash based on your suggestion. So far so good.

Tomorrow, I am going to migrate as much as possible to there. I might start looking into using EEPROM if the variables I need to change become too heavy for the RAM which is a very real possibilty. This would allow me to only use those EEPROM values when I need them and then stash them away when I don't. Right now, since I am using the 4D systems display, I am able to use their on board uSD card for storing the image but ultimately won't have that luxury so I am very likely going to be including an EEPROM chip on board to store the background image. So I am going to have to learn that code anyway. I am space limited for the uSD card and EEPROM is much cheaper.

I have the bulk of my GCLD Code in place with its associated variables but I still have to deal with some wireless comms and eventually I will migrate this over to a cheaper display which has a bunch of challenges all by itself. I am sure I will be back but for now this issue is SOLVED!!!!

Thanks again, I learned a lot during this.