Convert string of variable length to floats.

Hello!
I need to convert a string variable in length floats in order to generate a graph of temperature.
You must separate values from buf [ i ] in groups of 5 bytes and then convert them to floats.
Once this is done the output values must meet the conditions required for the chart is drawn correctly on my LCD.

Here's the code I'm trying to write:
I am using the library sdfat.h.

void tempgScreen()
{
int x, y, z;
int grafico;
t = rtc.getTime();
int16_t n;
uint8_t buf[6];
float temperatura;

file.open(&root, "LOGTDIA.TXT", O_READ);
while ((n = file.read(buf, sizeof(buf))) > 0)
{
for (uint8_t i = 0; i < n; i++)

buf[ i ]  //  separate values from buf [ i ] in groups of 5 bytes and then convert them to floats

}

temperatura = // Float of buf[ i ] //

if ((temperatura) < 22.5)
{
grafico = 190;
}
else if ((temperatura) >27.5)
{
grafico =30;
}
else
{
grafico = (190-((temperatura-22.5)*30));
}

for (uint8_t j=0; j < (n/5) ;j++)
{
setFont(SMALL, 255, 255, 255, 0, 0, 0);
myGLCD.drawPixel((40+j),grafico);
}
}

Here is the code that writes the values ??in the SD card:

//Write CR LF to a file

void writeCRLF(SdFile& f) {
f.write((uint8_t*)"\r\n", 2);
}
void logtempgraf() //Grava dados no SD CARD para gerar grafico de temperatura.
{
t= rtc.getTime();

String oldminuto;
oldminuto = time;
time = t.min;

if (oldminuto != time)
{
file.open(&root, "LOGTDIA.TXT", O_CREAT | O_APPEND | O_WRITE);

if ((tempC<=0.0) || (tempC>99.9))
{
file.print("00.00");
writeCRLF(file);
}
else
{
file.print(tempC);
writeCRLF(file);
}
file.close();

if ((t.hour==23) && (t.min==59))
{
file.remove(file,"LOGTDIA.TXT");
}
}
}

Here is a picture of how information is stored in TXT and the screen where the graphic will show.

Sorry for English I'm using google translator.
Thank you.

Moderator edit: CODE TAGS

temperatura = // Float of buf[ i ] //

The missing function is atof(), but in order to use it, you need to NULL terminate buf (and you pass the whole array to the function, not one element of the array).

Adding the NULL terminator means that buf needs to be bigger.

Hello!
If I use atof (buf); It converts only the first value of the TXT.
Grateful.
Fernando Garcia

If I use atof (buf); It converts only the first value of the TXT.

Post the modified code.

Hello!

Here are the code and eos the results obtained with the implementation of it.

Thank you.
Fernando Garcia

That's all you're asking the program to do! Try:

for (uint8_t i = 0; i < n; i++)
{  temperatura = atof(buf);
   Serial.println(temperatura);
}

That's all you're asking the program to do! Try:

That won't work.

OP: You are now asking the SD card file for 6 characters are a time, not the 5 that you were asking it for. You need to re-write the code that reads the data from the file, to read one byte at a time, until it finds the carriage return and/or line feed. Store the data in the next position in the array, until the character read is a carriage return or line feed. When you find a carriage return or line feed, discard it, add a NULL terminator, and, if the string length is greater than 0, call atof() and store the result.

Hello!
How do I get is drawn only one pixel for each value of the buf by varying the cordenanda x because of the way it is written it draws several pixels for each value of buf forming a line.

Thank you.

How do I get is drawn only one pixel for each value of the buf by varying the cordenanda x because of the way it is written it draws several pixels for each value of buf forming a line.

We'd need to see more of your code, posted here using the # icon, NOT as a screen shot.

