Convert float and long to string to complete a LCD I2C library

Hello, I know there are many convert 'this' to 'this' questions, and I believe I have gone through all of them and yet cant fix my problem, so please excuse yet another post.

I bought this LCD that has I2C to communicate 20 x 4 LCD Module With I2C & Keypad Controller

http://cgi.ebay.es/I2C-Serial-LCD-Display-Module-20-x-4-keypad-Control-/110609652307?pt=UK_BOI_Electrical_Test_Measurement_Equipment_ET&hash=item19c0d95a53

It has a HD44789 Controller and a BV4218 I2C LCD Display Controller.

However their Library is not very complete and as to printing only handles strings and chars.

// **************************************************************
// sends char
// **************************************************************
void BV4618_I::putch(char c)
{
  Wire.beginTransmission(_i2adr);
  Wire.send(c);
  Wire.endTransmission();
}  

// **************************************************************
// sends string
// **************************************************************
void BV4618_I::puts(char *s)
{
char *sp=s;  
  Wire.beginTransmission(_i2adr);
  // send *s as bytes of date
  while(*sp)
    Wire.send(*(sp++));
  Wire.endTransmission();
}

I would like to create a function to send a float directly, I have tried this but my program freezes.

void BV4618_I::putf(float st, int decimales)
{
  static char * sp = "         ";
  sp = dtostrf( st, 4, decimales, sp );
    Wire.beginTransmission(_i2adr);
  // send *s as bytes of date
  while(*sp)
    Wire.send(*(sp++));
  Wire.endTransmission();
}

Any help would be great, I have spend more hours I can count with problems of my program freezing because of this.
plus it would bevery useful for others with the same display.

Thanks a lot

PS:
This is the original library link practicalmaker.com - This website is for sale! - practicalmaker Resources and Information.

Have a look at the Print class, that support printing floats and longs (to certain extend),
You might even use it as a base class...

  static char * sp = "         ";

Why is sp static? Pointers and arrays are very similar, but there are times when one should be used in preference to another. This is a case where an array is better, since the allocated space can be written to.

char sp[16]; // Or whatever size is appropriate

Hi Paul, thanks for your answer.
I did the static part cause I copied from somewhere else, I didnt want to take it in until it worked.

I did this:

void BV4618_I::putf(float st, int decimales)
{
  char sp[16];
  sp = dtostrf( st, 4, decimales, sp );
    Wire.beginTransmission(_i2adr);
  // send *s as bytes of date
  while(*sp)
    Wire.send(*(sp++));
  Wire.endTransmission();
}

and in the class definition

	void putf(float st, int decimales);

I get this error:

error: incompatible types in assignment of 'char*' to 'char [16]'

Sorry I am completely lost in this one.

robtillaart I did look into that before but I use Wire library so i dont know how to integrate it.

  sp = dtostrf( st, 4, decimales, sp );

The dtostrf function writes to the array in the 4th argument AND returns a pointer to where it wrote. I have no idea why this is so, but you can just ignore the return value from dtostrf.

  dtostrf( st, 4, decimales, sp );

I did look into that [PRINT CLASS] before but I use Wire library so i dont know how to integrate it.

You could start with copying the code from the print class to see if it fits your need. If that does work you should read something about inheritance.
( look at the LCD class, it uses the print class as base IIRC )

Thanks Paul, but I tried

void BV4618_I::putf(float st, int decimales)
{
  char sp[16];
  dtostrf( st, 4, decimales, sp );
    Wire.beginTransmission(_i2adr);
  // send *s as bytes of date
  while(*sp)
    Wire.send(*(sp++));
  Wire.endTransmission();
}

I get

In member function 'void BV4618_I::putf(float, int)':
151:error: lvalue required as increment operand

line 151

    Wire.send(*(sp++));

So first error cleared, cant understand this one.
thanks

int len = strlen(sp);
for(int i=0; i<len; i++)
{
   Wire.send(sp[i]);
}

Or with pointers

void BV4618_I::putf(float st, int decimales)
{
  char sp[16];
  char *p = &sp[0]; // points to start of array.

  dtostrf( st, 4, decimales, sp );
   Wire.beginTransmission(_i2adr);
  // send *p as bytes of date
  while(*p)
    Wire.send(*(p++));
  Wire.endTransmission();
}

