\ Read DHT22 data.  (bit bang)
\ TI MSP430G2553 Launchpad with noForth mv 2553 240101 

(* 
To do: monitor timeout 

History
v0066 - Display negative temperatures correctly.
V0065 - Represent tenths of degrees of temperatures.
V0064 - Loops named with ( A ) ... ( D ). Variants of loops B and D studied. These loop variations of B and D work well. Comments revised. mk 20250423 05:25
V0063 - Cleaned up the code. Data output reduced to the essentials. mk 20250421 02:04
V0062 - Works well, output rounded to whole digits. mk 20250419 21:51
Previous versions: Successive approximation to the solution.

Patch millisecond to 100 microseconds. 
See: config2553.f
  00c7 10B2 rom!  
  hex 10B2 DMP
After COLD this value is active.

addr acronym registername
020  P1IN    Input
021  P1OUT   Output 
022  P1DIR   Direction
023  P1IFG   Interupt Flag
024  P1IES   Interrupt Edge Select
025  P1IE    Interrupt Enable
026  P1SEL   Port Select
041  P1SEL2  Port Select2
027  P1REN   Resistor Enable
*)


asm\    

hex

\ tools
code cls ( -- ) s0 # sp mov  next end-code  \ clear stack

code p1H     #1 021 & .b bis   next end-code \ set lines
code p1L     #1 021 & .b bic   next end-code 
code p6H   40 # 021 & .b bis   next end-code 
code p6L   40 # 021 & .b bic   next end-code 


\ Assign DHT22 data line to pin p1.0, controll pin to p1.6
: Pio ( -- )  \ set I/O function
  41 027 *bic \ p1ren off
  41 025 *bic \ p1ie  disable interrupt
  41 026 *bic \ P1SEL I/0
  41 041 *bic \ P1SEL2 I/0 
  41 022 *bis \ set out for P1.0, P1.6
  ;

: wakeup ( -- ) \ notify sensor to prepare the data
  pio p1H p6H 1 ms  p1L 10 ms  ( p6L ) p1H  ; \ 1 ms == 100┬Ás !

Code @data ( -- sun moon  xx  yy  zz chksum )  \ read sensor data
\  i.e     ( -- sun moon hum tmp chk chksum )
 \ get response time 
  #1 022 & .b bic \ p1,0 IN
  #0 sun      mov   
  #1 024 & .b bis \ FALLING EDGE\__
  #1 023 & .b bic  \ clear P1IFG 
40 # 021 & .b bic \ p6L\___  (for logic analyser)
  begin, ( A )       \ wait for edge 
    #1 023 & .b bit  \ test bit 
    \ Z: Set if result is zero, reset otherwise
    \ C: Set if result is not zero, reset otherwise (.NOT. Zero)
  cc? while, 
    #1 sun add
  repeat,   
40 # 021 & .b bis \ ___/p6H  (for logic analyser)
  tos sp -) mov   
  sun tos   mov   ( -- sun )
 \ get startpulse time
  #0 moon     mov   
  #1 024 & .b bic \ ___/ RISING EDGE
  #1 023 & .b bic  \ clear P1IFG 
40 # 021 & .b bic \ p6L\___  (for logic analyser)
  begin, ( B )       \ wait for edge
    #1 023 & .b bit  \ test bit 
   \ Z: Set if result is zero, reset otherwise
   \ C: Set if result is not zero, reset otherwise (.NOT. Zero)
   cc? while,
   #1 moon add
  repeat,   
40 # 021 & .b bis \ ___/p6H  (for logic analyser)
  tos sp -)  mov   
  moon tos   mov   ( -- moon )
 \ read 40 bits to array
  #0 xx mov  \ init array
  #0 yy mov
  #0 zz mov 
  dm 40 # day mov
  begin, ( C )
    #1 023 & .b bic \ clear P1IFG 
    begin,           \ wait for edge
      #1 023 & .b bit \ test IFG
      \ Z: Set if result is zero, reset otherwise
      \ C: Set if result is not zero, reset otherwise (.NOT. Zero)
    cs? until,
    \ wait to read bit
    moon w mov 
	w w add     \  2*moon, Loop D is about twice as fast as loop B.
40 # 021 & .b bic \ p6L\___  (for logic analyser)	
    begin, ( D )
      #1 w sub  
    0=? until,
	\ read bit
40 # 021 & .b bis  \ __/p6H  (for logic analyser)
    020 & w .b mov  \ read data line: bit H or L
    #1 w       bia   \ get bit
      \ tos sp -) mov  
      \ w tos     mov  ( ... -- ... bit ) \ test
      \ #1 sr bic  \ clear carry bit
	\ shift left all bits
    zz zz add   
    yy yy addc
    xx xx addc
    w  zz bix   \ = xor : write data bit
  #1 day sub
  0=? until, \ 40 bits are read
  \ adjust bits
  8 # day mov  \ lshift 40 bits up 8x -> xx=hum yy=tmp 
  begin,
    zz zz add 
    yy yy addc
    xx xx addc
    #1 day sub
  0=? until,
  \ push data to stack
  tos sp -)  mov   xx tos mov  ( -- xx ) 
  tos sp -)  mov   yy tos mov  ( -- yy ) 
  zz swpb  \ get upper byte
  tos sp -)  mov   zz tos mov  ( -- zz.b ) 
  \ calculate checksumme
  #0 w mov
  xx w .b add   xx swpb   xx w .b add
  yy w .b add   yy swpb   yy w .b add
  tos sp -)  mov  
  w tos   mov
next end-code

\ display 
decimal
: (dht22) ( -- sun moon hum tmp chk chksum )
  cls wakeup @data 
  ;

: decemit ( c -- ) \ print c from DEC special character set 
  hx 1B emit  [char] ( emit  [char] 0 emit   emit 
  hx 1B emit  [char] ( emit  [char] B emit   \ back to normal output
  ;


: .tmp ( tmp -- ) \ Print temperature with sign, one decimal place and degree symbol 
  dup hx 8000 and hx 8000 =
      if [char] - else [char] + then emit
  hx 7fff and ( tmp -- +tmp )  
  10 /mod 3 .r [char] . emit .
  [char] f decemit 
  [char] C emit space
  ;  
  
: .hum ( hum -- )  \ Print the relative humidity rounded to whole digits
  10 / . ." %rel" space 
  ;  
	
: dht22 ( -- ) \ get temperatur and humidity
  cr (dht22)   ( 2 + ) \ add 2 for 'else' part
  = if ." chk  " else ." chksum error" cls exit then
  .tmp space space  .hum space space
  \ ( sun moon -- ) drop drop 
    ( sun moon -- )  . .      \ testing
  ;

(*
The DHT22 starts its next measurement AFTER the query and saves the values. 
These are output with the next query, so they are old. 
For up-to-date values, query twice. 
There must be more than 2 seconds between each query, otherwise the DHT22 will not respond again.
*)
    
: test ( n -- )
  >r
  cr ." discard old values..." (dht22) cls 
  cr ." reading current data:"
  r> 0 do   
    dm 40000 ms  \ wait until the sensor is ready again.
    dht22  
  loop
  ;

shield nn\
freeze
( finis)