HX711
A platform agnostic driver to interface with the HX711 (load cell amplifier and 24 bit ADC)
Tested with STM32F103. Pull requests for other hardware welcome!
Because the interface works by toggling of GPIO pins, some care has to be taken. See below.
See here: https://github.com/jonas-hagen/hx711-examples
Incomplete appetizer: ```rust let mut val: i32 = 0;
let dout = gpioa.pa6.intofloatinginput(&mut gpioa.crl); let pdsck = gpioa.pa7.intopushpulloutput(&mut gpioa.crl);
let mut hx711 = Hx711::new(Delay::new(cp.SYST, clocks), dout, pdsck).intook();
// Obtain the tara value writeln!(tx, "Obtaining tara ...").unwrap(); const N: i32 = 8; for _ in 0..N { val += block!(hx711.retrieve()).into_ok(); // or unwrap, see features below } let tara = val / N; writeln!(tx, "Tara: {}", tara).unwrap(); ```
never_type
The never_type
feature can optionally be enabled when using nightly rust.
For some HALs, the digital input and output pins can never fail.
When using the driver with such a crate, one can use .into_ok()
on all results instead of .unwrap()
or .expect()
.
Example with e.g. STM32f1xx embedded hal: ```rust // Without never_type (stable rust): // We know that this never fails let weight = block!(hx711.retrieve()).unwrap())
// With nevertype (nightly rust) // It is obvious that this is always ok let weight = block!(hx711.retrieve()).intook() ```
The protocol is implemented using the GPIO interface because the HX711 needs a specific number of clock cycles to set the operation mode (25, 26 or 27 cycles). So, beware of interrupts during readout! The delays between state changes for clocking only need to be 0.1 µs (per HX711 specs), allowing to clock through all 24 cycles in approximately 5 µs. But the current embedded HAL does not support delays smaller than 1 µs (see embedded-hal #63 for the discussion). With a delay of 1 µs, the readout takes at least 48 µs. Depending on clock speed of the device, this increases to 300 µs in total (tested with STM32F103 at 8 MHz) or more. In a control loop, this might be undesirable and keeping the time closer to the 5 µs is compelling.
To tweak the performance, an alternative implementation of the delay trait can be used. For example:
```rust use embedded_hal::blocking::delay::DelayUs;
pub struct BusyDelay { nopsperus: u32, }
impl BusyDelay { pub fn new(loopsperus: u32) -> Self { BusyDelay{loopsperus: loopsperus as u32} } }
impl DelayUs
Or even:
```rust pub struct NoDelay();
impl NoDelay { pub fn new() -> Self { NoDelay() } }
impl DelayUs
Some random notes on this topic:
* Maybe add a nodelay
feature?
* It would be interesting to try to use SPI with MOSI as clock and MISO as data line, not using the actual SPI clock.
* How to make this work on linux? Any ideas?
get_mode
function. Thanks m-ou-se!never_type
behind feature for usage on stable rustenable()
and disable()
functions to enter and leave low-power mode..into_ok()
when using such HAL implementations.embedded-hal
digital pin v2 API. Thanks to mmou!Licensed under either of
at your option.