gobot.io/x/gobot@v1.16.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 "gobot.io/x/gobot" 29 ) 30 31 const ( 32 // SHT2xDefaultAddress is the default I2C address for SHT2x 33 SHT2xDefaultAddress = 0x40 34 35 // SHT2xAccuracyLow is the faster, but lower accuracy sample setting 36 // 0/1 = 8bit RH, 12bit Temp 37 SHT2xAccuracyLow = byte(0x01) 38 39 // SHT2xAccuracyMedium is the medium accuracy and speed sample setting 40 // 1/0 = 10bit RH, 13bit Temp 41 SHT2xAccuracyMedium = byte(0x80) 42 43 // SHT2xAccuracyHigh is the high accuracy and slowest sample setting 44 // 0/0 = 12bit RH, 14bit Temp 45 // Power on default is 0/0 46 SHT2xAccuracyHigh = byte(0x00) 47 48 // SHT2xTriggerTempMeasureHold is the command for measureing temperature in hold master mode 49 SHT2xTriggerTempMeasureHold = 0xe3 50 51 // SHT2xTriggerHumdMeasureHold is the command for measureing humidity in hold master mode 52 SHT2xTriggerHumdMeasureHold = 0xe5 53 54 // SHT2xTriggerTempMeasureNohold is the command for measureing humidity in no hold master mode 55 SHT2xTriggerTempMeasureNohold = 0xf3 56 57 // SHT2xTriggerHumdMeasureNohold is the command for measureing humidity in no hold master mode 58 SHT2xTriggerHumdMeasureNohold = 0xf5 59 60 // SHT2xWriteUserReg is the command for writing user register 61 SHT2xWriteUserReg = 0xe6 62 63 // SHT2xReadUserReg is the command for reading user register 64 SHT2xReadUserReg = 0xe7 65 66 // SHT2xReadUserReg is the command for reading user register 67 SHT2xSoftReset = 0xfe 68 ) 69 70 // SHT2xDriver is a Driver for a SHT2x humidity and temperature sensor 71 type SHT2xDriver struct { 72 Units string 73 74 name string 75 connector Connector 76 connection Connection 77 Config 78 sht2xAddress int 79 accuracy byte 80 delay time.Duration 81 crcTable *crc8.Table 82 } 83 84 // NewSHT2xDriver creates a new driver with specified i2c interface 85 // Params: 86 // conn Connector - the Adaptor to use with this Driver 87 // 88 // Optional params: 89 // i2c.WithBus(int): bus to use with this driver 90 // i2c.WithAddress(int): address to use with this driver 91 // 92 func NewSHT2xDriver(a Connector, options ...func(Config)) *SHT2xDriver { 93 // From the document "CRC Checksum Calculation -- For Safe Communication with SHT2x Sensors": 94 crc8Params := crc8.Params{0x31, 0x00, false, false, 0x00, 0x00, "CRC-8/SENSIRION-SHT2x"} 95 s := &SHT2xDriver{ 96 Units: "C", 97 name: gobot.DefaultName("SHT2x"), 98 connector: a, 99 Config: NewConfig(), 100 crcTable: crc8.MakeTable(crc8Params), 101 } 102 103 for _, option := range options { 104 option(s) 105 } 106 107 return s 108 } 109 110 // Name returns the name for this Driver 111 func (d *SHT2xDriver) Name() string { return d.name } 112 113 // SetName sets the name for this Driver 114 func (d *SHT2xDriver) SetName(n string) { d.name = n } 115 116 // Connection returns the connection for this Driver 117 func (d *SHT2xDriver) Connection() gobot.Connection { return d.connector.(gobot.Connection) } 118 119 // Start initializes the SHT2x 120 func (d *SHT2xDriver) Start() (err error) { 121 bus := d.GetBusOrDefault(d.connector.GetDefaultBus()) 122 address := d.GetAddressOrDefault(SHT2xDefaultAddress) 123 124 if d.connection, err = d.connector.GetConnection(address, bus); err != nil { 125 return 126 } 127 128 if err = d.Reset(); err != nil { 129 return 130 } 131 132 d.sendAccuracy() 133 134 return 135 } 136 137 // Halt returns true if devices is halted successfully 138 func (d *SHT2xDriver) Halt() (err error) { return } 139 140 func (d *SHT2xDriver) Accuracy() byte { return d.accuracy } 141 142 // SetAccuracy sets the accuracy of the sampling 143 func (d *SHT2xDriver) SetAccuracy(acc byte) (err error) { 144 d.accuracy = acc 145 146 if d.connection != nil { 147 err = d.sendAccuracy() 148 } 149 150 return 151 } 152 153 // Reset does a software reset of the device 154 func (d *SHT2xDriver) Reset() (err error) { 155 if err = d.connection.WriteByte(SHT2xSoftReset); err != nil { 156 return 157 } 158 159 time.Sleep(15 * time.Millisecond) // 15ms delay (from the datasheet 5.5) 160 161 return 162 } 163 164 // Temperature returns the current temperature, in celsius degrees. 165 func (d *SHT2xDriver) Temperature() (temp float32, err error) { 166 var rawT uint16 167 if rawT, err = d.readSensor(SHT2xTriggerTempMeasureNohold); err != nil { 168 return 169 } 170 171 // From the datasheet 6.2: 172 // T[C] = -46.85 + 175.72 * St / 2^16 173 temp = -46.85 + 175.72/65536.0*float32(rawT) 174 175 return 176 } 177 178 // Humidity returns the current humidity in percentage of relative humidity 179 func (d *SHT2xDriver) Humidity() (humidity float32, err error) { 180 var rawH uint16 181 if rawH, err = d.readSensor(SHT2xTriggerHumdMeasureNohold); err != nil { 182 return 183 } 184 185 // From the datasheet 6.1: 186 // RH = -6 + 125 * Srh / 2^16 187 humidity = -6.0 + 125.0/65536.0*float32(rawH) 188 189 return 190 } 191 192 // sendCommandDelayGetResponse is a helper function to reduce duplicated code 193 func (d *SHT2xDriver) readSensor(cmd byte) (read uint16, err error) { 194 if err = d.connection.WriteByte(cmd); err != nil { 195 return 196 } 197 198 //Hang out while measurement is taken. 85ms max, page 9 of datasheet. 199 time.Sleep(85 * time.Millisecond) 200 201 //Comes back in three bytes, data(MSB) / data(LSB) / Checksum 202 buf := make([]byte, 3) 203 counter := 0 204 for { 205 var got int 206 got, err = d.connection.Read(buf) 207 counter++ 208 if counter > 50 { 209 return 210 } 211 if err == nil { 212 if got != 3 { 213 err = ErrNotEnoughBytes 214 return 215 } 216 break 217 } 218 time.Sleep(1 * time.Millisecond) 219 } 220 221 //Store the result 222 crc := crc8.Checksum(buf[0:2], d.crcTable) 223 if buf[2] != crc { 224 err = errors.New("Invalid crc") 225 return 226 } 227 read = uint16(buf[0])<<8 | uint16(buf[1]) 228 read &= 0xfffc // clear two low bits (status bits) 229 230 return 231 } 232 233 func (d *SHT2xDriver) sendAccuracy() (err error) { 234 if err = d.connection.WriteByte(SHT2xReadUserReg); err != nil { 235 return 236 } 237 userRegister, err := d.connection.ReadByte() 238 if err != nil { 239 return 240 } 241 242 userRegister &= 0x7e //Turn off the resolution bits 243 acc := d.accuracy 244 acc &= 0x81 //Turn off all other bits but resolution bits 245 userRegister |= acc //Mask in the requested resolution bits 246 247 //Request a write to user register 248 _, err = d.connection.Write([]byte{SHT2xWriteUserReg, userRegister}) 249 if err != nil { 250 return 251 } 252 253 userRegister, err = d.connection.ReadByte() 254 if err != nil { 255 return 256 } 257 258 return 259 }