Interfacing with a Sensirion SHT Relative Humidity and Temperature Sensor

BasicX BX24 and Basic Atom

copyright, Peter H Anderson, Baltimore, MD, Mar, '03


Note. This discussion was originally developed for interfacing with the BasicX BX24. Additional material related to interfacing the SHT11 / SHT71 with the MicroBasic Basic Atom was added in May, '03. This material was developed by undergraduate student Brittany Fleming as a part of her capstone design project at Morgan State University.

Introduction.

This discussion focuses on interfacing BX24 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 x1 and x5 devices is the accuracy of the relative humidity, 3.5 vs 2.0 percent.

As of this writing, Sensirion offers a free sample of the SHT11. However, I was concerned with my ability to solder this 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, one will probably need an 8-pin SOIC to DIP adaptor which I stock for $5.00.

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

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 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 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 conversion.

Note, that as with the I2C protocol, the DATA lead is bidirectional and thus the two states are open (high Z) with an external 4.7K pull up resistor providing the logic one and ground acting as a logic zero. The question often arises, can't I use SHIFTOUT. Technically no, as with SHIFTOUT, the two states are a hard logic one (near +5VDC) and GRD and one could very well find that a hard +5 VDC from the BX24 is sourcing directly to a hard ground on the SHT. Damage might be avoided by using a series 330 Ohms resistor in the DATA lead. Note that in the following routine, I avoided the use of the SHIFTOUT command and thus, this situation of bucking active sources is avoided.

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 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. 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.

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, but I would hesitate to use it for measuring the relative humidity in a grain silo some 200 feet away. A preferred approach might be a slave processor collocated with the SHT device in the 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.


BasicX BX24

' Program SHT71_2.Bas (BX24)
'
' Illustrates an interface with the Sensirion SHT1x/7x Relative Humidity
' and Temperature System.
'
' BX24						SHT1x/7x
'
'          +5VDC
'			|
'			4.7K
'			|
'  Term 14 ------------------ DATA
'  Term 13 ------------------ SCK
'
' Note that terminal designations for the SHT1x differ from the SHT7x.
'
' Illustrates use of Soft Reset to set the SHT status register to the default
' values.
'
' Continually executes a sequence of measuring and calculating temperature and
' relative humidity.  Linearizes relative humidity and performs a temperature
' adjustment.  Calculates the dew point.
'
' Displays temperature, true relative humidity and dew point temperature.
'
' copyright, Peter H. Anderson, Baltimore, MD, Apr, 03
' Calculation of RH corrected, Sept 25, '03

const DATA as byte=14
const SCK as byte=13

const MeasTempCode as Byte = bx0000_0011
const MeasRHCode as Byte = bx0000_0101
const SoftReset as Byte = bx0001_1110

Sub Main()

   Dim RHLinear as Single, RHTrue as Single, TC as Single, TF as Single
   Dim SO_RH as Single, SO_Temp as Single
   Dim EW_RH as Single, DewPointTC as Single, DewPointTF as Single
   Dim H as Byte, L as Byte, CRC as Byte

   Call Sleep(1.0)			' to avoid download problems

   Debug.Print "..............."	' to see that something is happening

   ' be sure there is at least an 11 ms delay after the device is turned on.
   ' soft reset
   Call SHT1xIdle()
   Call SHT1xReset()
   Call SHT1xTransmissionStart()
   Call SHT1xOutByte(SoftReset)
   Call SHT1xIdle()
   Call Sleep(0.025)	' wait more than 11 ms for values to be written
   			' to status register

   Do
    ' measure temperature
      Call SHT1xIdle()
      Call SHT1xReset()
      Call SHT1xTransmissionStart()
      Call SHT1xOutByte(MeasTempCode)
      Call SHT1xWait(0.250)
      H = SHT1xInByte(1)	' High Byte
      L = SHT1xInByte(1)	' Low Byte
      CRC = SHT1xInByte(0)	' CRC
      Call SHT1xIdle()

        ' calculate the temperature
      SO_Temp = CSng ((CInt(H) * 256) + CInt(L))
      TC = -40.0 + 0.01 * SO_Temp
      TF = 1.8 * TC + 32.0
      Debug.Print "Temperature = "; CStr(TF); "  "; CStr(TC); "  "; CStr(H); " "; CStr(L); " "; CStr(CRC)

      ' relative humidity
      Call SHT1xIdle()
      Call SHT1xReset()
      Call SHT1xTransmissionStart()
      Call SHT1xOutByte(MeasRHCode)
      Call SHT1xWait(0.60)
      H = SHT1xInByte(1)	' High Byte
      L = SHT1xInByte(1)	' Low Byte
      CRC = SHT1xInByte(0)	' CRC
      Call SHT1xIdle()

      SO_RH = CSng ((CInt(H) * 256) + CInt(L))
      ' RHLinear =  -4.0 + 0.0405 * SO_RH + 2.8e-6 * SO_RH * SO_RH
      RHLinear =  -4.0 + 0.0405 * SO_RH - 2.8e-6 * SO_RH * SO_RH	' corrected, Sept, 03
      RHTrue = (TC - 25.0) * (0.01 + 0.00008 * SO_RH) + RHLinear

      Debug.Print "RH = "; CStr(RHTrue); "  "; CStr(H); " "; CStr(L); " "; CStr(CRC)

     	' calculate dew point

      EW_RH = exp10(0.6607 + 7.5 * TC / (237.3 + TC)) * RHTrue / 100.0
      DewPointTC = ((0.6607 - log10(EW_RH)) * 237.3) / (log10(EW_RH) - 8.16077)
      DewPointTF = 1.8 * DewPointTC + 32.0

      Debug.Print "Dew Point "; CStr(DewPointTF)

     Call Sleep(1.0)

   Loop

