Displaying Data to LCD. Runs very slow. (Solved!)

Ok, am building a custom control panel/display for a game called 'Kerbal Space Program'. Someone has made a plugin that pushes data from the game over a serial port which can then be interpreted by an Arduino (anything really...)

I have a Mega2560 that i am using.

I have the LCD panel connected and working (mostly...)
see photo
Imgur

Currently i have 3 values being displayed. All are floating point numbers, converted to strings so i can manipulate it (check length, add 'units' to the end, etc).

However, when i add more functions the refresh seems to almost die and only update once every minute or so.

The odd thing is it doesn't seem to relate to the actual content. If i turn off other values the new ones work.

I'm not sure if i'm 'overloading' the Arduino and i need to check the way i am doing it.

This is my code, it is not the complete code, only what i am adding to the one that maker of the plugin is posting.

I've tried to make it easy to follow and added in comments, hopefully you can work it out.

Please let me know if you have any questions or suggestions on why this is not working and how to fix it.

Thanks!

void LCD() {
  //Runs Functions that display various readouts on the LCD Screen
  VOrbit();
  APPE(VData.AP,"AP=");
  APPE(VData.PE,"PE=");
  Escape();
  //OrbitInc();
  
}

//Function to convert a Floating Point value to a String which is left justified, no 'extra' spaces
String FloatToString(float Float, int Dec){
 
 char dtostrfbuffer[8];
 
 dtostrf(Float,-1, Dec, dtostrfbuffer);
 
 return dtostrfbuffer;
 
}

//Function to clean up any 'trash' characters on the LCD screen by adding spaces to the end of the final String by checking the length of the String against the 'max length' passed to it.
String CheckLength (String DataString, int Length) {
 
 while (DataString.length() < Length) {
    DataString = DataString + " ";
 }
 
 return DataString;
 
}

//Function to work out the Orbit Velocity and display it 
void VOrbit(){
  lcd.setCursor(0, 3);
  
  int Dec = 2;
  
  String AP = (FloatToString(VData.VOrbit, Dec) + "ms");
  String StrLen = CheckLength(AP,11);

  lcd.print("V=" + StrLen);
 
  
}

//Function to display the AP and the PE
void APPE(float APPE, String Name){
  String SpeedUnit = "m";
  int Dec=2;
  
  //If reading is over 1000m, convert to km
    if (APPE > 1000.00) {
      APPE = APPE / 1000.00;
      SpeedUnit = "km";
  }
  //If reading is over 1000km, convert to Mm
    if (APPE > 1000.00) {
      APPE = APPE / 1000.00;
      SpeedUnit = "Mm";
      int Dec=3;
  }
  
  //Check that the reading is the 'AP' and then display it
  if (Name == "AP=") {
    
    lcd.setCursor(0, 0);
    if (VData.AP <= 0.00){
      lcd.print(Name + "0.00m");
    } else {
      
      String AP = (FloatToString(APPE, Dec) + SpeedUnit);
      String StrLen = CheckLength(AP,8);
      
    lcd.print(Name + StrLen);
  }
  }
  //Check that the reading is the 'PE' and then display it  
    if (Name == "PE=") {
    
    lcd.setCursor(0, 1);
    if (VData.PE <= 0.00){
      lcd.print(Name + "0.00m");
    } else {
      
      String PE = (FloatToString(APPE, Dec) + SpeedUnit);
      String StrLen = CheckLength(PE,8);
      
    lcd.print(Name + StrLen);
  }
  }
 }

//Function to determine the Orbit reading and if you are on an 'escape' tradjectory.
void Escape() {
  lcd.setCursor(12, 0);
  int Dec = 2;
  String escape = (FloatToString(VData.e, Dec)); 
  if (VData.e > 1.00) {
    lcd.print("Escape");
  } else {
    lcd.print(escape);
  }
}

