I am reading data from a humidity sensor via the I2C interface of an Arduino Uno. I am getting the data as a u16 which works fine. Now I want to convert that u16 raw data to the actual humidity. This would look something like this:
let humidity_raw: u16 = 0x3fff; // that would be 100 % rel. humidity
let humidity: f32 = (humidity_raw as f32) * 100.0 / 16383.0;
Now I have problems writing the humidityf32 value to the serial port. I am currently using the ufmt crate which does not support formatting of floats:
ufmt::uwriteln!(&mut serial, "humidity: {}", humidity).void_unwrap();
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `uDisplay` is not implemented for `f32`
Is there an alternative for the ufmt crate? I also tried to get the whole part and the fractional part from the humidity value separately but I did not come up with a trivial solution.
fmt::write(&mut serial, format_args!("humidity = {} %\n", humidity));
^^^^^^^^^^^ the trait `core::fmt::Write` is not implemented for `Usart0<MHz16, Floating>`
From there I have no idea what to do
Do I have to implement the traits?
I also took a look at dtoa but unfortunately it uses std which is not available to me.
Just like println!() for printing formatted text to stdout, you can use writeln!(&mut serial, "humidity = {} %", humidity) to write to the serial port.
This requires bringing core::fmt::Write into scope and assumes your serial implements it.
You can't use std::io::Write in a #[no_std] program.
I'm guessing the Usart0 peripheral actually implements embedded_hal::blocking::serial::Write, so you'll need to write the message to a temporary buffer then write it to the serial device from there.
Okay, I partly solved my problem with the ufmt_float crate which let's me do pre-formatting in the form of
let myfloat: f32 = 1.2345;
let myfloat_write = uFmt_f32::Three(myfloat);
ufmt::uwriteln!(&mut serial, "{}", myfloat_write);
--> prints 1.234
This works!
But! Now I've got another problem. Converting values from u16 to f32 always gives 0.0. Here is the code I've got:
let myint: u16 = 0x1a86;
let myfloat = myint as f32;
let myfloat_write = uFmt_f32::Three(myfloat);
ufmt::uwriteln!(&mut serial, "{}", myfloat_write).void_unwrap();
--> prints 0.000
What is going on here? Is the compiler playing tricks with me?
Also this nullification seems kind of arbitrary. Compare the two snippets:
let myint: u16 = 0x1a86;
let myfloat: f64 = myint as f64;
let myfloat_write = uFmt_f64::Three(myfloat);
ufmt::uwriteln!(&mut serial, "myfloat_write: {}", myfloat_write).void_unwrap();
--> prints 6790.000
let humidity_raw: u16 = 0x000a;
let hum_float = humidity_raw as f32;
let hum_write = uFmt_f32::Three(hum_float);
ufmt::uwriteln!(&mut serial, "hum_write f32: {}", hum_write).void_unwrap();
--> prints 10.000
but changing the variables to f64 in the lower block results in zeros everywhere:
let myint: u16 = 0x1a86;
let myfloat: f64 = myint as f64;
let myfloat_write = uFmt_f64::Three(myfloat);
ufmt::uwriteln!(&mut serial, "myfloat_write: {}", myfloat_write).void_unwrap();
--> prints 0.000
let humidity_raw: u16 = 0x000a;
let hum_float = humidity_raw as f64;
let hum_write = uFmt_f64::Three(hum_float);
ufmt::uwriteln!(&mut serial, "hum_write f64: {}", hum_write).void_unwrap();
--> prints 0.000