REM DHT11/12/22 sensor interface for Raspberry Pi 3/3+ (Raspbian)
REM (c) Richard Russell, http://www.rtrussell.co.uk/, 03-Jun-2019
INSTALL @lib$ + "gpiolib"
GPIO% = FN_gpio_setup
PIN% = 2 : REM BCM pin no.
@% = &2010A
REPEAT
CASE FN_dht_read(GPIO%, PIN%, humidity, temperature) OF
WHEN 0: PRINT TIME$ " Humidity = "; humidity "%, temperature = "; temperature "C"
WHEN 1: PRINT TIME$ " DHT11/12/22 read failed: wrong number of transitions"
WHEN 2: PRINT TIME$ " DHT11/12/22 read failed: checksum error"
WHEN 3: PRINT TIME$ " DHT11/12/22 read failed: no response"
ENDCASE
WAIT 200
UNTIL FALSE
END
REM Read from DHT11/12/22, G% is value returned from FN_gpio_setup, P% is BCM pin number:
DEF FN_dht_read(G%, P%, RETURN humidity, RETURN temperature)
LOCAL B%, C%, I%, J%, M%, N%, O%, T%, d&(), t%() : N% = 6000 : REM Adjust for CPU speed
DIM d&(4), t%(90), C% LOCAL N%*4 + 3
B% = G% + &34 : M% = 1 << P%
REM Initialise the GPIO pin to be used, happens only on first call:
PRIVATE initialised
IF NOT initialised THEN
PROC_gpio_inp(G%, P%) : PROC_gpio_pull(G%, 2) : REM pull-up
PROC_gpio_pullclk0(G%, 1 << P%) : PROC_gpio_pullclk0(G%, 0)
initialised = TRUE
WAIT 10
ENDIF
REM Send the start signal to the DHT11/12/22 and sample the data stream it responds with:
PROC_gpio_out(G%,P%) : G%!&28 = M% : REM Set data line to output and low
WAIT 2 : REM Wait 20 ms
G%!&1C = M% : PROC_gpio_inp(G%,P%) : REM Set data line high and to input
FOR I% = C% TO C% + N%*4 STEP 4 !I%=!B% : NEXT : REM Sample at ~1 us intervals
REM Scan the captured data for transitions and store their positions in an array:
FOR I% = C% + 32 TO C% + N%*4 STEP 4
IF !I% AND M% EOR O% t%(J%) = I% : O% EOR= M% : J% += 1 : IF J% > DIM(t%(),1) EXIT FOR
NEXT
IF J% < 5 THEN = 3 : REM If fewer than 5 transitions report no response
IF O% = 0 ERROR 100, "Sampling period not long enough to capture entire data stream"
REM Measure the total 'low' time (except for the initial pulse) to establish timebase:
FOR I% = 1 TO J%-2 STEP 2 : T% += t%(I%+1) - t%(I%) : NEXT : T% DIV= 41
REM If too few transitions attempt to infer where the missing pulse(s) was/were:
IF J% = 79 PROC_dht_fix(t%(), J%)
IF J% = 81 PROC_dht_fix(t%(), J%)
IF J% <> 83 THEN = 1 : REM Report uncorrectable wrong number of transitions
REM Decode data using only the high-to-low transitions:
FOR I% = 0 TO 39 : d&(I% DIV 8) = d&(I% DIV 8) * 2 - ((t%(I%*2+3) - t%(I%*2+1) > 2 * T%)) : NEXT
IF d&(4) <> (SUM(d&()) - d&(4) AND &FF) THEN
REM If checksum error attempt to decode using only the low-to-high transitions:
FOR I% = 0 TO 39 : d&(I% DIV 8) = d&(I% DIV 8) * 2 - ((t%(I%*2+4) - t%(I%*2+2) > 2 * T%)) : NEXT
ELSE IF d&(4) <> (SUM(d&()) - d&(4) AND &FF) THEN ;
REM If still a checksum error attempt to decode using widths of high pulses:
FOR I% = 0 TO 39 : d&(I% DIV 8) = d&(I% DIV 8) * 2 - ((t%(I%*2+3) - t%(I%*2+2) > T%)) : NEXT
ENDIF
IF d&(4) <> (SUM(d&()) - d&(4) AND &FF) THEN = 2 : REM Report uncorrectable checksum error
REM Get the humidity and temperature; REM or unREM as required for DHT11/12 or DHT22:
humidity = d&(0) + d&(1) / 10 : temperature = d&(2) + d&(3) / 10 : REM DHT11/12
REM humidity = (d&(0) * 256 + d&(1)) / 10 : REM DHT22
REM temperature = ((d&(2) AND &7F) * 256 + d&(3)) / 10 : IF d&(2) >= &80 temperature *= -1 : REM DHT22
= 0
REM If the number of transitions was wrong attempt to insert the 'missing' pulse:
DEF PROC_dht_fix(t%(), RETURN J%)
LOCAL I%, M%, S%, T%
FOR I% = 1 TO J%-2 STEP 2
T% = t%(I%+1) - t%(I%)
IF T% > M% M% = T% : S% = I%
NEXT
FOR I% = J%+1 TO S%+3 STEP -1
t%(I%) = t%(I%-2)
NEXT
t%(S%+1) = t%(S%) + M% * 2 / 5 + 0.5 : REM new rising edge
t%(S%+2) = t%(S%) + M% * 3 / 5 + 0.5 : REM new falling edge
J% += 2
ENDPROC