//Function to display the Orbit angle
void OrbitInc() {
  lcd.setCursor(12, 1);
  int Dec = 2;
  //(char)223 displays a 'degree' symbol.
  String Inc = (FloatToString(VData.inc, Dec) + ((char)223));
  
  lcd.print(Inc);
  
}

A good place to start would be to get rid of all the Strings and use standard C/C++ character array manipulation functions. Manipulation of String objects rapidly eats up memory and can cause no end of problems.
Edit: here is some discussion http://forum.arduino.cc/index.php/topic,124367.0.html
Your post will no doubt provoke more.

is that using the 'char' variable type?

I did try that and it didn't seem to make any difference, but that was 1-2 rewrites ago...

At what point in the coding did you start having this problem? That could be a big clue.
I have no idea what the LCD functions you are calling do, so can't comment on anything other than the "usual suspects".
I suggest to try a few simpler programs to isolate the problem.

Basically the functions take a floating point variable, convert it to a String using 'dtostrf' with a -1 for the max length.
I then add a 'unit' to the end of the number.
I then have a loop which compares the length of that string to a value that i provide, this means that if the number reduces in length (ie, 100 to 99) i add spaces to fill in the rest of it so i have no trash characters left over.

Some of them convert units over 1000 to something else (ie, m's to km's).

Then it prints the String to the LCD screen.

The odd thing is, everything seems to work on its own, it's only when i start trying to display more than 3 values that i have issues.

ie, i have 4 values. and display 1-2-3. When i add number 4 on it starts going really slow (ie, will sit static for ~1 minute, and then all numbers will refresh, then it will wait again).
However, i remove value #2, and values 1-3-4 all display correctly.
I add back #2 and remove #3 and 1-2-4 all display correctly.

It does seem to be some kind of 'load' issue or possibly a variable that i need to NULL at the end of something...but as most of them are declared inside functions i didn't think i needed to (ie, when the function ends they go 'poof')

*Edit, i am reading that thread you linked to. It is worth a try!

*Edit #2
After reading that thread, the issue may be with

String CheckLength (String DataString, int Length) {
 
 while (DataString.length() < Length) {
    DataString = DataString + " ";
 }
 
 return DataString;

I might need to rewrite that using another process...
I wonder if the reserve function could be used?

https://code.google.com/p/arduino/issues/detail?id=449

*Edit #3
Maybe something like this instead

String CheckLength (String DataString, int Length) {
 
  String DataString1;
  DataString1.reserve(Length);
  DataString1 = DataString;
    
 while (DataString1.length() < Length) {
    DataString1 = DataString1 + " ";
 }
 
 return DataString1;
}

Creates a new variable with enough memory allocated, then assigns that the value of the String passed to the function. Then adds whatever spaces are needed and returns it.

Is there a command i can use to free up the memory used by the first variable? Or is it not worth it for the function? It should hopefully not run for very long :stuck_out_tongue:

ok, i've tried the changes i posted in my previous post.

Seems to help a little, but still have the main problem.

I am not sure if the issue is String related...

I have 5 functions that i have written

  VOrbit();
  APPE(VData.AP,"AP=");
  APPE(VData.PE,"PE=");
  Escape();
  OrbitInc();

each is responsible for taking a variable and writing it to the LCD screen. Sometimes this involves calculations and String manipulation.
Now, i have just had it running correctly with the first Function ('VOrbit') commented out, but the other 4 working fine.

If i replace VOrbit with

lcd.print(VData.VOrbit);

(VData.VOrbit is the original variable that i am manipulating)
then i still have issues. There is absolutely no manipulation there, it is just writing the variable (which is the Float variable) to the LCD screen.

Does anyone else have anything they can suggest?

well, think i've got it sorted now.

I started using an 8-bit bus for the LCD instead of a 4-bit.

Not sure if my LCD is just cheap/slow (was ~$6 on ebay) or if they are all like this.

So, yay!

Thanks for your help jremington!