3030
3131import array
3232import time
33+ from digitalio import DigitalInOut , Pull , Direction
34+ _USE_PULSEIO = False
3335try :
3436 import pulseio
35- except ImportError as excpt :
36- print ( "adafruit_dht requires the pulseio library, but it failed to load." +
37- " Note that CircuitPython does not support pulseio on all boards." )
38- raise excpt
37+ _USE_PULSEIO = True
38+ except ImportError :
39+ pass # This is OK, we'll try to bitbang it!
40+
3941
4042__version__ = "0.0.0-auto.0"
4143__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DHT.git"
@@ -89,7 +91,7 @@ def _pulses_to_binary(self, pulses, start, stop):
8991
9092 return binary
9193
92- def _get_pulses (self ):
94+ def _get_pulses_pulseio (self ):
9395 """ _get_pulses implements the communication protcol for
9496 DHT11 and DHT22 type devices. It sends a start signal
9597 of a specific length and listens and measures the
@@ -100,10 +102,8 @@ def _get_pulses(self):
100102 pulses will have 81 elements for the DHT11/22 type devices.
101103 """
102104 pulses = array .array ('H' )
103-
104105 # create the PulseIn object using context manager
105106 with pulseio .PulseIn (self ._pin , 81 , True ) as pulse_in :
106-
107107 # The DHT type device use a specialize 1-wire protocol
108108 # The microprocessor first sends a LOW signal for a
109109 # specific length of time. Then the device sends back a
@@ -112,19 +112,51 @@ def _get_pulses(self):
112112 pulse_in .pause ()
113113 pulse_in .clear ()
114114 pulse_in .resume (self ._trig_wait )
115-
116115 # loop until we get the return pulse we need or
117116 # time out after 1/4 second
118117 tmono = time .monotonic ()
119- while True :
120- if time .monotonic ()- tmono > 0.25 : # time out after 1/4 seconds
121- break
122-
118+ while time .monotonic () - tmono < 0.25 :
119+ pass # time out after 1/4 seconds
123120 pulse_in .pause ()
124121 while pulse_in :
125122 pulses .append (pulse_in .popleft ())
126123 pulse_in .resume ()
124+ return pulses
125+
126+ def _get_pulses_bitbang (self ):
127+ """ _get_pulses implements the communication protcol for
128+ DHT11 and DHT22 type devices. It sends a start signal
129+ of a specific length and listens and measures the
130+ return signal lengths.
127131
132+ return pulses (array.array uint16) contains alternating high and low
133+ transition times starting with a low transition time. Normally
134+ pulses will have 81 elements for the DHT11/22 type devices.
135+ """
136+ pulses = array .array ('H' )
137+ with DigitalInOut (self ._pin ) as dhtpin :
138+ # we will bitbang if no pulsein capability
139+ transitions = []
140+ # Signal by setting pin high, then low, and releasing
141+ dhtpin .direction = Direction .OUTPUT
142+ dhtpin .value = True
143+ time .sleep (0.1 )
144+ dhtpin .value = False
145+ time .sleep (0.001 )
146+ timestamp = time .monotonic () # take timestamp
147+ dhtval = True # start with dht pin true because its pulled up
148+ dhtpin .direction = Direction .INPUT
149+ dhtpin .pull = Pull .UP
150+ while time .monotonic () - timestamp < 0.25 :
151+ if dhtval != dhtpin .value :
152+ dhtval = not dhtval # we toggled
153+ transitions .append (time .monotonic ()) # save the timestamp
154+ # convert transtions to microsecond delta pulses:
155+ # use last 81 pulses
156+ transition_start = max (1 , len (transitions ) - 81 )
157+ for i in range (transition_start , len (transitions )):
158+ pulses_micro_sec = int (1000000 * (transitions [i ] - transitions [i - 1 ]))
159+ pulses .append (min (pulses_micro_sec , 65535 ))
128160 return pulses
129161
130162 def measure (self ):
@@ -135,17 +167,19 @@ def measure(self):
135167 Raises RuntimeError exception for checksum failure and for insuffcient
136168 data returned from the device (try again)
137169 """
138- delay_between_readings = 0.5
139- if self ._dht11 :
140- delay_between_readings = 1.0
170+ delay_between_readings = 2 # 2 seconds per read according to datasheet
141171 # Initiate new reading if this is the first call or if sufficient delay
142172 # If delay not sufficient - return previous reading.
143173 # This allows back to back access for temperature and humidity for same reading
144174 if (self ._last_called == 0 or
145175 (time .monotonic ()- self ._last_called ) > delay_between_readings ):
146176 self ._last_called = time .monotonic ()
147177
148- pulses = self ._get_pulses ()
178+ if _USE_PULSEIO :
179+ pulses = self ._get_pulses_pulseio ()
180+ else :
181+ pulses = self ._get_pulses_bitbang ()
182+ #print(len(pulses), "pulses:", [x for x in pulses])
149183
150184 if len (pulses ) >= 80 :
151185 buf = array .array ('B' )
@@ -155,14 +189,11 @@ def measure(self):
155189 if self ._dht11 :
156190 # humidity is 1 byte
157191 self ._humidity = buf [0 ]
158- else :
159- # humidity is 2 bytes
160- self ._humidity = ((buf [0 ]<< 8 ) | buf [1 ]) / 10
161-
162- if self ._dht11 :
163192 # temperature is 1 byte
164193 self ._temperature = buf [2 ]
165194 else :
195+ # humidity is 2 bytes
196+ self ._humidity = ((buf [0 ]<< 8 ) | buf [1 ]) / 10
166197 # temperature is 2 bytes
167198 # MSB is sign, bits 0-14 are magnitude)
168199 raw_temperature = (((buf [2 ] & 0x7f )<< 8 ) | buf [3 ]) / 10
@@ -180,9 +211,12 @@ def measure(self):
180211 # check sum failed to validate
181212 raise RuntimeError ("Checksum did not validate. Try again." )
182213
183- else :
214+ elif len (pulses ) >= 10 :
215+ # We got *some* data just not 81 bits
184216 raise RuntimeError ("A full buffer was not returned. Try again." )
185-
217+ else :
218+ # Probably a connection issue!
219+ raise RuntimeError ("DHT sensor not found, check wiring" )
186220 @property
187221 def temperature (self ):
188222 """ temperature current reading. It makes sure a reading is available
0 commit comments