End Sub

Sub SHT1xIdle()
   Call PutPin(SCK, 0)		' DATA high, clock low
   Call PutPin(DATA, 2)
End Sub


Sub SHT1xReset()	' bring DATA high and provide 9 clock pulses
   Dim N as Integer
   Call PutPin(SCK, 0)
   Call PutPin(DATA, 2)

   For N = 1 to 9
      Call PutPin(SCK, 1)
      Call PutPin(SCK, 0)
   Next
End Sub   		' leave with DATA high, SCK low


Sub SHT1xTransmissionStart()
   Call PutPin(DATA, 2)
   Call PutPin(SCK, 1)
   CALL PutPin(DATA, 0)
   Call PutPin(SCK,0)		' negative clock pulse
   Call PutPin(SCK, 1)
   Call PutPin(DATA,2)
   Call PutPin(SCK, 0)		' leave with DATA high and SCK low
End Sub

Sub SHT1xOutByte(ByVal X as Byte)	' SCK is low

   Dim N as Integer

   For N=1 to 8

     If((X AND &H80) <> 0) Then
       Call PutPin(DATA,2)
'      Call PutByte(Asc("1"))   ' used for debugging
     Else
       Call PutPin(DATA,0)
'      Call PutByte(Asc("0"))	' used for debugging
    End If

    Call PutPin(SCK,1)
    Call PutPin(SCK,0)
    X = X*2

   Next

'  Call NewLine()		' used for debugging

   Call PutPin(DATA,2)
   Call PutPin(SCK,1)
   Call PutPin(SCK,0)
   Call PutPin(DATA,2)

End Sub

Sub SHT1xWait(ByVal X as Single)
   Call Sleep(X)
End Sub

Function SHT1xInByte(ByVal Ack as Byte) as Byte

   Dim N as Integer
   Dim X as Byte

   For N=1 to 8

    Call PutPin(SCK,1)
    If(GetPin(DATA)=1) Then
      X = X * 2 +1
    Else
      X = X * 2
    End If
    Call PutPin(SCK, 0)
   Next

   If (Ack <> 0) Then
      Call PutPin(DATA, 0)
   Else
      Call PutPin(DATA,2)
   End If

   Call PutPin(SCK,1)
   Call PutPin(SCK,0)
   Call PutPin(DATA,2)	' leave routine with DATA high and CLK low
   SHT1xInByte = X

End Function


Basic Atom

The following routine developed by undergraduate Brittany Fleming follows the general flow of the BX24 routine.

We had considerable difficulty with the floating point math routines. In the end, we concluded that use of the In Circuit Debugger resulted in the erroneous display of floats floats and we ultimately used the SerOut command. However, prior to reaching that conclusion, a considerable amount of time was spent tinkering with various approaches, including the use of intermediate variables and avoiding negative numbers. The final implementation is not elegant and there is probably a far clearer approach.

Note that the Dew Point is not calculated as the Basic Atom does not have the required "exp" and "ln" math functions.

' SHT_71Atom.Bas  (Basic Atom)
'
' Illustrates an interface with the Sensirion SHT1x/7x Relative Humidity
' and Temperature System.
'
' Basic Atom               SHT1x/7x
'
'              +5VDC
'		|
'		4.7K
'		|
'  P3 ----------------------- DATA
'  P2 ----------------------- SCK
'
' Note that terminal designations for the SHT1x differ from the SHT7x.
'
' Illustrates use of Soft Reset to set the SHT status register to the default
' values.
'
' Continually executes a sequence of measuring and calculating temperature and
' relative humidity.  Linearizizes relative humidity and performs a temperature
' adjustment.
'
' Displays temperature and true relative humidity.
'
' copyright, Brittany Chantay Fleming, Peter H Anderson, Baltimore, MD, May, '03
'_______________________________________________________
'                             Pin Functions
'_______________________________________________________
SCK 	Var Out2
SCKDir  Var Dir2
DTA	Var Out3
DTADir	Var Dir3
DTAIn	Var In3

