String to Char*

Seems like a simple problem on the surface but here are the basics. This is sort of a spin off on my previous thread where I have learned that I have memory issues so I am trying to move some strings to flash. The problem is that I have to send a char* to the LCD function and I keep getting an invalid conversion error.

So in the code:

const String initial = "INITIALIZING...";            //Doesn't work
//const char* initial = "INITIALIZING...";         //Doesn't work
//const char initial[16] = "INITIALIZING...";     //Doesn't work


// Later in the code I have this:

writetext (2,2,2,fontcolor,1,1,initial);    


// And the writetext function looks like this:

void writetext (unsigned int x, unsigned int y, unsigned int font, unsigned int color,unsigned int width,unsigned int height, char* text)
{
  Serial.write("S");
  Serial.write(x);
  Serial.write(y);
  Serial.write(font);  
  Serial.write(color >> 8);		// MSB			
  Serial.write(color & 0xFF);		// LSB
  Serial.write(width);
  Serial.write(height);
  Serial.write(text);
  Serial.write(0,HEX);
  getreply();
}

If I replace initial with any direct string like "INITIALIZING..." it works. If I cast it within the scope to a char[] it works. For some reason it does not like the const. The 3rd option above should work based on the fact that the following works later in the code:

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

I see that if I cast it to a char[] within the code it would work but that seems to be counter intuitive since I am trying to minimize RAM usage and adding a temporary variable to hold the string within the code makes no sense unless the arduino disposes of variables that are called within functions once they are used?

I have been searching the interweb but so far no success.

Thanks,

Okay so a little more research seems to imply that a local variable called within a function is disposed once it is used so I should be able to convert to a temp char[] within the function and still save a ton of ram since I have a lot of fixed strings that are written to the GLCD.

Is this correct?

Here is how I am going about it:

const String initial = "INITIALIZING...";
const String receiving = "RECEIVING GAME DATA...";
const String startup = "Startup...";


//And in the body of the code:

void initLCD()
{

  Serial.write("E");     //Erase LCD
  getreply();
  delay(100);
  
  char temptext[25];                                    //Using a value that will hold the largest string
  initial.toCharArray(temptext,25);
  writetext (2,2,2,fontcolor,1,1,temptext); 
  receiving.toCharArray(temptext,25);       //As long as I use the entire buffer any longer strings converted first will be overwritten. I tested this by moving the shorter string under the longer one.
  writetext (2,50,2,fontcolor,1,1,temptext); 

}

One of the interesting side affect is that as I move the strings to Flash, the sketch is rapidly getting larger.

So is this the best way to do this or is there are more memory/code efficient way to handle this?

Sacman:
I see that if I cast it to a char[] within the code it would work but that seems to be counter intuitive since I am trying to minimize RAM usage and adding a temporary variable to hold the string within the code makes no sense unless the arduino disposes of variables that are called within functions once they are used?

Casting a value does not create a copy in memory, it only tells the compiler to treat that value as a different type.

One of the interesting side affect is that as I move the strings to Flash, the sketch is rapidly getting larger.

The string is going to take space in SRAM or flash/PROGMEM. They are not disappearing/shrinking because you move them out of SRAM.

const String initial = "INITIALIZING...";            //Doesn't work
//const char* initial = "INITIALIZING...";         //Doesn't work
//const char initial[16] = "INITIALIZING...";     //Doesn't work

What does "doesn't work" mean. Any of those initialization methods should work. Whether they are usable as-is elsewhere is independent of the initialization method.

If the problem is that a function wants a char *, and you have a const char *, cast it!

Sacman:

const String initial = "INITIALIZING...";

One of the interesting side affect is that as I move the strings to Flash, the sketch is rapidly getting larger.

I thought you had to use macros and PROGMEM (PROGMEM - Arduino Reference) to move your strings to flash? I don't think simply using const does that.

I haven't looked at 1.0 however, and don't use String.

Brad.

If a reference is not taken, or a pointer not modified, the variable may be promoted to a compile constant resulting in a reduction in SRAM.
The only way to enforce flash memory though is using PROGMEM.

Awesome!

I just pulled up the reference to PROGRMEM. I am out of time tonight but this looks like what I need to do to relieve my RAM issues. I have a little over 100 characters in strings at the moment. You wouldn't think this would be too much of an issue, but it is.

Moving some of the minor pin assignments etc to constants helped for a while but now that I have started to add code, I have run into memory issues yet again so my const strings seem to be behaving as you described. Another place I can save some space is in the multitude of booleans I am using. I might be able to combine those into a couple of bytes to make more efficient use of space if it comes to it. Since most of these booleans will already be received as part of a serial string, not converting them to separate variables is not too much of a hardship. Hopefully it won't come to that though.

I will work on this tomorrow and see if PROGMEM solves my problems.

Thanks again!

PROGMEM seems to be doing the trick.