Hi!

I faced the similar problem with a 20x4 LCD and 320x240 LCD and adapted this function to convert a float into a string:

String ftoa(float number, uint8_t precision, uint8_t size) {
// Based on mem,  16.07.2008
// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num = 1207226548/6#6
// ---
// avenue33, April 10th, 2010
// Added rounding, size and overflow #
// ftoa(343.1453, 2, 10) -> "    343.15"
// ftoa(343.1453, 4,  7) -> "#      "

  String s = "";

  // Negative 
  if (number < 0.0)  {
    s = "-";
    number = -number;
  }

  double rounding = 0.5;
  for (uint8_t i = 0; i < precision; ++i)    rounding /= 10.0;

  number += rounding;
  s += String(uint16_t(number));  // prints the integer part

  if(precision > 0) {
    s += ".";                // prints the decimal point
    uint32_t frac;
    uint32_t mult = 1;
    uint8_t padding = precision -1;
    while(precision--)     mult *= 10;

    frac = (number - uint16_t(number)) * mult;

    uint32_t frac1 = frac;
    while(frac1 /= 10)    padding--;
    while(padding--)      s += "0";

    s += String(frac,DEC) ;  // prints the fractional part
  }

  if (size>0)                // checks size
    if (s.length()>size)        return("#");
    else while(s.length()<size) s = " "+s;

  return s;
}

Enjoy :slight_smile:

Thanks avenue but i dont need to take care of negative floats so thanks alot for that code but I used Paul's suggestion.

Paul thank you so much for your help, I have not answered earlier cause I was testing thoroughly the code before posting it here as "it's working code".

// **************************************************************
// sends string
// **************************************************************

void BV4618_I::puts(char *s)
{
char *sp=s;  
  Wire.beginTransmission(_i2adr);
  // send *s as bytes of date
  while(*sp)
    Wire.send(*(sp++));
  Wire.endTransmission();
}  



void BV4618_I::putf(float st, int decimales)
{
  char sp[16];
  dtostrf( st, 4, decimales, sp );
    Wire.beginTransmission(_i2adr);
  // send *s as bytes of date
int len = strlen(sp);
	for(int i=0; i<len; i++)
	{
	   Wire.send(sp[i]);
	}
	  Wire.endTransmission();
	} 

// other way of float
void BV4618_I::putff(float st, int decimales)
{
  char sp[16];
  char *p = &sp[0]; // points to start of array.

  dtostrf( st, 4, decimales, sp );
   Wire.beginTransmission(_i2adr);
  // send *p as bytes of date
  while(*p)
    Wire.send(*(p++));
  Wire.endTransmission();
} 

void BV4618_I::puti(int st)
{
char hour_str[4]; // Define as a string (4 bytes)
itoa (st, hour_str, 10); //convert integer to string
//di.puts(hour_str); //print string on LCD
char *sp=hour_str;  
  Wire.beginTransmission(_i2adr);
  // send *s as bytes of date
  while(*sp)
    Wire.send(*(sp++));
  Wire.endTransmission();
} 

void BV4618_I::putl(long st)
{
char hour_str[4]; // Define as a string (4 bytes)
ltoa (st, hour_str, 10); //convert integer to string
//di.puts(hour_str); //print string on LCD
char *sp=hour_str;  
  Wire.beginTransmission(_i2adr);
  // send *s as bytes of date
  while(*sp)
    Wire.send(*(sp++));
  Wire.endTransmission();
}

remember to modify bv_4618_I.h and add:

	void putf(float st, int decimales);
	void putff(float st, int decimales);
	void puti(int st);
	void putl(long st);

This is working, I still have some times where program freezes but I think its cause I am doing some conversion wrong before sending it to the LCD.

I will do more testing and when I have everything clear I will upload the libraries modified, for others to use.

once again, Paul thank you very very much.

I need only two digit after point; so I use that code

void System::lcdPrint(float f){
	print((int) f);
	print('.');
	if(((int) (f * 100)) % 100 < 10)
		print('0');
	print( ((int) (f * 100)) % 100);
}

edit: I've forgotten to sey that my float are < 100...