@@ -57,14 +57,18 @@ float dht_humidity(DHTChipType type, std::array<uint8_t, 2> pair) {
57
57
// but, its never negative, so no reason to do any conversions for signed numbers
58
58
float out;
59
59
60
+ // based on ADSONG datasheet and various other libs implementing dht12
61
+ // extract sign info from the decimal scale part instead of the integral
62
+ constexpr auto MagnitudeMask = uint8_t { 0b1111111 };
63
+
60
64
switch (type) {
61
65
case DHT_CHIP_DHT11:
62
66
out = pair[0 ];
63
67
break ;
64
68
65
69
case DHT_CHIP_DHT12:
66
- out = pair[0 ];
67
- out += pair[1 ] * 0 .1f ;
70
+ out = ( pair[0 ] & MagnitudeMask) ;
71
+ out += ( pair[1 ] & MagnitudeMask) * 0 .1f ;
68
72
break ;
69
73
70
74
case DHT_CHIP_DHT21:
@@ -85,38 +89,49 @@ float dht_temperature(DHTChipType type, std::array<uint8_t, 2> pair) {
85
89
constexpr auto SignMask = uint8_t { 0b10000000 };
86
90
87
91
// in case it is negative and looks like twos-complement, value can be c/p into memory as-is
88
- // plus, it is enough to only check the sign bit neighbour. possible values are around [0...800]
92
+ // it is enough to only check the sign bit neighbour; possible values are around [0...800]
89
93
constexpr auto NegativeTwoComplementMask = uint8_t { 0b11000000 };
90
94
91
95
float out;
92
96
93
97
switch (type) {
98
+ // []pair for dht11 & dht12 contains integral and decimal scale
99
+ // based on ADSONG datasheet and various other libs implementing dht12
100
+ // try to extract sign info from both pairs, not just the integral one
101
+
102
+ // original code prefers to drop decimal scale in favour of a integral reading due to poor precision
94
103
case DHT_CHIP_DHT11:
95
104
out = pair[0 ];
105
+ if ((pair[0 ] & SignMask) || (pair[1 ] & SignMask)) {
106
+ out = -out;
107
+ }
96
108
break ;
97
109
110
+ // added decimal place based on the decimal scale byte
98
111
case DHT_CHIP_DHT12:
99
- out = pair[0 ] & MagnitudeMask;
100
- if (pair[0 ] & SignMask) {
112
+ out = (pair[0 ] & MagnitudeMask);
113
+ out += (pair[1 ] & MagnitudeMask) * 0 .1f ;
114
+ if ((pair[0 ] & SignMask) || (pair[1 ] & SignMask)) {
101
115
out = -out;
102
116
}
103
117
104
- out = out * 0 .1f ;
105
118
break ;
106
119
120
+ // []pair on recent chips contains s16 data w/ sign included
107
121
case DHT_CHIP_DHT21:
108
122
case DHT_CHIP_DHT22:
109
123
case DHT_CHIP_AM2301:
110
124
case DHT_CHIP_SI7021:
125
+ // special exception for negative numbers in twos-complement
111
126
if ((pair[0 ] & NegativeTwoComplementMask) == NegativeTwoComplementMask) {
112
127
int16_t tmp;
113
128
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
114
129
std::swap (pair[0 ], pair[1 ]);
115
130
#endif
116
131
std::memcpy (&tmp, pair.data (), sizeof (tmp));
117
132
out = tmp;
133
+ // fallback works both for the original chips and positive numbers
118
134
} else {
119
- // positive numbers are the same, no conversion needed
120
135
pair[0 ] &= MagnitudeMask;
121
136
out = (pair[0 ] << 8 ) | pair[1 ];
122
137
if (pair[0 ] & SignMask) {
0 commit comments