New to Arduino - help converting float

I’m new to arduino programming and my background is in JavaScript.

I’m reading voltage from a sensor on input A2. I need to pass this data into ble_write(unsigned char *).

My question is, how can I convert or cast the voltage float to a value I can send through ble_write? Also, it ‘appears’ ble_write() can only accept one character at a time. Do I need to loop through the digits?

Any help or suggestions will be greatly appreciated, thanks!

  // custom read the input on analog pin 0:
  int sensorValue = analogRead(A2);
  float voltage = sensorValue * (5.0 / 1023.0);
  Serial.println(voltage);
  
  if ( ble_connected() )
  {
    ble_write('t'); // this works
    ble_write(voltage); // this does not work
  }
ble_write((unsigned char*) &voltage);
ble_write('t'); // this works

But that isn't an "unsigned char*"

my background is in JavaScript.

Don't worry - you can still be saved.

Look at dtostrf() for help.

void setup() {
  char buff[10];
  Serial.begin(115200);

  int sensorValue = 512;
  float voltage = (float) sensorValue * (5.0 / 1023.0);
  Serial.println(voltage);
  dtostrf(voltage, 8, 6, buff);
  Serial.println(buff);
  
}

void loop() {}

If you need to send it one byte at a time, try:

int index = 0;
while (buff[index]) {
   ble_write( buff[index++]);
}

I haven't tested the code, but it should work.

thanks econjack!

Why does passing 3.13 into dtostrf give me 3.128055? Is the original float just rounding it up to 3.13, but still storing the original value?
before: 3.13
after: 3.128055

ble_write(unsigned char *).

why would you assume this function only processes a single char at a time ?

If the function really did process a single char at a time, it would use a single byte char argument, not a pointer to a single char, which would take two bytes.

It is much more plausible that the argument to this function is the address of the first element of an array of chars.

@joelzyla: floating point numbers have a number of limitations. First, a float for the Arduino IDE is a 4 byte value, so its accuracy only extends to the first 6 or 7 digits even though it can "represent" a number with 38 digits. Alas, the first 6-7 are probably spot on and the remaining 32 are the computer's best approximation of the actual value.

Second, some numbers cannot be represented accurately in binary, such as 1/3. If you don't want to exceed a float's precision in your answer, you can specify what you want with the width and precision parameters that are passed to dtostrf(). Unfortunately, the choice of terms is a little misleading for the function. In this case, width refers to the minimum field width of the number being represented while precision is the number of places after the decimal point.

@michinyon, I'm not sure, but I can only pass 1 character into the function. For example, if I pass 'hi' into it, I only get 'h' on the other end. If I pass 'buff' into it, I only get the first digit. Maybe I am misunderstanding something here.

@econjack, that makes sense. But what I don't understand, is if a float can extend to 6 or 7 digits, why do I only get 3.13 when I log it? And how are the remaining digits preserved before I pass the float into dtostrf()?

Thanks for the help, everyone!

When I pass 3.13 to dtostrf() in my sample program, it comes back as 3.130000. I would suggest that you print out the value of both sensorValue and voltage to see what their values are.

That's why I'm confused. It's like the float voltage is only printing 3.13, but actually holds a larger number. I'm printing voltage before passing into dtostrf().

results:
voltage: 3.13
buff: 3.128055

And thanks, econjack, the while loop worked like a charm.

    int index = 0;
    while (buff[index]) {
      ble_write(buff[index++]);
    }
 float voltage = sensorValue * (5.0 / 1023.0);
  Serial.println(voltage);
  
  // convert double value to char
  dtostrf(voltage, 8, 6, buff);
    
  // print char voltage
  Serial.println(buff);

Log:

Looping!
3.11
3.113392
Looping!
3.11
3.113392
Looping!
3.11
3.108504
Looping!
3.11
3.108504

I'd have to look at the code for the Serial object's println() method, but it appears that it rounds to the nearest digit in a default field of 2 decimal places for floating point numbers.

thanks for the help!

From what I can google, I believe that it is

ble_write(unsigned char)/code]

You can send ASCII or binary data, it is up to the application at the other end to process it appropriately.

Why does the OP say this

I need to pass this data into ble_write(unsigned char *).

?

@AWOL, I guess what I read on a couple forums was wrong, and I was having trouble finding any documentation. Not sure why some forums list the function as ble_write(unsigned char *). Maybe it's changed since then, no idea. Thanks! raywenderlich.com Forums

@michinyon, I’m not sure, but I can only pass 1 character into the function. For example, if I pass ‘hi’ into it, I only get ‘h’ on the other end. If I pass ‘buff’ into it, I only get the first digit. Maybe I am misunderstanding something here.

You are completely confused.

Firstly, in C/C++, a character surrounded by single quotes is a single character. One character. Like ‘a’ or ‘B’ or ‘Q’. ‘hi’ is two characters, it is simply invalid in C/C++ and I am surprised the compiler accepts it.

For a sequence of characters, you use double quotes, like “hi”. This represents either an array of single char values, or an object of the String class. In the case of the array, the array must actually have three bytes in it, because the array of char values has to have an extra byte with 0x00 in it at the end.

The construct unsigned char* refers to a value which is a pointer. It represents the address ( memory location ) of a char value, or the address of the first item in an array of char values.

You can call a function with a value which is the value of a character. Or, you can call a function with a value which is the memory address of where one or more chars are stored in memory. These are two quite different things in C/C++, and you need to understand the difference.

The type “unsigned char” make very little sense if the value is to be used as an actual character and not as a single-byte integer.

Your function ble_value( unsigned char* ) requires an argument which is the address of a char, or more usually, the address of the first element of an array of chars.

Providing an actual single char value to this function would actually be wrong - unless there is also defined another function with the same name which takes a single char value.

The correct way to call this function would be something like

char myname[] = "awol" ;     // this creates an array of 5 bytes

ble_value (  myname ) ;                          //  the normal way
ble_value ( &myname[0] ) ;                  //  the very explicit way
ble_value( &myname[1] );                      //  this will print "wol"

'hi' is two characters, it is simply invalid in C/C++

No, it really isn't.