Interfacing with a Sensirion SHT-71 Relative Humidity and Temperature Sensor - PICAXE-18X

copyright, Peter H Anderson, Baltimore, MD, Feb, '04


Introduction.

Note that the original work in interfacing the Sensirion SHT71 with a BasicX BX24 and with a Basic Atom was originally developed by undergraduate student Brittany Fleming as a part of her capstone design project at Morgan State University.

This discussion focuses on interfacing a PICAXE-18X with a Sensirion SHT RH and Temperature sensor. Sensirion offers the SHT module in a small SOIC like package (SHT11/15) and a 4-pin SIP (0.05 inch centers) (SHT71/75). The only difference between the SHTx1 and SHTx5 devices is the accuracy of the relative humidity, 3.5 vs 2.0 percent.

I was concerned with my ability to solder the very small SHT1x device to an adaptor without damaging the device and I opted for the SHT71 and for the moment I have a stock of these for $25.00. With either, you will probably need an 8-pin SOIC to DIP adaptor which I stock for $5.00. (As of this writing, the US $ is falling like a stone. As the SHT devices are manufactured in Europe, the price may well rise with time).

Note that the terminal assignments for the SHT1x and the SHT7x are not the same.

Interface Protocol

The interface with the SHT is similar to the Philips I2C protocol in having a unidirectional clock (SCK) and a bidirectional data lead (DATA), but the actual protocol is quite different and I seriously doubt that one could accommodate other I2C devices on the same pair used by the SHT device nor operate multiple SHT sensors on the same pair.

Thus, in developing the following code, I attempted to carefully follow the timing diagrams in the data sheet and the result may well be an overkill. For example, in initiating each communication session, I opted to reset the device by bringing DATA high (high impedance) and providing nine clock pulses. This probably is not necessary, but uses little code and consumes little time relative to the time required for A/D conversions.

Although the developers of the PICAXE provide specific commands such as WriteI2C and Read I2C, these will not work with the SHT71;

An additional complication is that the PICAXE-18X does not have a bidirectional IO pin. Thus, it is not obvious that one can bring the DATA output to a high impedance state (logic one) nor read from the slave.

However I found that I could use a series 4.7K resistor between the Data output and the slave's data lead and also loop this to a PICAXE input;


PICAXE-18X                                        SHT-71

DataOut, Output1 (term 7) ------ 4.7K --------------- Data
                                        |
DataIn, Input1 (term 18) ---------------

CLK, Output0 (term 6) ------------------------------- CLK

When sending a logic zero, the DataOut terminal is brought low and CLK is brought high and low. When sending a logic one, DataOut is brought high and CLK is brought high and low.

When reading a bit, DataOut is first brought high. CLK is brought high and the bit is read on DataIn.

Environment

The Sensirion data sheet indicates a maximum of distance of 11 cm from the processor to the SHT sensor. This probably is good conservative advice. Clearly, it probably could be located much further, and I have verified reliable operation to 100 feet through an inexpensive telephone extension cable. However, I would hesitate to use it over any such distances where property or health may be at risk if the communications is not reliable. A preferred approach might be a slave processor collocated with the SHT device in a grain silo and interfacing with the master processor using either RS232 or better yet, RS485.

I am not capable of offering advice to the ruggedness of the SHT device, its ability to withstand very cold temperatures or its recovery from moisture or recovery from frozen moisture.

Calculations

The SHT defaults to a 12-bit conversion for the relative humidity measurement. This amounts to the RH range of 0.0 to 100 percent being broken into 4096 quantizing levels or about 40 levels per percent humidity. The unit defaults to a whopping 14-bit resolution for temperature which I believe amounts to the range of -40 to 100 degrees C being quantized into some 16384 levels. Both strike me as an overkill and perhaps this comes at a penalty. Eight, 12 and 14 bit conversions, require nominally 11, 55 and 210 ms, respectively. In the following routine, I used the default values of the status register and thus used a 250 ms delay for the 14-bit temperature measurement and a 60 ms delay for the 12-bit RH measurement. However, these are times which may well make the averaging of 100 measurements requiring 30 seconds impractical.

