gobot.io/x/gobot@v1.16.0/drivers/i2c/bmp280_driver.go (about) 1 package i2c 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "math" 7 8 "gobot.io/x/gobot" 9 ) 10 11 const ( 12 bmp280RegisterControl = 0xf4 13 bmp280RegisterConfig = 0xf5 14 bmp280RegisterPressureData = 0xf7 15 bmp280RegisterTempData = 0xfa 16 bmp280RegisterCalib00 = 0x88 17 bmp280SeaLevelPressure = 1013.25 18 ) 19 20 type bmp280CalibrationCoefficients struct { 21 t1 uint16 22 t2 int16 23 t3 int16 24 p1 uint16 25 p2 int16 26 p3 int16 27 p4 int16 28 p5 int16 29 p6 int16 30 p7 int16 31 p8 int16 32 p9 int16 33 } 34 35 // BMP280Driver is a driver for the BMP280 temperature/pressure sensor 36 type BMP280Driver struct { 37 name string 38 connector Connector 39 connection Connection 40 Config 41 42 tpc *bmp280CalibrationCoefficients 43 } 44 45 // NewBMP280Driver creates a new driver with specified i2c interface. 46 // Params: 47 // conn Connector - the Adaptor to use with this Driver 48 // 49 // Optional params: 50 // i2c.WithBus(int): bus to use with this driver 51 // i2c.WithAddress(int): address to use with this driver 52 // 53 func NewBMP280Driver(c Connector, options ...func(Config)) *BMP280Driver { 54 b := &BMP280Driver{ 55 name: gobot.DefaultName("BMP280"), 56 connector: c, 57 Config: NewConfig(), 58 tpc: &bmp280CalibrationCoefficients{}, 59 } 60 61 for _, option := range options { 62 option(b) 63 } 64 65 // TODO: expose commands to API 66 return b 67 } 68 69 // Name returns the name of the device. 70 func (d *BMP280Driver) Name() string { 71 return d.name 72 } 73 74 // SetName sets the name of the device. 75 func (d *BMP280Driver) SetName(n string) { 76 d.name = n 77 } 78 79 // Connection returns the connection of the device. 80 func (d *BMP280Driver) Connection() gobot.Connection { 81 return d.connector.(gobot.Connection) 82 } 83 84 // Start initializes the BMP280 and loads the calibration coefficients. 85 func (d *BMP280Driver) Start() (err error) { 86 bus := d.GetBusOrDefault(d.connector.GetDefaultBus()) 87 address := d.GetAddressOrDefault(bmp180Address) 88 89 if d.connection, err = d.connector.GetConnection(address, bus); err != nil { 90 return err 91 } 92 93 if err := d.initialization(); err != nil { 94 return err 95 } 96 97 return nil 98 } 99 100 // Halt halts the device. 101 func (d *BMP280Driver) Halt() (err error) { 102 return nil 103 } 104 105 // Temperature returns the current temperature, in celsius degrees. 106 func (d *BMP280Driver) Temperature() (temp float32, err error) { 107 var rawT int32 108 if rawT, err = d.rawTemp(); err != nil { 109 return 0.0, err 110 } 111 temp, _ = d.calculateTemp(rawT) 112 return 113 } 114 115 // Pressure returns the current barometric pressure, in Pa 116 func (d *BMP280Driver) Pressure() (press float32, err error) { 117 var rawT, rawP int32 118 if rawT, err = d.rawTemp(); err != nil { 119 return 0.0, err 120 } 121 122 if rawP, err = d.rawPressure(); err != nil { 123 return 0.0, err 124 } 125 _, tFine := d.calculateTemp(rawT) 126 return d.calculatePress(rawP, tFine), nil 127 } 128 129 // Altitude returns the current altitude in meters based on the 130 // current barometric pressure and estimated pressure at sea level. 131 // Calculation is based on code from Adafruit BME280 library 132 // https://github.com/adafruit/Adafruit_BME280_Library 133 func (d *BMP280Driver) Altitude() (alt float32, err error) { 134 atmP, _ := d.Pressure() 135 atmP /= 100.0 136 alt = float32(44330.0 * (1.0 - math.Pow(float64(atmP/bmp280SeaLevelPressure), 0.1903))) 137 138 return 139 } 140 141 // initialization reads the calibration coefficients. 142 func (d *BMP280Driver) initialization() (err error) { 143 var coefficients []byte 144 if coefficients, err = d.read(bmp280RegisterCalib00, 24); err != nil { 145 return err 146 } 147 buf := bytes.NewBuffer(coefficients) 148 binary.Read(buf, binary.LittleEndian, &d.tpc.t1) 149 binary.Read(buf, binary.LittleEndian, &d.tpc.t2) 150 binary.Read(buf, binary.LittleEndian, &d.tpc.t3) 151 binary.Read(buf, binary.LittleEndian, &d.tpc.p1) 152 binary.Read(buf, binary.LittleEndian, &d.tpc.p2) 153 binary.Read(buf, binary.LittleEndian, &d.tpc.p3) 154 binary.Read(buf, binary.LittleEndian, &d.tpc.p4) 155 binary.Read(buf, binary.LittleEndian, &d.tpc.p5) 156 binary.Read(buf, binary.LittleEndian, &d.tpc.p6) 157 binary.Read(buf, binary.LittleEndian, &d.tpc.p7) 158 binary.Read(buf, binary.LittleEndian, &d.tpc.p8) 159 binary.Read(buf, binary.LittleEndian, &d.tpc.p9) 160 161 d.connection.WriteByteData(bmp280RegisterControl, 0x3F) 162 163 return nil 164 } 165 166 func (d *BMP280Driver) rawTemp() (temp int32, err error) { 167 var data []byte 168 var tp0, tp1, tp2 byte 169 170 if data, err = d.read(bmp280RegisterTempData, 3); err != nil { 171 return 0, err 172 } 173 buf := bytes.NewBuffer(data) 174 binary.Read(buf, binary.LittleEndian, &tp0) 175 binary.Read(buf, binary.LittleEndian, &tp1) 176 binary.Read(buf, binary.LittleEndian, &tp2) 177 178 temp = ((int32(tp2) >> 4) | (int32(tp1) << 4) | (int32(tp0) << 12)) 179 180 return 181 } 182 183 func (d *BMP280Driver) rawPressure() (press int32, err error) { 184 var data []byte 185 var tp0, tp1, tp2 byte 186 187 if data, err = d.read(bmp280RegisterPressureData, 3); err != nil { 188 return 0, err 189 } 190 buf := bytes.NewBuffer(data) 191 binary.Read(buf, binary.LittleEndian, &tp0) 192 binary.Read(buf, binary.LittleEndian, &tp1) 193 binary.Read(buf, binary.LittleEndian, &tp2) 194 195 press = ((int32(tp2) >> 4) | (int32(tp1) << 4) | (int32(tp0) << 12)) 196 197 return 198 } 199 200 func (d *BMP280Driver) calculateTemp(rawTemp int32) (float32, int32) { 201 tcvar1 := ((float32(rawTemp) / 16384.0) - (float32(d.tpc.t1) / 1024.0)) * float32(d.tpc.t2) 202 tcvar2 := (((float32(rawTemp) / 131072.0) - (float32(d.tpc.t1) / 8192.0)) * ((float32(rawTemp) / 131072.0) - float32(d.tpc.t1)/8192.0)) * float32(d.tpc.t3) 203 temperatureComp := (tcvar1 + tcvar2) / 5120.0 204 205 tFine := int32(tcvar1 + tcvar2) 206 return temperatureComp, tFine 207 } 208 209 func (d *BMP280Driver) calculatePress(rawPress int32, tFine int32) float32 { 210 var var1, var2, p int64 211 212 var1 = int64(tFine) - 128000 213 var2 = var1 * var1 * int64(d.tpc.p6) 214 var2 = var2 + ((var1 * int64(d.tpc.p5)) << 17) 215 var2 = var2 + (int64(d.tpc.p4) << 35) 216 var1 = (var1 * var1 * int64(d.tpc.p3) >> 8) + 217 ((var1 * int64(d.tpc.p2)) << 12) 218 var1 = ((int64(1) << 47) + var1) * (int64(d.tpc.p1)) >> 33 219 220 if var1 == 0 { 221 return 0 // avoid exception caused by division by zero 222 } 223 p = 1048576 - int64(rawPress) 224 p = (((p << 31) - var2) * 3125) / var1 225 var1 = (int64(d.tpc.p9) * (p >> 13) * (p >> 13)) >> 25 226 var2 = (int64(d.tpc.p8) * p) >> 19 227 228 p = ((p + var1 + var2) >> 8) + (int64(d.tpc.p7) << 4) 229 return float32(p) / 256 230 } 231 232 func (d *BMP280Driver) read(address byte, n int) ([]byte, error) { 233 if _, err := d.connection.Write([]byte{address}); err != nil { 234 return nil, err 235 } 236 buf := make([]byte, n) 237 bytesRead, err := d.connection.Read(buf) 238 if bytesRead != n || err != nil { 239 return nil, err 240 } 241 return buf, nil 242 }