Conversion of double to String using "String"

Hi, I am trying to convert a double value obtained from the library of Emon which i have running at home. https://github.com/openenergymonitor/MainsACv3/blob/master/EmonLib/Emon.cpp

the code i am using is this, using the tutorial of sciguy on youtube which works perfectly (when not using doubles)

As you can see below I need to save a line with unixtime stamp obtained from an RTC clock, then with comma separated also have apparentPower, realPower, powerfactor, Vrms, Irms... which are all doubles
So it will end up something like this...

//unixtime;apparentpower;realpower;Voltage;Current;powerfactor
1315255517;2371.16;2012.23;230;8.21;0.95

The code below WORKS, but as soon as I add any extra info on the String dataString, then the line gets corrupted and arduino restarts.
So I guess the conversion from double to string is not working correctly.

Please help me out, I really appreciate.

void saveSD(){
// Get time information in "now" to use later
  DateTime now = RTC.now();
  
//************ convert double to String ***************  
  char charapparentPower[16];
  dtostrf( emon.apparentPower, 4, 2, charapparentPower );
//***************************

// Create the String that will be output to Serial port and saved to SD card.
String dataString = String(now.unixtime()) + ";" + String(charapparentPower); //230;0.95;1;45";    


  //Open a file to write to
  //Only one file can be open at a time
  File dataFile = SD.open("loga.txt", FILE_WRITE);
        if(dataFile)
        {
          dataFile.println(dataString);
          dataFile.close();
          Serial.println(dataString);
        }
        else
        {
          Serial.println("Couln't access file");
        }
}

btw, I forgot to mention I am using the official ethernet shield for the SD. But as I said its working perfectly when only a string such as the one below is used

// String dataString = " Hello ethernet";

so basically, this is the aim of the question

//************ convert double to String ***************  
  char charapparentPower[16];
  dtostrf( emon.apparentPower, 4, 2, charapparentPower );
//***************************

// Create the String that will be output to Serial port and saved to SD card.
String dataString = String(now.unixtime()) + ";" + String(charapparentPower); //230;0.95;1;45";

The code below WORKS, but as soon as I add any extra info on the String dataString, then the line gets corrupted and arduino restarts.

Can be anything but what comes in mind first is an out of memory error, but I cannot see your whole code.

hi, please let me know what do you need to evaluate?
The rest of the code does not uses all memory, after compiling

Binary sketch size: 22858 bytes (of a 32256 byte maximum)

Is that what you are refering to?

thank you a lot

That is program memory, not RAM. They are different. You have 2 Kb of RAM on an Atmega328.

The String library is known to gobble up memory under certain circumstances. You could use sprintf instead.

Hello Nick,
thanks for that.
My Sketch uses the following libraries: (wdt.h, wire.h, rtclib.h,sd.h and the emon.h I mention in the first post) could that mean i am using all memory? Is there a way to look it up?

What i dont understand is that it seems to do the right job with the conversion but makes all the program very unstable. So could it be because of the memory?

So would this be a better method?

 char charapparentPower[32];
 float apparentPower = 1234.14;
 int apparentPowerdecimals = (apparentPower - (int)apparentPower ) * 100;
 sprintf(ascii,"The Value is: %0d.%d", (int)apparentPower , apparentPowerdecimals);

instead of

//************ convert double to String ***************  
  char charapparentPower[16];
  dtostrf( emon.apparentPower, 4, 2, charapparentPower );
//***************************

If you hold down the "shift" key when you compile your code, the IDE will tell you where it put all the files.
Go to that directory, and run "avr-objdump -h" on the ".elf" file
Look at the size of the ".bss" and ".data" segments.

AWOL:
If you hold down the "shift" key when you compile your code, the IDE will tell you where it put all the files.
Go to that directory, and run "avr-objdump -h" on the ".elf" file
Look at the size of the ".bss" and ".data" segments.

wow when i first read your answer sounded like chinese to me hehe, managed to figure it out, just in case it is usefull for others cause i had no idea about how to do this...

open cmd window
find the avr-objdump located in your arduino folder and go to it inside the cmd
find the .elf file using the shift method described
do:
C:\arduino-0022\hardware\tools\avr\bin>avr-objdump -h C:\Users\name\AppData\Local\Temp\build5056369074338823503.tmp\v21_1_sketch_beta_SD.cpp.elf

and this is what i get

 2 .bss          00000473  00800378  00800378  00005140  2**0
                 ALLOC

And what about the ".data" segment?

(.data contains initialised globals, like tables, .bss contains unitialised global variables)

sorry i should have copied all

