1个不稳定版本
0.1.0 | 2020年11月19日 |
---|
#1404 in 嵌入式开发
26KB
192 行
hal_sensor_dht
使用嵌入式-hal接口的Rust DHT驱动程序。
DHT数字湿度温度传感器的接口。
设计
本库的设计灵感来源于
- Adafruit DHT cpp 代码
- dht-hal-drv 库
- dht-hal 库
- dht-sensor 库
- dht22_pi 库
所有这些库以及这个库基本上是相同的,只是接口略有不同。
代码已在DHT22传感器、Raspberry Pi 3B和rppal上进行了测试。
问题
此库利用了embedded-hal库提供的特制。遗憾的是,嵌入式-hal中仍有很多东西缺失,例如可重新配置的GPIO的特制和禁用中断。因此,应预期这个库会随着时间的推移而改变。
用法
要创建DHT传感器的驱动程序,调用者必须提供以下项目
- 一个GPIO引脚,该引脚实现了
InputPin
和OutputPin
特制,并属于embedded-hal
。此外,它应该能够重新配置引脚(从输出到输入)。遗憾的是,这目前不是embedded-hal
的一部分,因此需要实现此库中的特制。 - 一个提供
DelayMs
和DelayUs
特制的计时器。 - 在读取信号线时需要抑制中断。此库提供了一个简单的特制
InterruptCtrl
用于此目的。
示例:在Raspberry Pi上使用库
实现GPIO接口。
您可以使用rppal
来控制GPIO引脚。然而,由于外部结构外部特制的“孤儿”规则,需要实现包装器。
extern crate rppal;
use rppal::gpio::{Gpio, Mode, PullUpDown};
extern crate hal_sensor_dht;
use hal_sensor_dht::{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 = <rppal::gpio::IoPin as InputPin>::Error;
fn is_high(&self) -> Result<bool, <rppal::gpio::IoPin as InputPin>::Error> {
Ok(self.0.is_high())
}
fn is_low(&self) -> Result<bool, <rppal::gpio::IoPin as InputPin>::Error> {
Ok(self.0.is_low())
}
}
impl OutputPin for MyPin {
type Error = <rppal::gpio::IoPin as OutputPin>::Error;
fn set_high(&mut self) -> Result<(), <rppal::gpio::IoPin as OutputPin>::Error> {
Ok(self.0.set_high())
}
fn set_low(&mut self) -> Result<(), <rppal::gpio::IoPin as OutputPin>::Error> {
Ok(self.0.set_low())
}
}
impl hal_sensor_dht::IoPin for MyPin {
fn set_input_pullup_mode(&mut self) {
self.0.set_mode(Mode::Input);
self.0.set_pullupdown(PullUpDown::PullUp);
}
fn set_output_mode(&mut self) {
self.0.set_mode(Mode::Output);
}
}
实现延迟接口。
DelayMs
没有问题,但微秒级延迟有。但是,只需要非常小的延迟,因此我们使用写入和读取操作来产生这种小延迟。
use std::thread;
use std::time::Duration;
use rppal::gpio::{Gpio, Mode, PullUpDown};
use std::ptr::read_volatile;
use std::ptr::write_volatile;
struct MyTimer {}
impl DelayUs<u16> for MyTimer {
fn delay_us(&mut self, t:u16) {
let mut i = 0;
unsafe {
while read_volatile(&mut i) < t {
write_volatile(&mut i, read_volatile(&mut i) + 1);
}
}
}
}
impl DelayMs<u16> for MyTimer {
fn delay_ms(&mut self, ms: u16) {
thread::sleep(Duration::from_millis(ms.into()));
}
}
禁用中断。
您将使用 sched_setscheduler
从 libc
库中用于此目的。这足以读取传感器数据。
extern crate libc;
use libc::sched_param;
use libc::sched_setscheduler;
use libc::SCHED_FIFO;
use libc::SCHED_OTHER;
struct MyInterruptCtrl {}
impl hal_sensor_dht::InterruptCtrl for MyInterruptCtrl {
fn enable(&mut self) {
unsafe {
let param = sched_param { sched_priority: 32 };
let result = sched_setscheduler(0, SCHED_FIFO, ¶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");
}
}
}
}
整合所有内容
好吧,终于完成了!以下是主函数的示例代码。请注意,在两次调用 read
函数之间应该有一个延迟。您每次调用该函数时并不总是能得到有效结果。但这对监控您房间的温度应该足够好了。
fn main() {
let pin_number = 12;
if let Ok(gpio) = Gpio::new() {
if let Ok(pin) = gpio.get(pin_number) {
let my_pin = MyPin::new(pin);
let my_timer = MyTimer{};
let my_interrupt = MyInterruptCtrl{};
let mut sensor = DHTSensor::new(SensorType::DHT22, my_pin, my_timer, my_interrupt);
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!")
}
}
依赖项
对于此示例,您需要 libc
库,rppal
库,embedded-hal
库,当然还有这个库!
[dependencies]
libc = "0.2.21"
[dependencies.hal_sensor_dht]
path = "../hal_sensor_dht"
features = ["floats"]
[dependencies.embedded-hal]
version = "0.2.4"
features = ["unproven"]
[dependencies.rppal]
version = "0.11.3"
features = ["hal", "hal-unproven"]
依赖项
~71KB