gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/sht2x_driver.go (about) 1 /* 2 * Copyright (c) 2016-2017 Weston Schmidt <weston_schmidt@alumni.purdue.edu> 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package i2c 18 19 // SHT2xDriver is a driver for the SHT2x based devices. 20 // 21 // This module was tested with Sensirion SHT21 Breakout. 22 23 import ( 24 "errors" 25 "time" 26 27 "github.com/sigurn/crc8" 28 ) 29 30 const sht2xDefaultAddress = 0x40 31 32 const ( 33 // SHT2xAccuracyLow is the faster, but lower accuracy sample setting 34 // 0/1 = 8bit RH, 12bit Temp 35 SHT2xAccuracyLow = byte(0x01) 36 37 // SHT2xAccuracyMedium is the medium accuracy and speed sample setting 38 // 1/0 = 10bit RH, 13bit Temp 39 SHT2xAccuracyMedium = byte(0x80) 40 41 // SHT2xAccuracyHigh is the high accuracy and slowest sample setting 42 // 0/0 = 12bit RH, 14bit Temp 43 // Power on default is 0/0 44 SHT2xAccuracyHigh = byte(0x00) 45 46 // SHT2xTriggerTempMeasureHold is the command for measureing temperature in hold master mode 47 SHT2xTriggerTempMeasureHold = 0xe3 48 49 // SHT2xTriggerHumdMeasureHold is the command for measureing humidity in hold master mode 50 SHT2xTriggerHumdMeasureHold = 0xe5 51 52 // SHT2xTriggerTempMeasureNohold is the command for measureing humidity in no hold master mode 53 SHT2xTriggerTempMeasureNohold = 0xf3 54 55 // SHT2xTriggerHumdMeasureNohold is the command for measureing humidity in no hold master mode 56 SHT2xTriggerHumdMeasureNohold = 0xf5 57 58 // SHT2xWriteUserReg is the command for writing user register 59 SHT2xWriteUserReg = 0xe6 60 61 // SHT2xReadUserReg is the command for reading user register 62 SHT2xReadUserReg = 0xe7 63 64 // SHT2xReadUserReg is the command for reading user register 65 SHT2xSoftReset = 0xfe 66 ) 67 68 // SHT2xDriver is a Driver for a SHT2x humidity and temperature sensor 69 type SHT2xDriver struct { 70 *Driver 71 Units string 72 sht2xAddress int 73 accuracy byte 74 delay time.Duration 75 crcTable *crc8.Table 76 } 77 78 // NewSHT2xDriver creates a new driver with specified i2c interface 79 // Params: 80 // c Connector - the Adaptor to use with this Driver 81 // 82 // Optional params: 83 // i2c.WithBus(int): bus to use with this driver 84 // i2c.WithAddress(int): address to use with this driver 85 // 86 func NewSHT2xDriver(c Connector, options ...func(Config)) *SHT2xDriver { 87 // From the document "CRC Checksum Calculation -- For Safe Communication with SHT2x Sensors": 88 crc8Params := crc8.Params{ 89 Poly: 0x31, 90 Init: 0x00, 91 RefIn: false, 92 RefOut: false, 93 XorOut: 0x00, 94 Check: 0x00, 95 Name: "CRC-8/SENSIRION-SHT2x", 96 } 97 d := &SHT2xDriver{ 98 Driver: NewDriver(c, "SHT2x", sht2xDefaultAddress), 99 Units: "C", 100 crcTable: crc8.MakeTable(crc8Params), 101 } 102 d.afterStart = d.initialize 103 104 for _, option := range options { 105 option(d) 106 } 107 108 return d 109 } 110 111 func (d *SHT2xDriver) Accuracy() byte { return d.accuracy } 112 113 // SetAccuracy sets the accuracy of the sampling 114 func (d *SHT2xDriver) SetAccuracy(acc byte) (err error) { 115 d.accuracy = acc 116 117 if d.connection != nil { 118 err = d.sendAccuracy() 119 } 120 121 return 122 } 123 124 // Reset does a software reset of the device 125 func (d *SHT2xDriver) Reset() (err error) { 126 if err = d.connection.WriteByte(SHT2xSoftReset); err != nil { 127 return 128 } 129 130 time.Sleep(15 * time.Millisecond) // 15ms delay (from the datasheet 5.5) 131 132 return 133 } 134 135 // Temperature returns the current temperature, in celsius degrees. 136 func (d *SHT2xDriver) Temperature() (temp float32, err error) { 137 var rawT uint16 138 if rawT, err = d.readSensor(SHT2xTriggerTempMeasureNohold); err != nil { 139 return 140 } 141 142 // From the datasheet 6.2: 143 // T[C] = -46.85 + 175.72 * St / 2^16 144 temp = -46.85 + 175.72/65536.0*float32(rawT) 145 146 return 147 } 148 149 // Humidity returns the current humidity in percentage of relative humidity 150 func (d *SHT2xDriver) Humidity() (humidity float32, err error) { 151 var rawH uint16 152 if rawH, err = d.readSensor(SHT2xTriggerHumdMeasureNohold); err != nil { 153 return 154 } 155 156 // From the datasheet 6.1: 157 // RH = -6 + 125 * Srh / 2^16 158 humidity = -6.0 + 125.0/65536.0*float32(rawH) 159 160 return 161 } 162 163 // sendCommandDelayGetResponse is a helper function to reduce duplicated code 164 func (d *SHT2xDriver) readSensor(cmd byte) (read uint16, err error) { 165 if err = d.connection.WriteByte(cmd); err != nil { 166 return 167 } 168 169 //Hang out while measurement is taken. 85ms max, page 9 of datasheet. 170 time.Sleep(85 * time.Millisecond) 171 172 //Comes back in three bytes, data(MSB) / data(LSB) / Checksum 173 buf := make([]byte, 3) 174 counter := 0 175 for { 176 var got int 177 got, err = d.connection.Read(buf) 178 counter++ 179 if counter > 50 { 180 return 181 } 182 if err == nil { 183 if got != 3 { 184 err = ErrNotEnoughBytes 185 return 186 } 187 break 188 } 189 time.Sleep(1 * time.Millisecond) 190 } 191 192 //Store the result 193 crc := crc8.Checksum(buf[0:2], d.crcTable) 194 if buf[2] != crc { 195 err = errors.New("Invalid crc") 196 return 197 } 198 read = uint16(buf[0])<<8 | uint16(buf[1]) 199 read &= 0xfffc // clear two low bits (status bits) 200 201 return 202 } 203 204 func (d *SHT2xDriver) initialize() error { 205 if err := d.Reset(); err != nil { 206 return err 207 } 208 209 d.sendAccuracy() 210 211 return nil 212 } 213 214 func (d *SHT2xDriver) sendAccuracy() error { 215 if err := d.connection.WriteByte(SHT2xReadUserReg); err != nil { 216 return err 217 } 218 userRegister, err := d.connection.ReadByte() 219 if err != nil { 220 return err 221 } 222 223 userRegister &= 0x7e //Turn off the resolution bits 224 acc := d.accuracy 225 acc &= 0x81 //Turn off all other bits but resolution bits 226 userRegister |= acc //Mask in the requested resolution bits 227 228 //Request a write to user register 229 if _, err := d.connection.Write([]byte{SHT2xWriteUserReg, userRegister}); err != nil { 230 return err 231 } 232 233 if _, err := d.connection.ReadByte(); err != nil { 234 return err 235 } 236 237 return nil 238 }