Sections:
Idx Name Size VMA LMA File off Algn
0 .data 00000236 00800100 00005714 000057a8 20
CONTENTS, ALLOC, LOAD, DATA
1 .text 00005714 00000000 00000000 00000094 2
1
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .bss 00000471 00800336 00800336 000059de 20
ALLOC
3 .debug_aranges 00000958 00000000 00000000 000059de 2
0
CONTENTS, READONLY, DEBUGGING
4 .debug_pubnames 00001992 00000000 00000000 00006336 20
CONTENTS, READONLY, DEBUGGING
5 .debug_info 000158aa 00000000 00000000 00007cc8 2
0
CONTENTS, READONLY, DEBUGGING
6 .debug_abbrev 0000344d 00000000 00000000 0001d572 20
CONTENTS, READONLY, DEBUGGING
7 .debug_line 000078e9 00000000 00000000 000209bf 2
0
CONTENTS, READONLY, DEBUGGING
8 .debug_frame 00001090 00000000 00000000 000282a8 22
CONTENTS, READONLY, DEBUGGING
9 .debug_str 000045ae 00000000 00000000 00029338 2
0
CONTENTS, READONLY, DEBUGGING
10 .debug_loc 00006650 00000000 00000000 0002d8e6 20
CONTENTS, READONLY, DEBUGGING
11 .debug_ranges 000009c0 00000000 00000000 00033f36 2
0
CONTENTS, READONLY, DEBUGGING

Hmm, 1703 bytes doesn't look too bad.
Maybe you're running off the end of a buffer someplace else.
Difficult to say, without seeing what is presumably quite a lot of code.

So I guess the conversion from double to string is not working correctly.

Why not Serial.print() the string, and see?

Why is it so important that you concatenate everything into a single String to write to the file?

  File dataFile = SD.open("loga.txt", FILE_WRITE);
  if(dataFile)
  {
     dataFile.print(now.unixtime());
     dataFile.print(";");
     datafile.println(charapparentPower);
     dataFile.close();
     Serial.println(dataString);
  }
  else
  {
     Serial.println("Couln't access file");
  }

performs the same operation, without all the overhead and memory wasting that the String class brings to the party.

haha Paul a few minutes ago, before reading your message I figured the same thing and was just right now testing that it works much better.
I guess the solution is to do it separately, but I also wanted to know why is was not working in order to understand what the problem was and maybe it can be usefull for other situations. (as in the LCD post you helped me out not long ago)

thank you for your time!!

ps. it would still be nice to know why dtostrf is having trouble :frowning:

Re: The video tutorial.
If SD card initialisation fails, print a message and "return" (from "setup"), then fall into "loop", and write a string to the device you just failed to initialise.

Novel approach.

I sometimes wish the String genie hadn't been let out of the bottle :frowning:

it would still be nice to know why dtostrf is having trouble

You seem to be having issues concatenating three strings - the one returned by now.unixtime() converted to a String, the ";", and the string created by dtostrf(). Yet you persist in blaming the problem on dtostrf(), even though:

was just right now testing that it works much better.

So, if you are able to write the string created by dtostrf() to the SD card, then the problem is not with dtostrf(). It is with the String class, or how you are using it, or with the fact that you are running out of memory.

PaulS:

it would still be nice to know why dtostrf is having trouble

You seem to be having issues concatenating three strings - the one returned by now.unixtime() converted to a String, the ";", and the string created by dtostrf(). Yet you persist in blaming the problem on dtostrf(), even though:

was just right now testing that it works much better.

So, if you are able to write the string created by dtostrf() to the SD card, then the problem is not with dtostrf(). It is with the String class, or how you are using it, or with the fact that you are running out of memory.

Sorry I did not express myself clear on the last one.
I am doing this now...

  File dataFile = SD.open(filename, FILE_WRITE);  //"logd.txt"
        if(dataFile)
        {
          dataFile.print(now.unixtime());dataFile.print(";");
          dataFile.print(emon.apparentPower);dataFile.print(";");
          dataFile.print(emon.realPower);dataFile.print(";");
          dataFile.print(emon.Vrms);dataFile.print(";");
          dataFile.print(emon.Irms);dataFile.print(";");
          dataFile.print(emon.powerFactor);dataFile.print(";");
          dataFile.print(statusservidor);dataFile.print(";");
          dataFile.print(percentage);
          dataFile.println();
          dataFile.close();
          Serial.println("done");
        }
        else
        {
          Serial.println("Couln't access file");
        }

and is working, but this does not involve the dtostrf() at all.
I wish I could see where the problem was so I understand better everthing.

I still belief the problem is the dtostrf cause i am able to concatenate more the 3 strings, but not if the result of dtostrf is one of them.
any idea?
as always, thanks a lot