void tempgScreen()
{
  int x, y, z, grafico, hora;
  int16_t n;
  char buf[7];
  float temperatura;
  
  file.open(&root, "LOGTDIA.TXT", O_READ);
while ((n = file.read(buf, sizeof(buf))) > 0)
{
  
hora = (t.hour*60)+t.min;

temperatura = atof(buf);

if ((temperatura) < 22.5)
{
grafico = 190;
}
else if ((temperatura) >27.5)
{
grafico =30;
}
else
{
grafico = (190-((temperatura-22.5)*30));
}

for (uint8_t j=0; j <=(hora/6) ;j++)
{
setFont(SMALL, 255, 0, 255, 0, 0, 0);
myGLCD.drawPixel((40+j),grafico);
}

}
if ((temperatura) < 22.5)

Why are there parentheses around tempartatura?

How do I get is drawn only one pixel for each value of the buf

You have several problems. First, and foremost:

  char buf[7];

defines an array that can hold 7 characters.

while ((n = file.read(buf, sizeof(buf))) > 0)

sizeof(buf), therefore, returns 7, so you are asking the file.read() function to move 7 characters into buf.
The records in the file are arranged in a stream, containing
nn.nnnn.nnnn.nn...
So, for the first call, you are asking for "nn.nnn" to be read. Then, you are asking for "n.nnnn". Then, "nnnn.".

It should be apparent that this is NOT what you want to do. If you are absolutely positive that there will always be exactly two characters, a decimal point, exactly 2 characters, a carriage return and a line feed, in repeating patterns, then hardcode a length of 7 for the number of bytes to read. Do NOT make it a function of the size of the array.

Then, make the array large enough to those 7 characters (it already is, so this is handled).

Finally, make the array be NULL terminated, by replacing the carriage return (the 6th value read) with a NULL.

buf[5] = '\0';

Now, you have a string, which is what the atof() function expects.

Then, you have this:

hora = (t.hour*60)+t.min;

I have no idea what t is, but there is no other code that references t, so the value of t.hour and t.min do not change while you are reading the file, so the value of hora never changes. Therefore, this code belongs before the while loop that reads the file.

Finally, you have

for (uint8_t j=0; j <=(hora/6) ;j++)
{
setFont(SMALL, 255, 0, 255, 0, 0, 0);
myGLCD.drawPixel((40+j),grafico);
}

Which draws a line by lighting up a series of pixels. If your goal is to light just one pixel, why is the drawPixel() function called in a loop?

Hello!

Why are there parentheses around tempartatura?

Just why I forgot to pull out when I changed the code.

Finally, make the array be NULL terminated, by replacing the carriage return (the 6th value read) with a NULL.

When I changed from buf [6] to buf [7] the code passed to return the correct values with 2 houses before and 2 after the decimal point.

I have no idea what t is, but there is no other code that references t, so the value of t.hour and t.min do not change while you are reading the file, so the value of hora never changes. Therefore, this code belongs before the while loop that reads the file.

t=rtc.getTime();
This is necessary because I want is designed only to the printer and the current time.

Which draws a line by lighting up a series of pixels. If your goal is to light just one pixel, why is the drawPixel() function called in a loop?

The intent is to be drawn one pixel for each output value of buf.
Example to the values shown in the image above txt:

For temperature = 26.62, 26.69, 26.69, 26.69, 26.31

The function calls
myGLCD.drawPixel(X,Y);

grafico = (190-((26.62-22.5)*30)); // grafico =66
grafico = (190-((26.69-22.5)*30)); // grafico =64
grafico = (190-((26.69-22.5)*30)); // grafico =64
grafico = (190-((26.69-22.5)*30)); // grafico =64
grafico = (190-((26.31-22.5)*30)); // grafico =75

I want it to be drawn.
myGLCD.drawPixel(40,66);
myGLCD.drawPixel(41,64);
myGLCD.drawPixel(42,64);
myGLCD.drawPixel(43,64);
myGLCD.drawPixel(44,75);
.
.
.

Thank you.
Fernando Garcia

Hello!
Can someone help me?

Thank you.
Fernando Garcia

Can someone help me?

We offer advice. You ignore it. So, no, I don't think so.

Hello Paul!
I did not ignore your help. I answered their questions but appeared several other topics and I stayed brings. So I posted a request for help again.
If you can help me also be very grateful.

So, post the code where you are properly reading data from the card.

PaulS:
So, post the code where you are properly reading data from the card.

void tempgScreen()
{
  t=rtc.getTime();
  int x, y, z, grafico, hora;
  int16_t n;
  char buf[7];
  float temperatura;
  
  file.open(&root, "LOGTDIA.TXT", O_READ);
while ((n = file.read(buf, sizeof(buf))) > 0)
{
  
hora = (t.hour*60)+t.min;

temperatura = atof(buf);

if ((temperatura) < 22.5)
{
grafico = 190;
}
else if ((temperatura) >27.5)
{
grafico =30;
}
else
{
grafico = (190-((temperatura-22.5)*30));
}

for (uint8_t j=0; j <=(hora/6) ;j++)
{
setFont(SMALL, 255, 0, 255, 0, 0, 0);
myGLCD.drawPixel((40+j),grafico);
}

}

That is exactly why I say that you are NOT listening. That code does NOT properly read data from the card.

  char buf[7];

This creates an array that can hold 7 characters.

while ((n = file.read(buf, sizeof(buf))) > 0)

This gets 7 characters from the file, and puts them in the array. There is now no room for a terminating NULL.

temperatura = atof(buf);

This function expects a NULL terminated array of chars, which is NOT what you are passing it.

If you start at the top of this thread, I've told you this before. I've told you that you need to fix it.

Now, I'll try one more time, telling you HOW.
while ((n = file.read(buf, sizeof(buf)-1)) > 0) // Read SIX characters from the file
buf[6] = '\0'; // Append a NULL.

Now, the call to atof will behave as expected, and you can define grafico, based on the output of atof().

I want it to be drawn.
myGLCD.drawPixel(40,66);
myGLCD.drawPixel(41,64);
myGLCD.drawPixel(42,64);
myGLCD.drawPixel(43,64);
myGLCD.drawPixel(44,75);

Where does the first value come from?

Where does the first value come from?

for (uint8_t j=0; j <=(hora/6) ;j++)
{
setFont(SMALL, 255, 0, 255, 0, 0, 0);
myGLCD.drawPixel((40+j),grafico);
}

PaulS:
You have several problems. First, and foremost:

  char buf[7];

defines an array that can hold 7 characters.

while ((n = file.read(buf, sizeof(buf))) > 0)

sizeof(buf), therefore, returns 7, so you are asking the file.read() function to move 7 characters into buf.
The records in the file are arranged in a stream, containing
nn.nnnn.nnnn.nn...
So, for the first call, you are asking for "nn.nnn" to be read. Then, you are asking for "n.nnnn". Then, "nnnn.".

Hey PaulS, I count 7 characters here - "nn.nn" :slight_smile:

But the array should definitely be 8 characters long so the OP can null terminate the string.