Byte to float to string (eventually)

Hi all,

Scenario: I've got some data coming from a battery operated sensor over RF, its all in bytes to minimise the payload.

One element of data is battery level, eg if battery is 3.94 its coming over as 94 in the byte (394-300 see?).

The destination is a template which only accepts text.

So what I need to do is convert the byte 94 to an int8_t, add back the 300 to make it 394 again, turn it into a float, divide by 100 so it becomes 3.94 then on to become a string ready for the template.

Has anyone seen a simple way of doing this? I know from when I was learning c that there are many tricky ways of getting things typecast, I was looking for a shortcut.

I realise this isn't strictly an Arduino problem, but I thought I'd share my problem here as it might be a common one.

Thanks for looking!

if your are doing all of that just to get the 'string' decimal value (ie ur not using the receive value for any calc before converstion to string then you could just simply do this:

sprintf(outstr,"3.%i",rx_val);

where 'outstr' is a char array and 'rx_val' is your received value.

so for example, if 'rx_val' = 94,

then 'outstr' would contain "3.94" as a c-string.

hope that helps...

2 Likes

Good point!

case: the input is 109 meaning an original reading of 4.09.

Lipo/lLons etc function between say, 3.20v and 4.2v - outside of those params they are deadish and not going to be reporting their status anyway.

Yeah, could use a conditional to detect whether input byte is 109 or 94, but this looks promising, will test it out tomorrow. Thank you for stopping by, thinking about the problem and taking the time to reply.

then this one line within your code should do! :wink:

sprintf(outstr,"%c.%02i",rx_val<100? '3':'4', rx_val<100? rx_val:rx_val-100);

hope that helps....

OK, that definitely helps, less typecasting more string manipulation. Good enough.

        if(rx_val>100)
          sprintf(outstr,"%c.%02i",'4', rx_val-100);
        else  
          sprintf(outstr,"%c.%02i", '3', rx_val);

The nested ternary sent the compiler into a bit of a spin, and the 8bit AVR I'm testing on wasnt too cool either - this is more readable to me. Thanks again!

To simplify a bit more:

    if (rx_val > 100)
      sprintf(outstr, "4.%02i", rx_val - 100);
    else
      sprintf(outstr, "3.%02i", rx_val);

An alternative method, although it takes more math so longer to execute:

    sprintf(outstr, "%i.%02i", (rx_val / 100) + 3, rx_val % 100);

Thanks, I'm thinking about this a bit more.

As the figure I can send is going to be an arbitrary one worked out on the uController using the usual voltage divider - I can pretty much send what I want in the way of a byte. If I work that out I will try and get back and post what my final solution is going to be, thanks all, this'll get me something working.

just proceed as you described

byte rxVal = 95;
float voltage = (300.0 + rxVal) / 100.0;

then you can you dtostrf()

char outStr[10];
dtostrf(voltage, 6, 2, outStr); // the 6 will generate some padding with spaces in front 

here is an example going through the 256 values of the byte

the code

void setup() {
  char outStr[10];
  byte rxVal = 0;

  Serial.begin(115200);
  do {
    float voltage = (300.0 + rxVal) / 100.0;
    dtostrf(voltage, 6, 2, outStr); // as the volatage is x.dd and we want 6 positions, we will have 2 spaces in front of the value
    Serial.print("rxVal = "); Serial.print(rxVal);
    Serial.print("\tvoltage = "); Serial.print(voltage, 2); // printing the float with 2 decimal
    Serial.print("\t\tvoltage string = \""); Serial.print(outStr); // printing the string
    Serial.println("\"");
  } while (++rxVal != 0);
}


void loop() {}

You'll get

rxVal = 0	voltage = 3.00		voltage string = "  3.00"
rxVal = 1	voltage = 3.01		voltage string = "  3.01"
rxVal = 2	voltage = 3.02		voltage string = "  3.02"
rxVal = 3	voltage = 3.03		voltage string = "  3.03"
rxVal = 4	voltage = 3.04		voltage string = "  3.04"
rxVal = 5	voltage = 3.05		voltage string = "  3.05"
rxVal = 6	voltage = 3.06		voltage string = "  3.06"
rxVal = 7	voltage = 3.07		voltage string = "  3.07"
rxVal = 8	voltage = 3.08		voltage string = "  3.08"
rxVal = 9	voltage = 3.09		voltage string = "  3.09"
rxVal = 10	voltage = 3.10		voltage string = "  3.10"
rxVal = 11	voltage = 3.11		voltage string = "  3.11"
•••
rxVal = 98	voltage = 3.98		voltage string = "  3.98"
rxVal = 99	voltage = 3.99		voltage string = "  3.99"
rxVal = 100	voltage = 4.00		voltage string = "  4.00"
rxVal = 101	voltage = 4.01		voltage string = "  4.01"
•••
rxVal = 253	voltage = 5.53		voltage string = "  5.53"
rxVal = 254	voltage = 5.54		voltage string = "  5.54"
rxVal = 255	voltage = 5.55		voltage string = "  5.55"

If nothing else in the code uses float, my preference would be to not use it for this in order to conserve memory. The code for handling floats and dtostrf() on an UNO increases the sketch size by around 1600 bytes.

Sure, if that’s a concern. I did not read that in the requirements.
If not that memory can be put to good use :wink:
Otherwise best is to keep only the byte and drive the code from there.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.