Now I have a new issue. Once again I have done a lot of research and can't seem to find an answer.

In another post, someone mentioned that the arduino compiler will attempt to optimize code and this could lead to global variables sharing the same memory space. While this is silly on the surface, I can see why it does that to minimize ram usage. However, I need it to stop doing that. I have several variables that I have declared as integers. It seems somewhat
arbitrary which ones don't work and I can't seem to fix it.

Currently I have about 30 global variables. A few of these could be eliminated but I need the bulk of them to be global. Is this part of the problem? All string variables and other constants have been moved to flash. It seems that every time I attempt to optimize memory I take several steps backward before I can move forward.
For example:

//simplified variable names to explain. 

int x = 0;
int y = 0; 
int timersec = 10;
int timermin = 10;

// Later in the code, when I set y to = 1

y = 1;

// later I compare to a random and set x = to a value depending on my random result:

randomnumber = random(3);

if (randomnumber == 1) 
{
x = 3;
}
if (randomnumber == 2)
{
x = 4;
}

// No matter what I do I x sees the value of y and I cannot change it. I have printed it out to make sure that this is what is happening and it is. 
// I tried initializing the variables with different numbers and it still doesn't work. 

int x = 100;
int y = 33;

//I can make neither heads nor tails of this.

Help!

Are you still using the String class in your sketch (tho' perhaps initialising the strings from PROGMEM)?
Are you manipulating String objects (concatenating them, passing copies)?
I found that Strings simply aren't suitable for use in an embedded environment: they quickly chew up or fragment the heap and Release the Hounds of Chaos.
Try switching to careful use of char[]'s, strcpy() etc.

Sacman:
In another post, someone mentioned that the arduino compiler will attempt to optimize code and this could lead to global variables sharing the same memory space.

I believe that is incorrect. Perhaps you misunderstood what was being said?

Do you have a link to the thread in question?

Help!

It might be helpful to post as simplified an example as you can create that shows the problem.

The most likely reason for your unexpected results is operator error, not compiler optimizations.

Brad.

I agree that this shouldn't be happening but I have stripped out everything of no consequence and it still will not change that variable. I have moved all my strings to PROGMEM so I am fairly confident that this is not causing my problem. I have been trying to avoid posting a bunch of code so as not to scare people off but here goes:

I have left out the string setup at the top and the vast majority of the code but this is the part that is broken. If I dumb it way down and simply print to the HyperTerminal it works fine.

int bombteam = 0;
int gamemode = 0;
int team1score = 0;
int team2score = 0;

char team1scoretext[4];
char team2scoretext[5];

boolean gamestart = false;

int timesec = 10;
int timemin = 10;
int bombsec = 10;
int bombmin = 10;

const int LCDResetpin =13;
const int redpin = 12;
const int greenpin = 11;
const int buttonpin = 9;

boolean lastbutton = LOW;
boolean currentbutton = HIGH;

unsigned long startmillis = 0;
unsigned long endmillis = 0;

boolean initialized = false;
int powerontime = 3000;

unsigned long scoremillis = 0;

const unsigned int fontcolor = 65535;
unsigned int timecolor = 0;
unsigned int bombcolor = 0;
unsigned int tempcolor = 0;


void setup()
{
  pinMode(redpin,OUTPUT);
  pinMode(greenpin,OUTPUT);
  pinMode(buttonpin,INPUT);
  pinMode(LCDResetpin,OUTPUT);     //LCD Reset
  pinMode(8,OUTPUT);
  digitalWrite(LCDResetpin,HIGH);  //Must be kept high. Low to reset LCD.
  
  randomSeed(analogRead(0));

  Serial.begin(9600);

  delay(2000);            //Wait for display power 
  Serial.write(0x55);      //Autobaud
  getreply();  
  fontcolor = getcolor(255,255,255);
  timecolor = fontcolor;
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[2]))); //Startup            //This comes from the string table and should be unimportant
  writetext(5,5,2,fontcolor,1,1,buffer);
}


