gobot.io/x/gobot@v1.16.0/drivers/i2c/bmp180_driver.go (about) 1 package i2c 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "time" 7 8 "gobot.io/x/gobot" 9 ) 10 11 const bmp180Address = 0x77 12 13 const bmp180RegisterAC1MSB = 0xAA 14 15 const bmp180RegisterCtl = 0xF4 16 const bmp180CmdTemp = 0x2E 17 const bmp180RegisterTempMSB = 0xF6 18 const bmp180CmdPressure = 0x34 19 const bmp180RegisterPressureMSB = 0xF6 20 21 const ( 22 // BMP180UltraLowPower is the lowest oversampling mode of the pressure measurement. 23 BMP180UltraLowPower BMP180OversamplingMode = iota 24 // BMP180Standard is the standard oversampling mode of the pressure measurement. 25 BMP180Standard 26 // BMP180HighResolution is a high oversampling mode of the pressure measurement. 27 BMP180HighResolution 28 // BMP180UltraHighResolution is the highest oversampling mode of the pressure measurement. 29 BMP180UltraHighResolution 30 ) 31 32 // BMP180OversamplingMode is the oversampling ratio of the pressure measurement. 33 type BMP180OversamplingMode uint 34 35 type calibrationCoefficients struct { 36 ac1 int16 37 ac2 int16 38 ac3 int16 39 ac4 uint16 40 ac5 uint16 41 ac6 uint16 42 b1 int16 43 b2 int16 44 mb int16 45 mc int16 46 md int16 47 } 48 49 // BMP180Driver is the gobot driver for the Bosch pressure sensor BMP180. 50 // Device datasheet: https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf 51 type BMP180Driver struct { 52 name string 53 Mode BMP180OversamplingMode 54 connector Connector 55 connection Connection 56 Config 57 calibrationCoefficients *calibrationCoefficients 58 } 59 60 // NewBMP180Driver creates a new driver with the i2c interface for the BMP180 device. 61 // Params: 62 // conn Connector - the Adaptor to use with this Driver 63 // 64 // Optional params: 65 // i2c.WithBus(int): bus to use with this driver 66 // i2c.WithAddress(int): address to use with this driver 67 // 68 func NewBMP180Driver(c Connector, options ...func(Config)) *BMP180Driver { 69 b := &BMP180Driver{ 70 name: gobot.DefaultName("BMP180"), 71 connector: c, 72 Mode: BMP180UltraLowPower, 73 Config: NewConfig(), 74 calibrationCoefficients: &calibrationCoefficients{}, 75 } 76 77 for _, option := range options { 78 option(b) 79 } 80 81 // TODO: expose commands to API 82 return b 83 } 84 85 // Name returns the name of the device. 86 func (d *BMP180Driver) Name() string { 87 return d.name 88 } 89 90 // SetName sets the name of the device. 91 func (d *BMP180Driver) SetName(n string) { 92 d.name = n 93 } 94 95 // Connection returns the connection of the device. 96 func (d *BMP180Driver) Connection() gobot.Connection { 97 return d.connector.(gobot.Connection) 98 } 99 100 // Start initializes the BMP180 and loads the calibration coefficients. 101 func (d *BMP180Driver) Start() (err error) { 102 bus := d.GetBusOrDefault(d.connector.GetDefaultBus()) 103 address := d.GetAddressOrDefault(bmp180Address) 104 105 if d.connection, err = d.connector.GetConnection(address, bus); err != nil { 106 return err 107 } 108 if err := d.initialization(); err != nil { 109 return err 110 } 111 return nil 112 } 113 114 func (d *BMP180Driver) initialization() (err error) { 115 var coefficients []byte 116 // read the 11 calibration coefficients. 117 if coefficients, err = d.read(bmp180RegisterAC1MSB, 22); err != nil { 118 return err 119 } 120 buf := bytes.NewBuffer(coefficients) 121 binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.ac1) 122 binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.ac2) 123 binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.ac3) 124 binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.ac4) 125 binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.ac5) 126 binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.ac6) 127 binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.b1) 128 binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.b2) 129 binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.mb) 130 binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.mc) 131 binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.md) 132 133 return nil 134 } 135 136 // Halt halts the device. 137 func (d *BMP180Driver) Halt() (err error) { 138 return nil 139 } 140 141 // Temperature returns the current temperature, in celsius degrees. 142 func (d *BMP180Driver) Temperature() (temp float32, err error) { 143 var rawTemp int16 144 if rawTemp, err = d.rawTemp(); err != nil { 145 return 0, err 146 } 147 return d.calculateTemp(rawTemp), nil 148 } 149 150 // Pressure returns the current pressure, in pascals. 151 func (d *BMP180Driver) Pressure() (pressure float32, err error) { 152 var rawTemp int16 153 var rawPressure int32 154 if rawTemp, err = d.rawTemp(); err != nil { 155 return 0, err 156 } 157 if rawPressure, err = d.rawPressure(d.Mode); err != nil { 158 return 0, err 159 } 160 return d.calculatePressure(rawTemp, rawPressure, d.Mode), nil 161 } 162 163 func (d *BMP180Driver) rawTemp() (int16, error) { 164 if _, err := d.connection.Write([]byte{bmp180RegisterCtl, bmp180CmdTemp}); err != nil { 165 return 0, err 166 } 167 time.Sleep(5 * time.Millisecond) 168 ret, err := d.read(bmp180RegisterTempMSB, 2) 169 if err != nil { 170 return 0, err 171 } 172 buf := bytes.NewBuffer(ret) 173 var rawTemp int16 174 binary.Read(buf, binary.BigEndian, &rawTemp) 175 return rawTemp, nil 176 } 177 178 func (d *BMP180Driver) read(address byte, n int) ([]byte, error) { 179 if _, err := d.connection.Write([]byte{address}); err != nil { 180 return nil, err 181 } 182 buf := make([]byte, n) 183 bytesRead, err := d.connection.Read(buf) 184 if bytesRead != n || err != nil { 185 return nil, err 186 } 187 return buf, nil 188 } 189 190 func (d *BMP180Driver) calculateTemp(rawTemp int16) float32 { 191 b5 := d.calculateB5(rawTemp) 192 t := (b5 + 8) >> 4 193 return float32(t) / 10 194 } 195 196 func (d *BMP180Driver) calculateB5(rawTemp int16) int32 { 197 x1 := (int32(rawTemp) - int32(d.calibrationCoefficients.ac6)) * int32(d.calibrationCoefficients.ac5) >> 15 198 x2 := int32(d.calibrationCoefficients.mc) << 11 / (x1 + int32(d.calibrationCoefficients.md)) 199 return x1 + x2 200 } 201 202 func (d *BMP180Driver) rawPressure(mode BMP180OversamplingMode) (rawPressure int32, err error) { 203 if _, err = d.connection.Write([]byte{bmp180RegisterCtl, bmp180CmdPressure + byte(mode<<6)}); err != nil { 204 return 0, err 205 } 206 time.Sleep(pauseForReading(mode)) 207 var ret []byte 208 if ret, err = d.read(bmp180RegisterPressureMSB, 3); err != nil { 209 return 0, err 210 } 211 rawPressure = (int32(ret[0])<<16 + int32(ret[1])<<8 + int32(ret[2])) >> (8 - uint(mode)) 212 return rawPressure, nil 213 } 214 215 func (d *BMP180Driver) calculatePressure(rawTemp int16, rawPressure int32, mode BMP180OversamplingMode) float32 { 216 b5 := d.calculateB5(rawTemp) 217 b6 := b5 - 4000 218 x1 := (int32(d.calibrationCoefficients.b2) * (b6 * b6 >> 12)) >> 11 219 x2 := (int32(d.calibrationCoefficients.ac2) * b6) >> 11 220 x3 := x1 + x2 221 b3 := (((int32(d.calibrationCoefficients.ac1)*4 + x3) << uint(mode)) + 2) >> 2 222 x1 = (int32(d.calibrationCoefficients.ac3) * b6) >> 13 223 x2 = (int32(d.calibrationCoefficients.b1) * ((b6 * b6) >> 12)) >> 16 224 x3 = ((x1 + x2) + 2) >> 2 225 b4 := (uint32(d.calibrationCoefficients.ac4) * uint32(x3+32768)) >> 15 226 b7 := (uint32(rawPressure-b3) * (50000 >> uint(mode))) 227 var p int32 228 if b7 < 0x80000000 { 229 p = int32((b7 << 1) / b4) 230 } else { 231 p = int32((b7 / b4) << 1) 232 } 233 x1 = (p >> 8) * (p >> 8) 234 x1 = (x1 * 3038) >> 16 235 x2 = (-7357 * p) >> 16 236 return float32(p + ((x1 + x2 + 3791) >> 4)) 237 } 238 239 func pauseForReading(mode BMP180OversamplingMode) time.Duration { 240 var d time.Duration 241 switch mode { 242 case BMP180UltraLowPower: 243 d = 5 * time.Millisecond 244 case BMP180Standard: 245 d = 8 * time.Millisecond 246 case BMP180HighResolution: 247 d = 14 * time.Millisecond 248 case BMP180UltraHighResolution: 249 d = 26 * time.Millisecond 250 } 251 return d 252 }