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.
This discussion focuses on interfacing BX24 with a
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.
' 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
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