'______________________________________________________
'                             SHT 11/71 Commands
'_______________________________________________________


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

'_______________________________________________________
'                  Defined Variables
'_______________________________________________________

N 	Var Byte
OByte	Var Byte
IByte	Var Byte
SOrh	Var Word
SOt	Var Word

C1	Var Long	' for Humidity Calculation
C2 	Var Long
C3	Var Long

D1	Var Long	' for Temperature Calculation
D2	Var long

T1	Var Long	' for temperature correction of RH
T2 	Var Long

Temp1 Var Long
Temp2 Var Long
Temp3 Var Long


RH	Var Long
Tc  Var Long
RHCorrected Var Long


'_______________________________________________________
'                             Main Loop
'_______________________________________________________

Main:

   While 1

        SCKDir = 0		' clock is always an output

        ' 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 500
	GoSub ReadByte		' read high byte
	SOt.Byte1 = IByte
	GoSub ReadByte		' read low byte
	SOt.Byte0 = IByte

	' Debug ["TEMP = ", dec SOt, 13]

	' measure the humidity

	GoSub Idle
	GoSub ResetComm
	GoSub TransStart
	OByte = shtMH		' measure humidity
	GoSub WriteByte
	Pause 500		 ' allow for conversion to complete
	GoSub ReadByte
	SOrh.Byte1 = IByte
	GoSub ReadByte
	SOrh.Byte0 = IByte

	' Debug ["HUMI = ", dec SOrh, 13]

	' Now calculate RH = -4.0 + 0.0405 * SOrh - 2.8e-6 * SOrh^2
	C1 = 4.0			' positive coefficients were used
	C2 = 0.0405
	C3 = 0.000002.8

	Temp1 = FLOAT SOrh		' SOrh
	Temp2 = Temp1
	Temp3 = Temp2 FMUL Temp1 ' SOrh ^2

	Temp4 = Temp1 FMUL C2	' C2 * SOrh
	Temp2 = Temp3 FMUL C3   ' C3 * SOrh^2

	RH =  FNEG C1 FADD Temp4 FSUB Temp2

    ' Calculate Temperature	Tc = -40.0 + 0.01 * SOt
    D1 = 40.0	' -40.0
    D2 = 0.01

    Temp1 = FLOAT SOt
    Temp2 = Temp1 FMUL D2

    Tc = FNEG D1 FADD Temp2

    ' Now, RHCorrected = (Tc - 25.0) * (T1 + T2 * SOrh) + RH

    T1 = 0.01
    T2 = 0.00008

    Temp1 = FLOAT SOrh
    Temp2 = Temp1 FMUL T2
    Temp1 = T1 FADD Temp2	' T1 + T2 * SOrh

    Temp2 = 25.0
    Temp3 = Tc FSUB Temp2

    RHCorrected =  (Temp1 FMUL Temp3) FADD RH

	SerOut S_OUT, i9600, ["RH = ", Real RH, "  Tc = ", Real Tc]
	SerOut S_OUT, i9600, ["  RHCorrected = ", Real RHCorrected, 13]

   Wend

Idle:
    SCK = 0		' low clock
    DTADir = 1	' high Z on Data
    Return

ResetComm:
    SCK = 0		' low on CLK
    DTADir = 1	' DTA in high Z state

    For N = 1 to 9
	SCK = 1
	SCK = 0
    Next

    Return


TransStart:

    DTADir = 1
    SCK = 0
    SCK = 1
    DTA = 0
    DTADir = 0
    SCK = 0
    SCK = 1
    DTADir = 1
    SCK = 0

    Return

WriteByte:

    For N = 1 to 8
	If ((OByte/128) <> 0) Then
	   DTADir = 1
	Else
	   DTA = 0
	   DTADir = 0
	EndIf

	SCK = 1
	SCK = 0

	OByte = OByte * 2

    Next

    DTADir = 1
    SCK = 1
    SCK = 0

    Return

ReadByte:

    DTADir = 1
    IByte = $00

    For N = 1 To 8
        SCK = 1
        IByte = (IByte * 2) + DTAIn
        SCK = 0
    Next

    DTA = 0
    DTADir = 0
    SCK = 1
    SCK = 0

    DTADir = 1

    Return