void loop()
{
  //Debounce button
  currentbutton = debounce(lastbutton);
  //Check if burron pressed. Count Millis until released.
  if (lastbutton == LOW && currentbutton == HIGH) 
  {
    startmillis = millis();
      do
      {
       endmillis = millis();
      }while(digitalRead(buttonpin) == HIGH);
  }
  //Check to see if this is the startup button press.
  if ((initialized == false) && (endmillis - startmillis > powerontime))
  {
    digitalWrite(redpin,HIGH);
    digitalWrite(greenpin,LOW);
    initialized = true;
    delay(100);
    initLCD();
    delay(1000);
    receivegamedata();
    initgameLCD();
    startmillis = endmillis;
  }    
  
  //See if this is the start game press.
  if ((initialized == true) && (endmillis - startmillis > 300))
  {
    gamestart = true;
    startmillis = endmillis;
  }  

  //Check every one second to update time. 
  //This currently also randomly assigns scores and bombteam color
  if ((millis() - scoremillis > 1000) && gamestart == true)
  {
    long randomteam = random(3);
    if (randomteam == 1)
      {
      bombteam = 1;                                                    //This simply doesn't happen
      team1score += 100;                                              //This works exactly as expected
      sprintf(team1scoretext, "%d", team1score);              //This works exactly as expected
      writetext(60,34,0,fontcolor,1,1,team1scoretext);      //This works exactly as expected
     // Because the score updates on the LCD screen, I know this if loop is functioning. It just doesn't change the bombteam number?????? Both the initialized and gamestart variables are both set to a logical 1. 
      }
    else if (randomteam == 2)
      {
      bombteam = 2;                                                   //Same as above
      team2score += 100;
      sprintf(team2scoretext, "%d", team2score);
      writetext(60,49,0,fontcolor,1,1,team2scoretext);  
      }
    //Handle countdown issues.
    if (timesec > 0)
      {
      timesec -= 1;
      }
    else
      {
       timesec = 59;
       timemin -= 1; 
      }
    if ((timemin == 0) && (timesec <= 59))
      {
      timecolor = getcolor(255,0,0); //Sets countdown timer color to red once less than 1 minute remaining.
      }
    else
      {
      timecolor = fontcolor; //If more than 1 minute remaining, countdown timer is white.
      }
    if ((bombteam = 1) || (bombteam = 2))
      {
      if (bombsec > 0)
      {
       bombsec -= 1;
      }
      else
      {
       bombsec = 59;
       bombmin -= 1; 
      }
    }
    updatetime();
    scoremillis = millis();    
  }
  
 lastbutton = currentbutton;

}
// Routine to receive game setup data.
void receivegamedata()
{
 bombteam = 1;
 gamemode = 11;
 timesec = 20;
 timemin = 1;
 bombmin = 2;
 bombsec = 0;
}
void updatetime()
{ 
  char timetext[20];
  sprintf(timetext,"%d",bombteam);                                  // This is where I am printing the BombTeam number. It is whatever I set it to in the Receive data function until I start the game then it goes to a 1 and never changes.
  writetext(2,2,1,fontcolor,1,1,timetext);
  if (gamemode >= 10)
  {
  sprintf(timetext,"%2d:%02d", timemin, timesec);
  writetext(18,78,2,timecolor,1,1,timetext);
  sprintf(timetext,"%2d:%02d", bombmin, bombsec);
     if (bombteam == 0)
     {
       bombcolor = fontcolor;
     }
     if (bombteam == 1)
     {
       bombcolor = getcolor(0,0,255); 
     }
     if (bombteam == 2)
    {
       bombcolor = getcolor(51,204,51);
    }
    
   writetext(75,78,2,bombcolor,1,1,timetext);
  }
  else
  {
  writetext(24,71,2,timecolor,2,2,timetext);
  }
}

I am stuck!

    if ((bombteam = 1) || (bombteam = 2))

A quick look shows the above, I wouldn't think you'd really want to do that. I think you mean "==".

Brad.

EDIT: I'll take a closer look in a bit and let you know if I see anything else that's not quite right.

Holy Crap!!!

That did it. I would think that would have thrown a compile error.

Thanks a ton. Now I am back on track!

Sacman:
Holy Crap!!!

That did it. I would think that would have thrown a compile error.

Well, unfortunately that is a valid C construct. Just not what you wanted :slight_smile:

Thanks a ton. Now I am back on track!

No problem. Glad to help. Good luck finishing your project.

Brad.

char team1scoretext[4];
char team2scoretext[5];

Why are these two similarly named arrays different sizes?

That did it. I would think that would have thrown a compile error.

    if ((1 = bombteam) || (2 = bombteam))

would have.

PaulS:

char team1scoretext[4];

char team2scoretext[5];



Why are these two similarly named arrays different sizes?

They aren't supposed to be. In fact, I had already caught that and fixed it.

You guys helped me solve a ton of issues yet still had one more pop up. This entire time I have been using hardware serial for my LCD. Since this limits my ability to use the serial port for troubleshooting, plus I will ultimately have some form of wireless, I decided to move everything to a software serial port. What a train wreck!

The good news is I solved this one myself but wanted to post in case anyone else is using the 4D Goldelox SGC display.

Since the Library is not optimized for V1.0, I have had to strip code out to use it. When you write a string to the display the last character that is sent is the string terminator. This is a 0.

Arduino doesn't like Serial.write(0x00), it gives an ambiguous error but this has been covered in other posts. So I thought I was smart and used (0,HEX). Apparently this doesn't work either. I only figured this out by doing a very simple Hello World program and looking at my responses back from the LCD. I was getting an odd response from the writetext function. I assigned the 0x00 to a char terminator[5] and all my problems have gone away.

Thanks again for all the help, I'm quite certain I will have more questions soon.