Raspberry BASIC

Author Topic: Interfacing with a DHT11/12/22 sensor  (Read 8973 times)

Richard Russell

  • Moderator
  • *****
  • Posts: 66
    • View Profile
Interfacing with a DHT11/12/22 sensor
« on: June 03, 2019, 04:21:14 PM »
The BBC BASIC program below interfaces with a DHT11/12 or DHT22 humidity and temperature sensor connected to a Raspberry Pi GPIO pin.  These sensors use a proprietary serial data format on a one-wire bidirectional bus, which has to be decoded in software.

Because of the variable latency associated with a user-mode program reading the GPIO, the data cannot always be decoded reliably.  The code uses a number of strategies to minimize this problem but mis-reads must be expected and dealt with (e.g. by means of retries) in any application using it.  Note that the DHT11/12 may be polled no faster than once per second and the DHT22 no faster than once every two seconds.

The code has been written to be functional rather than pretty!

Code: Text
  1.       REM DHT11/12/22 sensor interface for Raspberry Pi 3/3+ (Raspbian)
  2.       REM (c) Richard Russell, http://www.rtrussell.co.uk/, 03-Jun-2019
  3.  
  4.       INSTALL @lib$ + "gpiolib"
  5.       GPIO% = FN_gpio_setup
  6.       PIN% = 2 : REM BCM pin no.
  7.  
  8.       @% = &2010A
  9.       REPEAT
  10.         CASE FN_dht_read(GPIO%, PIN%, humidity, temperature) OF
  11.           WHEN 0: PRINT TIME$ "  Humidity = "; humidity "%, temperature = "; temperature "C"
  12.           WHEN 1: PRINT TIME$ "  DHT11/12/22 read failed: wrong number of transitions"
  13.           WHEN 2: PRINT TIME$ "  DHT11/12/22 read failed: checksum error"
  14.           WHEN 3: PRINT TIME$ "  DHT11/12/22 read failed: no response"
  15.         ENDCASE
  16.         WAIT 200
  17.       UNTIL FALSE
  18.       END
  19.  
  20.       REM Read from DHT11/12/22, G% is value returned from FN_gpio_setup, P% is BCM pin number:
  21.       DEF FN_dht_read(G%, P%, RETURN humidity, RETURN temperature)
  22.       LOCAL B%, C%, I%, J%, M%, N%, O%, T%, d&(), t%() : N% = 6000 : REM Adjust for CPU speed
  23.       DIM d&(4), t%(90), C% LOCAL N%*4 + 3
  24.       B% = G% + &34 : M% = 1 << P%
  25.  
  26.       REM Initialise the GPIO pin to be used, happens only on first call:
  27.       PRIVATE initialised
  28.       IF NOT initialised THEN
  29.         PROC_gpio_inp(G%, P%) : PROC_gpio_pull(G%, 2) : REM pull-up
  30.         PROC_gpio_pullclk0(G%, 1 << P%) : PROC_gpio_pullclk0(G%, 0)
  31.         initialised = TRUE
  32.         WAIT 10
  33.       ENDIF
  34.  
  35.       REM Send the start signal to the DHT11/12/22 and sample the data stream it responds with:
  36.       PROC_gpio_out(G%,P%) : G%!&28 = M% : REM Set data line to output and low
  37.       WAIT 2                             : REM Wait 20 ms
  38.       G%!&1C = M% : PROC_gpio_inp(G%,P%) : REM Set data line high and to input
  39.       FOR I% = C% TO C% + N%*4 STEP 4 !I%=!B% : NEXT : REM Sample at ~1 us intervals
  40.  
  41.       REM Scan the captured data for transitions and store their positions in an array:
  42.       FOR I% = C% + 32 TO C% + N%*4 STEP 4
  43.         IF !I% AND M% EOR O% t%(J%) = I% : O% EOR= M% : J% += 1 : IF J% > DIM(t%(),1) EXIT FOR
  44.       NEXT
  45.       IF J% < 5 THEN = 3 : REM If fewer than 5 transitions report no response
  46.       IF O% = 0 ERROR 100, "Sampling period not long enough to capture entire data stream"
  47.  
  48.       REM Measure the total 'low' time (except for the initial pulse) to establish timebase:
  49.       FOR I% = 1 TO J%-2 STEP 2 : T% += t%(I%+1) - t%(I%) : NEXT : T% DIV= 41
  50.  
  51.       REM If too few transitions attempt to infer where the missing pulse(s) was/were:
  52.       IF J% = 79 PROC_dht_fix(t%(), J%)
  53.       IF J% = 81 PROC_dht_fix(t%(), J%)
  54.       IF J% <> 83 THEN = 1 : REM Report uncorrectable wrong number of transitions
  55.  
  56.       REM Decode data using only the high-to-low transitions:
  57.       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
  58.       IF d&(4) <> (SUM(d&()) - d&(4) AND &FF) THEN
  59.         REM If checksum error attempt to decode using only the low-to-high transitions:
  60.         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
  61.       ELSE IF d&(4) <> (SUM(d&()) - d&(4) AND &FF) THEN ;
  62.         REM If still a checksum error attempt to decode using widths of high pulses:
  63.         FOR I% = 0 TO 39 : d&(I% DIV 8) = d&(I% DIV 8) * 2 - ((t%(I%*2+3) - t%(I%*2+2) > T%)) : NEXT
  64.       ENDIF
  65.       IF d&(4) <> (SUM(d&()) - d&(4) AND &FF) THEN = 2 : REM Report uncorrectable checksum error
  66.  
  67.       REM Get the humidity and temperature; REM or unREM as required for DHT11/12 or DHT22:
  68.       humidity = d&(0) + d&(1) / 10 : temperature = d&(2) + d&(3) / 10 : REM DHT11/12
  69.       REM humidity = (d&(0) * 256 + d&(1)) / 10 : REM DHT22
  70.       REM temperature = ((d&(2) AND &7F) * 256 + d&(3)) / 10 : IF d&(2) >= &80 temperature *= -1 : REM DHT22
  71.       = 0
  72.  
  73.       REM If the number of transitions was wrong attempt to insert the 'missing' pulse:
  74.       DEF PROC_dht_fix(t%(), RETURN J%)
  75.       LOCAL I%, M%, S%, T%
  76.       FOR I% = 1 TO J%-2 STEP 2
  77.         T% = t%(I%+1) - t%(I%)
  78.         IF T% > M% M% = T% : S% = I%
  79.       NEXT
  80.       FOR I% = J%+1 TO S%+3 STEP -1
  81.         t%(I%) = t%(I%-2)
  82.       NEXT
  83.       t%(S%+1) = t%(S%) + M% * 2 / 5 + 0.5 : REM new rising edge
  84.       t%(S%+2) = t%(S%) + M% * 3 / 5 + 0.5 : REM new falling edge
  85.       J% += 2
  86.       ENDPROC
  87.  