An alternative might be to write a logic one to the least significant bit of the status register and live with 8-bit and 12-bit resolutions for RH and temperature measurements, respectively. The wait times are then reduced to nominally 11 and 55 ms.

In the following routine, I read the 12-bit value for relative humidity (SOrh) from the SHT-71. However, in performing the calculation I opted to use only the eight most significant bits.

The value of relative humidity is then calculated;

	RH_linear = -4 + 0.648 * SOrh -7.2e-4 * SOrh

	RH_linear = -4 + 0.648 * SOrh * (1 - 7.2e-4/0.648 * SOrh)
Multiplying by 100;
	RH_linear_100 = -400 + 0.648 * SOrh * (100 - 0.111 * SOrh)
This is implemented as follows;
   X = SOrh / 10
   X = SOrh / 100 + X
   X = SOrh  / 1000 + X	' 0.111 * SOrh

   X = 100 - X			' 100 - 0.111 * SOrh

   X = X * SOrh
   X = X * 6 / 10		' times 0.648
   X = X * 4 /100 + X
   X = X * 8 / 1000 + X

   RH_100 = X - 400

I used the 14-bit value of the temperature (SOt).


	TC = -40.00 + 0.01 * SHt
Multiplying by 100;
	TC_100 = -4000 + SHt
The relative humidity is then compensated for temperature;
	RH_true = (Tc - 25) * (0.01 + 0.00128 * SOrh) + RH_linear
Multiplying by 100;
	RH_true_100 = (Tc - 25) * (1.0 + 0.128 * SOrh) + RH_100
Note that for values of temperature less than 25 degrees C, the value added to RH_100 is negative.

This temperature compensation is implemented;

   X = SOrh / 10
   X = SOrh * 2 / 100 + X
   X = SOrh * 8 / 1000 + X
   X = X + 1			' 1 + 0.128 * SOrh

   T_diff = TC_100 / 100 - 25
   SignBit = T_diff / 128

   If SignBit = 1 Then Negative

Positive:
   X = T_diff * X
   RH_100 = RH_100 + X
   GoTo Display

Negative:
   T_diff = T_diff ^ $ff + 1	' two's compliment
   X = T_diff * X
   RH_100 = RH_100 - X
   GoTo Display

General Observations.

In performing the arithmetic calculations, I have made every attempt to avoid overflows. However, recognize that I did not develop it for any product that I plan to offer. Rather, I developed this code for PICAXE users to go forth and use this and use their creativity. But, before you bet the farm, it is best you be certain there are no overflows, or for that matter, other careless errors. I did test the code at my desk and compared the RH and temperature with other devices I have and then placed my finger near the device to observe increasing humidity, but this is not a conclusive test by any means.

In developing this routine, I had to pause as I allocated each of the 14 bytes of user RAM. One can sure use these 14 bytes quite quickly

Recognize however, that one has the ability to peek and poke far more RAM. I did not do so, but plan to develop code that illustrates how one might use the peek poke capability without the program becoming unreadable.


' SHT71.Bas
'
' copyright, Peter H Anderson, Baltimore, MD, Feb, '04


' pin definitions
Symbol  SCL = OutPut0
Symbol  SDAOut = Output1
Symbol  SDAin = Input1


Symbol shtMT = %00000011 	' Meas Temp
Symbol shtMH = %00000101	' Meas Rel Hum
Symbol shtSRW	= %00000110	' Status Reg Write
Symbol shtSRR	= %00000111	' Status Reg Read
Symbol shtRSR	= %00011110	' Soft Reset

Symbol OByte = B0
Symbol IByte = B0
Symbol N = B1

Symbol H = B0
Symbol L = B1

Symbol SOrh = W1
Symbol SOt = W2

Symbol X = W3
Symbol TC_100 = W4
Symbol RH_100 = W5

Symbol T_Diff = B0

Symbol MSBit = B12
Symbol SignBit = B12
Symbol Digit2 = B12


