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
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.
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) ------------------------------- CLKWhen 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.
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.
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 * SHtMultiplying by 100;
TC_100 = -4000 + SHtThe relative humidity is then compensated for temperature;
RH_true = (Tc - 25) * (0.01 + 0.00128 * SOrh) + RH_linearMultiplying by 100;
RH_true_100 = (Tc - 25) * (1.0 + 0.128 * SOrh) + RH_100Note 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
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