Closed grukx closed 1 year ago
I can't see anything obvious
--deleted incorrect suggestion here---
Geir
Hi, Thank for this new issue !
I think you're right there's probably an bug ^^ I will investigate this. When you got the value of -3275.1C, do you know the real temperature ? (even an approximation ?)
Thanks, Jonathan
I try to refactoring the casts in the read function. Can you try the 0.5.2 ?
I see the problem the moment it dips below 0C. My guess is that there is an incorrect sign extension happening somewhere, however I have not found it yet. As you can see the number is very close to 32767. I guess it must happen before or possibly during the 0x7FFF mask. I have tried a few different casts, but with little luck so far. I will try 0.5.2 a little later today, but have to prioritize work first :D
I get it with this code
fn main() {
let t:u32 = 0x0000FFEF;
let mut final_t: i32 = (t & 0x7FFF) as i32;
if (t & 0x8000) > 0 {
final_t *= -1;
}
let temperature = final_t as f32 / 10.0;
println!("Converted temp: {} ", temperature);
}
Yes I have the same idea, but I don't understand what happen. I remove the sign bit, before convert the unsigned into a signed value. My guess for the 0.5.2, ts the casts to f32 from i32, when the value is negative, could probably gone wrong (the value bigger than the mantis, maybe ?).
No problem :D Same for me ! I'll try to put a DHT in my freezer during my lunch break ^^
(Our messages have crossed ^^ [Is this only a french expression ? ^^])
From the DataSheet of the DHT22, when the temperature is below zero, the 16th bit is set to one, but the value is not "two's complement".
For example :
0000 0000 0110 0101
1000 0000 0110 0101
yes - and code is fine when tested with t=0x00008065, but that is seemingly not what gets passed in from read_data
fn main() {
let chip_read:u32 = 0x80650000;
let t: u32 = (chip_read & 0xFFFF0000) >> 16;
let mut final_t: i32 = (t & 0x7FFF) as i32;
if (t & 0x8000) > 0 {
final_t *= -1;
}
let temperature = final_t as f32 / 10.0;
println!("Converted temp: {} ", temperature);
}
Is fine - so if chip was returning 0x8065 (-10.1) it should work
Why are you left align the value ?
let chip_read:u32 = 0x80650000;
let t: u32 = (chip_read & 0xFFFF0000) >> 16;
But your code, show something stupid I did. I return u32 but the value is on 16 bits.... It's probable better to return u16 instead....
That was me mixing up hum and temp returned from the sensor - so ignore my last code - the left align is nonsense. I was trying to include some of what happens in read_data - but this was wrong :D
As for returning a u16, I agree - but it is a bit weird that this happens as the conversions seem fine. I suspect that it happens closer to the sensor readout.
While on the topic of optimization - from compiler explorer it looks like its better to write the code like this (https://godbolt.org/z/rK1G1GE7G). It produces way less assembly.
pub fn test() -> f32 {
let t:u32 = 0x80c1;
let final_t: i16 = (t & 0x7FFF) as i16;
let temperature:f32;
if (t & 0x8000) > 0 {
temperature= final_t as f32 / -10.0;
} else
{
temperature= final_t as f32 / 10.0;
}
temperature
}
(sorry about the side-track)
Ok I made some measures, and I get something strange...
As a raw value I got: 65320
in binary 1111 1111 0010 0011
, but I don't understand why, I have so many 1
for MSBs. If I remove all the 1s, the right value appears 0010 0011 = 23 => -2.3 °C
.
But the datasheet said, only the MSB bit, should set to 1 on negative value... And it's not a problème with my algorithm because de CRC pass.
Very strange - I can do a test in my freezer - the outside temp has risen a bit so its no longer below 0 at night.
I wonder if our sensors aren't actually DHT12? Because it seems that for this component we only need the first byte for the value... https://github.com/adafruit/DHT-sensor-library/blob/be6915c60d7ca6922a99b9c089d4e82c0ef12829/DHT.cpp#L100
I've pushed version 0.6 with DHT12 support, can you try? It works for me. Where did you buy the DHT? (Me on aliexpress, maybe not the most reliable ^^)
(I'm not sure if it works... I can't go below -25.5°C... I think I made a mistake...) I confirm I'm stupid....
dht12 is only down to -20
I bought mine locally as I was eager to get started - but I have two - maybe I should just open up one and check
no markings, the strange thing is that dht12 is supposed to also be i2c
tested in freezer with dh12, but once it got down to 0C it started reporting -25.5 - and decreased as it got colder. So that is not correct either.
no markings, the strange thing is that dht12 is supposed to also be i2c Yes... That why I said I'm stupid.... (I just 'yanked' the 6.0.0)
It seems there different "type" of DHT22 some library call it TYPE2. But there is no real consensus around this. Somme libs simply ignore the first byte when the temperature is under 0°C, and some make something more clever: they invert (logic "not") the first byte when the temperature is under 0°C.
And I think I'll make this, because during my test I observe the first byte with the value 1111 1110
when temperature is below -25°C.
When in DHT22 mode it got down to 0b1111_1110_1011_1011 -> which if I mask out the top bits until the first 0 gives 187, or -18.7 - which seems reasonable. Except its not how its supposed to be.
This ends up being just guesswork - but removing all leading ones from the MSB and converting at least gives some kind of sensible result. But it must be possible to dig up some more info on this Type2.
Yes, I agree. I can't find any datasheet with this behaviour... I will add a dht22Type2
struct to keep both data structure.
There is something in here about DHT22's that require a different length reset pulse https://github.com/esphome/esphome/pull/926
Could it be that we are reading back invalid registers due to a bad reset?
I think that 18ms in the document is a typo. Everywhere else in there says minimum 1ms. There was someone in the Discord channel today that couldn't get his DTH22 working until he changed the 800us to 2ms. Did you actually find a DHT22 that would fail if the pulse was longer than 800us? When he tried 18ms, it still worked like I expected it to. But it did have to be more than 1ms because that wasn't enough. 1.5ms would probably be good.
Try a longer reset pulser maybe? 2ms?
Well... inverting the first byte doesn't work... But by doing a "not" (or a two's complement), it seems to work....
Your link is interesting, but why it work on positive value ? I can try to add a longer pulse (but after the dinner 😉).
Just try a 2ms reset, it don't change anything... But I think I'll keep it to 2ms.
Well, I tested a bit as well and my DHT is not happy with any longer reset than 1ms, in fact 800ms is in the middle of the pulse it tolerates as reset. setting x to 32 causes dht to fail to start at -20C (tested in freezer)
I will probably be investigating other sensors, this is too magical and undocumented for me 😞
Is there anything in the pio code that could do sign extension on the top byte for some reason? would be super strange, but I know no PIO code - yet.
Hm... So maybe I will set X to 25, this should generate a pulse of 800µS... From my test it seems the result is two's complements...
I will probably be investigating other sensors, this is too magical and undocumented for me 😞
Yes, you are probably right ^^
Is there anything in the pio code that could do sign extension on the top byte for some reason?
In theory no, the PIO script read the pin state and shift the result into a 32 bits buffer. This buffer is sent once is full or when I forced it (for the CRC for example)
but I know no PIO code - yet.
You can try it's not that hard ^^
Ok ! It make me angry because it's not documented, but the data from the DHT are two's complemented... So I simply cast the result to i16
then into f32
(then divide by 10) and it works like a charm...
If you want to try I will push the 0.5.3
Go for it
Its only 9 instructions! (just read some doc 🤣) Looks like they got their inspiration from the TIS-100 game 💯 (probably one of histories nerdiest games)
Yeah ! It's very simple. I LOVE this game !!! But there are some limitations, your "PIO" program can only have 32 instructions.
I think the hygrometer doesn't like the freezer 😆
Ooops
The 0.5.3 is available. You have to change Dht22
to Dht22Type2
Well... I need to dry my sensor but, the values are correct
Oh ! And I kept the old value for the reset pulse...
Can I close this problem? Have you tested the new version, or have you changed sensors?
You can close this ticket - the reading worked down to -22, however I have some questions about the sensor accuracy at this temperature as it deviated by about 4 degrees from the thermal camera I have on the same pico. This could be something else though and I will re-check accuracy at some other time.
You can close this for now.
Thanks for the help.
My DHT reported -3275.1C when the temp outside was a bit below 0C
DHT22: -3275.1C, 76.5%
Pretty sure it was not that cold outside 🤒
Regards, Geir