Main:
Top:
   ' soft reset
   GoSub Idle
   GoSub ResetComm
   GoSub TransStart
   OByte = shtRSR
   GoSub WriteByte

   Pause 50

   ' measure the temperature
   GoSub Idle
   GoSub ResetComm
   GoSub TransStart
   OByte = shtMT
   GoSub WriteByte
   Pause 250
   Pause 250
   GoSub ReadByte		' read high byte
   SOt = IByte * 256
   GoSub ReadByte		' read low byte
   SOt = SOt + IByte

   ' H = SOt / 100
   ' L = SOt % 100

   ' SerTxD ("T = ", H, "  ", L, 13)

   ' measure the humidity

   GoSub Idle
   GoSub ResetComm
   GoSub TransStart
   OByte = shtMH		' measure humidity
   GoSub WriteByte
   Pause 250		 ' allow for conversion to complete
   Pause 250
   GoSub ReadByte
   SOrh = IByte * 256
   GoSub ReadByte
   SOrh = SOrh + IByte

'  Do the calculations

   SOrh = SOrh / 16		' use 8 bit

   ' SerTxD ("Point 1 ", #SOrh, 13, 10)

   X = SOrh / 10
   X = SOrh / 100 + X
   X = SOrh / 1000 + X	' 0.112 * SOrh

   X = 100 - X			' 100 - 0.112 * SOrh

   X = X * SOrh
   X = X / 10 * 6		' times 0.648
   X = X / 100 * 4 + X
   X = X / 1000 * 8 + X

   RH_100 = X - 400

   TC_100 = SOt - 4000


   X = SOrh / 10
   X = SOrh * 2 / 100 + X
   X = SOrh * 8 / 1000 + X
   X = X + 1			' 1 + 0.128 * SOrh

   T_diff = TC_100 / 100 - 25
   SignBit = T_diff / 256 / 128

   If SignBit = 1 Then Negative

Positive:
   X = T_diff * X
   RH_100 = RH_100 + X
   GoTo Display

Negative:
   T_diff = T_diff ^ $ff + 1
   X = T_diff * X
   SerTxD ("Point 3 ", #X, 13, 10)

   RH_100 = RH_100 - X
   GoTo Display

Display:
   SignBit = TC_100 / 256 / 128
   X = TC_100
   GoSub DisplayFloat
   SerTxD (" ")
   SignBit = RH_100 / 256 / 128
   If SignBit = 0 Then Display_1 ' it is positive
     SignBit = 0		 ' Oops, it's negative
     X = 0
     GoSub DisplayFloat
     GoTo Display_3

Display_1:
   If RH_100 < 9999 Then Display_2
     X = 9999			  ' limit to 99.99 percent
     GoSub DisplayFloat
     GoTo Display_3

Display_2:     			  ' in range of 0 to 9999
   X = RH_100
   GoSub DisplayFloat

Display_3:
   SerTxD (10, 13)
   Sleep 1

   GoTo Top


Idle:
    Low SCL		' low clock
    High SDAOut 	' high Z on Data
    Return

ResetComm:
    Low SCL 		' low on CLK
    High SDAOut 		' DTA in high Z state

    For N = 1 to 9
	High SCL
	Low SCL
    Next

    Return


TransStart:

    High SDAOut
    Low SCL
    High SCL
    Low SDAOut
    Low SCL
    High SCL
    High SDAOut
    Low SCL

    Return

WriteByte:

    For N = 1 to 8
	MSBit = OByte / 128
      If MSBit = 1 Then WriteByte_1

      Low SDAOut
      Goto WriteByte_2

WriteByte_1:
      High SDAOut

WriteByte_2:

	High SCL
	Low SCL

	OByte = OByte * 2
    Next

    High SDAOut
    High SCL
    Low SCL

    Return

ReadByte:

    High SDAOut
    IByte = $00

    For N = 1 To 8
        High SCL
        IByte = IByte * 2 + SDAIn
        Low SCL
    Next

    Low SDAOut
    High SCL
    Low SCL

    High SDAOut

    Return

DisplayFloat:
    If SignBit = 0 Then DisplayFloat_1
    SerTxD ("-")
DisplayFloat_1:
    Digit2 = X / 100	' display the hundreds
    SerTxD (#Digit2, ".")
    Digit2 = X % 100
    If Digit2 > 9 Then DisplayFloat_2
      SerTxD ("0", #Digit2)	' be sure to put in leading zero
      GoTo DisplayFloat_3
DisplayFloat_2:
    SerTxD (#Digit2)

DisplayFloat_3:
    Return