« Last Edit: June 03, 2019, 06:55:00 PM by admin »

Richard Russell

  • Moderator
  • *****
  • Posts: 66
    • View Profile
Re: Interfacing with a DHT11/12/22 sensor
« Reply #1 on: June 03, 2019, 08:16:33 PM »
The syntax highlighting is great, thank you, but the 'Select All' option seems to have gone! It was there before, wasn't it, or did I imagine it?

« Last Edit: June 03, 2019, 08:19:33 PM by Richard Russell »

John Spikowski

  • BASIC Developer
  • ***
  • Posts: 234
    • View Profile
    • ScriptBasic
Re: Interfacing with a DHT11/12/22 sensor
« Reply #2 on: June 04, 2019, 03:40:54 AM »
It seems when you use the custom syntax highlighting option, Select All is no longer available. You can still select the text but you have to do it manually.
ScriptBasic Project Manager/Facilitator

Richard Russell

  • Moderator
  • *****
  • Posts: 66
    • View Profile
Re: Interfacing with a DHT11/12/22 sensor
« Reply #3 on: June 04, 2019, 08:18:41 AM »
It seems when you use the custom syntax highlighting option, Select All is no longer available. You can still select the text but you have to do it manually.

That's a pity.  I find manual selection difficult (on this laptop PC, at least), particularly if it needs to scroll; maybe if I had a proper mouse with a scrollwheel it would be easier.  It seems odd that one useful feature would be removed at the same time as adding another.  [I'd add a frown but emoticons are seemingly broken on this forum!]

John Spikowski

  • BASIC Developer
  • ***
  • Posts: 234
    • View Profile
    • ScriptBasic
Re: Interfacing with a DHT11/12/22 sensor
« Reply #4 on: June 07, 2019, 07:27:49 AM »
 I fixed the Smiley problem.  8)
« Last Edit: June 07, 2019, 07:41:31 AM by John Spikowski »
ScriptBasic Project Manager/Facilitator