Register formulas¶
A datasheet writes a temperature register as
\[
T = \frac{\text{raw}}{256} + 25\ ^\circ\text{C}
\]
That is a point against an origin 25 K above 0 °C, in steps of \(1/256\) K. Declare the origin once, and the raw register value is the field's type.
use exact_units::{Fixed, Offset, Point, origin, origins::Celsius, prefix::{Centi, Rational}, units::Kelvin};
origin! {
/// The LSM6DS temperature register: raw / 256 + 25 °C.
pub struct Lsm6dsTemp { above: Celsius, offset: Offset::int(25) }
}
type Lsm = Point<Lsm6dsTemp, Fixed<Kelvin, Rational<1, 256>, i16>>;
assert_eq!(Lsm::from_raw(128).to_string(), "25.5 °C");
assert_eq!(Lsm::from_raw(64).to::<Celsius, Centi, i16>().map(|p| p.raw()), Some(2525));
above: Celsiustakes the unit, the reference and the display of °C and adds the offset.- The conversion to 0.01 °C is \(\text{raw} \cdot 100 / 256 + 2500\), by constants, checked to be whole.
- On the wire it is the register's
i16, nothing else.
Bus formulas¶
CAN and J1939 signals are written the same way, an offset and a step:
use exact_units::{Fixed, Offset, Point, origin, origins::Celsius, prefix::One, units::Kelvin};
origin! {
/// J1939 engine coolant temperature (SPN 110): 1 °C per bit, −40 °C offset.
pub struct J1939Temp { above: Celsius, offset: Offset::int(-40) }
}
type Coolant = Point<J1939Temp, Fixed<Kelvin, One, u8>>;
assert_eq!(Coolant::from_raw(130).to::<Celsius, One, i16>().map(|p| p.raw()), Some(90));
Pressure against the ambient¶
A gauge pressure is measured against the air around it, which is known only at run time. Gauge and Vacuum have different references, so they don't convert at compile time; against takes the ambient: