embassy_dht/
lib.rs

1/* usage
2 *  //for dht22
3 * use embassy_executor::Spawner;
4 * use defmt::*;
5 * use embassy_time::{Delay, Timer};
6 * use embassy_rp;
7 * use embassy_dht::dht22::DHT22;
8 *
9 * #[embassy_executor::main]
10 *   async fn main(_spawner: Spawner) {
11 *   info!("Hello World!");
12 *
13 *   let p = embassy_rp::init(Default::default());
14 *
15 *   info!("set up dhtxx pin");
16 *
17 *   let mut dht_pin = DHT22::new(p.PIN_22,Delay);
18 *
19 *   loop {
20 *      Timer::after_secs(1).await;
21 *      let dht_reading = dht_pin.read().unwrap();
22 *      let (temp, humi) = (dht_reading.get_temp(), dht_reading.get_hum());
23 *      defmt::info!("Temp = {}, Humi = {}\n", temp,humi);
24 *      ... the code what you write
25 *   }
26 *}
27 *
28 *  //for dht11
29 * use embassy_executor::Spawner;
30 * use defmt::*;
31 * use embassy_time::{Delay, Timer};
32 * use embassy_rp;
33 * use embassy_dht::dht11::DHT11;
34 *
35 * #[embassy_executor::main]
36 *  async fn main(_spawner: Spawner) {
37 *  info!("Hello World!");
38 *
39 *  let p = embassy_rp::init(Default::default());
40 *
41 *  info!("set up dhtxx pin");
42 *
43 *  let mut dht_pin = DHT11::new(p.PIN_22,Delay);
44 *
45 *  loop {
46 *      Timer::after_secs(1).await;
47 *      let dht_reading = dht_pin.read().unwrap();
48 *      let (temp, humi) = (dht_reading.get_temp(), dht_reading.get_hum());
49 *      defmt::info!("Temp = {}, Humi = {}\n", temp,humi);
50 *      ... the code what you write
51 *  }
52 *}
53 *
54*/
55
56#![no_std]
57
58use embassy_rp::gpio::{Flex, Pin};
59use embassy_rp::Peripheral;
60use embedded_hal::delay::DelayNs;
61use num_traits::float::FloatCore;
62#[cfg(feature = "embedded_alloc")]
63extern crate alloc;
64#[cfg(feature = "embedded_alloc")]
65use alloc::borrow::ToOwned;
66#[cfg(feature = "embedded_alloc")]
67use alloc::string::{String, ToString};
68
69#[derive(Debug, Copy, Clone)]
70pub struct Reading<T, H> {
71    pub temp: T,
72    pub hum: H,
73}
74
75const WAIT_STEP: u32 = 5;
76const MAX_WAIT: u32 = 100;
77
78fn wait_for_state<F, D>(f: F, delay: &mut D) -> u32
79where
80    F: Fn() -> bool,
81    D: DelayNs,
82{
83    let mut t = 0;
84    loop {
85        if f() || t > MAX_WAIT {
86            return t;
87        }
88        t += WAIT_STEP;
89        delay.delay_us(WAIT_STEP);
90    }
91}
92
93#[cfg(feature = "embedded_alloc")]
94pub trait DhtValueString {
95    fn get_temp_str(&self) -> String;
96    fn get_hum_str(&self) -> String;
97}
98
99pub mod dht11 {
100    use super::*;
101
102    impl Reading<i8, u8> {
103        pub fn get_temp(&self) -> i8 {
104            self.temp
105        }
106        pub fn get_hum(&self) -> u8 {
107            self.hum
108        }
109    }
110    #[cfg(feature = "embedded_alloc")]
111    impl DhtValueString for Reading<i8, u8> {
112        fn get_temp_str(&self) -> String {
113            let temp = self.get_temp();
114            let temp_str = temp.to_string();
115            temp_str.to_owned()
116        }
117        fn get_hum_str(&self) -> String {
118            let hum = self.get_hum();
119            let hum_str = hum.to_string();
120            hum_str.to_owned()
121        }
122    }
123    pub struct DHT11<'a, D> {
124        pub pin: Flex<'a>,
125        pub delay: D,
126    }
127
128    impl<'a, D> DHT11<'a, D>
129    where
130        D: DelayNs,
131    {
132        pub fn new(pin: impl Peripheral<P = impl Pin> + 'a, delay: D) -> Self {
133            let pin = Flex::new(pin);
134            Self { pin, delay }
135        }
136
137        //pub fn read(&mut self) -> Result<Reading, &str> {
138        pub fn read(&mut self) -> Result<Reading<i8, u8>, &str> {
139            let data = self.read_raw()?;
140            let rh = data[0];
141            let temp_signed = data[2];
142            let temp = {
143                let (signed, magnitude) = convert_signed(temp_signed);
144                let temp_sign = if signed { -1 } else { 1 };
145                temp_sign * magnitude as i8
146            };
147
148            Ok(Reading {
149                temp: temp,
150                hum: rh,
151            })
152        }
153
154        fn read_raw(&mut self) -> Result<[u8; 4], &str> {
155            // wake up the sensor by pulling the pin down
156
157            self.pin.set_as_output();
158            self.pin.set_low();
159            self.delay.delay_ms(18);
160            self.pin.set_high();
161            self.delay.delay_us(48);
162
163            // wait for the pin to go up again and then drop to low for 20-40us
164            self.pin.set_as_input();
165            let _ = wait_for_state(|| self.pin.is_high(), &mut self.delay);
166            let _ = wait_for_state(|| self.pin.is_low(), &mut self.delay);
167
168            // data read starts here
169            let mut buf = [0; 4];
170
171            for idx in 0..4 {
172                buf[idx] = self.read_byte();
173            }
174            let checksum = self.read_byte();
175            if checksum
176                != buf
177                    .iter()
178                    .fold(0_u8, |acc: u8, a: &u8| acc.wrapping_add(*a))
179            {
180                return Err("Checksum error");
181            }
182
183            Ok(buf)
184        }
185
186        fn read_byte(&mut self) -> u8 {
187            let mut buf = 0u8;
188            for idx in 0..8 {
189                let _ = wait_for_state(|| self.pin.is_high(), &mut self.delay);
190                let t = wait_for_state(|| self.pin.is_low(), &mut self.delay);
191
192                if t > 35 {
193                    buf |= 1 << 7 - idx;
194                }
195            }
196            buf
197        }
198    }
199
200    fn convert_signed(signed: u8) -> (bool, u8) {
201        let sign = signed & 0x80 != 0;
202        let magnitude = signed & 0x7F;
203        (sign, magnitude)
204    }
205}
206
207pub mod dht22 {
208    use super::*;
209
210    impl Reading<f32, f32> {
211        pub fn get_temp(&self) -> f32 {
212            self.temp
213        }
214
215        pub fn get_hum(&self) -> f32 {
216            self.hum
217        }
218    }
219
220    #[cfg(feature = "embedded_alloc")]
221    impl DhtValueString for Reading<f32, f32> {
222        fn get_temp_str(&self) -> String {
223            let temp = self.get_temp();
224            let temp_str = temp.to_string();
225            temp_str.to_owned()
226        }
227        fn get_hum_str(&self) -> String {
228            let hum = self.get_hum();
229            let hum_str = hum.to_string();
230            hum_str.to_owned()
231        }
232    }
233
234    //rust f32 custom decimal point length pick up from
235    //https://zhuanlan.zhihu.com/p/466389032
236    trait F32Utils {
237        fn round_fixed(self, n: u32) -> f32;
238    }
239
240    impl F32Utils for f32 {
241        fn round_fixed(self, n: u32) -> f32 {
242            if n <= 0 {
243                return self.round();
244            }
245            let i = 10_usize.pow(n) as f32;
246            let x = self * i;
247            if self > 0_f32 {
248                // 正数情况下 1.15_f32.round() 为1.2
249                let m = x.round() as u32;
250                m as f32 / i
251            } else {
252                //默认的负数round四舍五入取整(a) -1.15_f32.round() 为 -1.2 (b)
253                let mr = x.trunc(); //整数部分
254                let mf = x.fract(); //小数部分
255                if mf.abs() >= 0.5 {
256                    // -3.14159 四舍五入保留3位 则-3141.59 / 1000 = -3.14159(逢五进一) 变为-3.140
257                    return (mr + 1_f32) / i;
258                }
259                //小数部分 < 0.5直接舍弃小数部分;小数点直接使用整数部分向前移动n位
260                mr / i
261            }
262        }
263    }
264
265    pub struct DHT22<'a, D> {
266        pub pin: Flex<'a>,
267        pub delay: D,
268    }
269
270    impl<'a, D> DHT22<'a, D>
271    where
272        D: DelayNs,
273    {
274        pub fn new(pin: impl Peripheral<P = impl Pin> + 'a, delay: D) -> Self {
275            let pin = Flex::new(pin);
276            Self { pin, delay }
277        }
278
279        pub fn read(&mut self) -> Result<Reading<f32, f32>, &str> {
280            let data = self.read_raw()?;
281
282            let raw_temp: u16 = (data[2] as u16) << 8 | data[3] as u16;
283
284            // If the first bit of the 16bit word is set the temp. is negative
285            // Didn't have negative temps around to test it,
286            // so the conversion might be wrong as there are numerous different
287            // pieces of info on the subject over the Internet.
288            // Maybe will update it when the winter comes :)
289            let temp: f32 = match raw_temp & 0x8000 == 1 {
290                true => -0.1 * (raw_temp & 0x7fff) as f32,
291                false => 0.1 * raw_temp as f32,
292            };
293
294            let raw_hum: u16 = (data[0] as u16) << 8 | data[1] as u16;
295            let hum: f32 = 0.1 * raw_hum as f32;
296
297            let temp = temp.round_fixed(2);
298            let hum = hum.round_fixed(2);
299
300            Ok(Reading { temp, hum })
301        }
302
303        fn read_raw(&mut self) -> Result<[u8; 4], &str> {
304            // wake up the sensor by pulling the pin down
305            self.pin.set_as_output();
306            self.pin.set_low();
307            self.delay.delay_us(1000);
308
309            // wait for the pin to go up again and then drop to low for 20-40us
310            self.pin.set_as_input();
311            let _ = wait_for_state(|| self.pin.is_high(), &mut self.delay);
312            let _ = wait_for_state(|| self.pin.is_low(), &mut self.delay);
313
314            // another state flip, 80us for both low and high
315            let _ = wait_for_state(|| self.pin.is_high(), &mut self.delay);
316            let _ = wait_for_state(|| self.pin.is_low(), &mut self.delay);
317
318            // data read starts here
319            let mut buf = [42u8; 4];
320
321            for idx in 0..4 {
322                buf[idx] = self.read_byte();
323            }
324            let checksum = self.read_byte();
325            if checksum != buf.iter().fold(0, |acc: u8, a: &u8| acc.wrapping_add(*a)) {
326                return Err("Checksum error");
327            }
328
329            Ok(buf)
330        }
331
332        fn read_byte(&mut self) -> u8 {
333            let mut buf = 0u8;
334            for idx in 0..8 {
335                let _ = wait_for_state(|| self.pin.is_high(), &mut self.delay);
336                let t = wait_for_state(|| self.pin.is_low(), &mut self.delay);
337
338                if t > 35 {
339                    buf |= 1 << 7 - idx;
340                }
341            }
342            buf
343        }
344    }
345}