A Rust DHT driver using embedded-hal interfaces.
An interface to the DHT Digital Humidity and Temperature sensors.
The design of this crate is inspired by: - The Adatfruit DHT cpp code - The dht-hal-drv crate - The dht-hal crate - The dht-sensor crate - The dht22_pi crate
All of these libraries and also this library are basically the same, only the interfaces are a little different.
The code has been tested with DHT22 sensor, a Raspberry Pi 3B, and the rppal.
This library makes use of the traits provided by the embedded-hal crate. Unfortunately, a lot of stuff is still missing in embedded-hal, such as traits for reconfigurable GPIOs and disabling interrupts. Therefore it should be expected that this library will be change over time.
To create a driver for the DHT sensor, the caller have to provide the
following items:
- a GPIO pin, which implements the InputPin
and OutputPin
traits of embedded-hal
.
Additionally, it should be able to reconfigure the pin (from output to input).
Unfortunately, this is currently not part of embedded-hal
, so the trait from
this crate needs to be implemented.
- a timer providing the DelayMs
and DelayUs
traits.
- interrupts need to be suppressed while we are reading the signal line.
This crate provides a simple trait InterruptCtrl
for this purpose.
You can use rppal
to control the GPIO pin.
However, a wrapper needs to be implemented because of the "orphan" rule for
implementation of external traits for external structs.
``` extern crate rppal; use rppal::gpio::{Gpio, Mode, PullUpDown}; extern crate halsensordht; use halsensordht::{DHTSensor, SensorType};
struct MyPin(rppal::gpio::IoPin);
impl MyPin { pub fn new(pin: rppal::gpio::Pin) -> MyPin { MyPin(pin.into_io(Mode::Input)) } }
impl InputPin for MyPin {
type Error =
impl OutputPin for MyPin {
type Error =
impl halsensordht::IoPin for MyPin { fn setinputpullupmode(&mut self) { self.0.setmode(Mode::Input); self.0.setpullupdown(PullUpDown::PullUp); } fn setoutputmode(&mut self) { self.0.setmode(Mode::Output); } } ```
The DelayMs
is no problem, but microsecond delay is. However, only need a
a tiny delay, therefore we use write and read operation to produce such small
delay.
``` use std::thread; use std::time::Duration; use rppal::gpio::{Gpio, Mode, PullUpDown};
use std::ptr::readvolatile; use std::ptr::writevolatile; struct MyTimer {}
impl DelayUs
impl DelayMs
You will use sched_setscheduler
from the libc
crate for this purpose.
This is good enough for reading the sensor data.
``` extern crate libc; use libc::schedparam; use libc::schedsetscheduler; use libc::SCHEDFIFO; use libc::SCHEDOTHER;
struct MyInterruptCtrl {}
impl halsensordht::InterruptCtrl for MyInterruptCtrl { fn enable(&mut self) { unsafe { let param = schedparam { schedpriority: 32 }; let result = schedsetscheduler(0, SCHEDFIFO, ¶m);
if result != 0 {
panic!("Error setting priority, you may not have cap_sys_nice capability");
}
}
}
fn disable(&mut self) {
unsafe {
let param = sched_param { sched_priority: 0 };
let result = sched_setscheduler(0, SCHED_OTHER, ¶m);
if result != 0 {
panic!("Error setting priority, you may not have cap_sys_nice capability");
}
}
}
} ```
OK, finally we are done! Here is some example code for the main function.
Keep in mind, that there should be a delay between two calls of the read
function.
You will not get a valid result every time, the function is called. But it
should be good enough to monitor the temperature of your room.
``` fn main() { let pinnumber = 12; if let Ok(gpio) = Gpio::new() { if let Ok(pin) = gpio.get(pinnumber) { let mypin = MyPin::new(pin); let mytimer = MyTimer{}; let myinterrupt = MyInterruptCtrl{}; let mut sensor = DHTSensor::new(SensorType::DHT22, mypin, mytimer, myinterrupt);
for _i in 0 .. 200 {
if let Ok(r) = sensor.read() {
println!("Temperature = {} / {} and humidity = {}",
r.temperature_celsius(),
r.temperature_fahrenheit(),
r.humidity_percent());
}
thread::sleep(Duration::from_secs(10));
}
} else {
println!("Error: Could not get the pin!")
}
} else {
println!("Error: Could not get the GPIOs!")
}
} ```
For this example, you need the libc
crate, the rppal
crate, the
embedded-hal
crate, and of cause this crate!
``` [dependencies] libc = "0.2.21"
[dependencies.halsensordht] path = "../halsensordht" features = ["floats"]
[dependencies.embedded-hal] version = "0.2.4" features = ["unproven"]
[dependencies.rppal] version = "0.11.3" features = ["hal", "hal-unproven"] ```