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