i2c: functional bmp180 temperature/pressure and bme280 humidity

Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
deadprogram 2017-03-31 23:00:03 +02:00
parent c573ba99ac
commit bdb24109af
2 changed files with 78 additions and 41 deletions

View File

@ -3,8 +3,10 @@ package i2c
import (
"bytes"
"encoding/binary"
"errors"
)
const bme280RegisterControlHumidity = 0xF2
const bme280RegisterHumidityMSB = 0xFD
const bme280RegisterCalibDigH1 = 0xa1
const bme280RegisterCalibDigH2LSB = 0xe1
@ -68,7 +70,7 @@ func (d *BME280Driver) Start() (err error) {
// Humidity returns the current humidity in percentage of relative humidity
func (d *BME280Driver) Humidity() (humidity float32, err error) {
var rawH int32
var rawH uint32
if rawH, err = d.rawHumidity(); err != nil {
return 0.0, err
}
@ -105,46 +107,52 @@ func (d *BME280Driver) initHumidity() (err error) {
d.hc.h4 = 0 + (int16(addrE4) << 4) | (int16(addrE5 & 0x0F))
d.hc.h5 = 0 + (int16(addrE6) << 4) | (int16(addrE5) >> 4)
d.connection.WriteByteData(bme280RegisterControlHumidity, 0x3F)
return nil
}
func (d *BME280Driver) rawHumidity() (int32, error) {
func (d *BME280Driver) rawHumidity() (uint32, error) {
ret, err := d.read(bme280RegisterHumidityMSB, 2)
if err != nil {
return 0, err
}
if ret[0] == 0x80 && ret[1] == 0x00 {
return 0, errors.New("Humidity disabled")
}
buf := bytes.NewBuffer(ret)
var rawH int32
var rawH uint16
binary.Read(buf, binary.BigEndian, &rawH)
return rawH, nil
return uint32(rawH), nil
}
// Adapted from https://github.com/BoschSensortec/BME280_driver/blob/master/bme280.c
// function bme280_compensate_humidity_double(s32 v_uncom_humidity_s32)
func (d *BME280Driver) calculateHumidity(rawH int32) float32 {
func (d *BME280Driver) calculateHumidity(rawH uint32) float32 {
var rawT int32
var err error
var h float32
rawT, _, err = d.rawTempPress()
rawT, err = d.rawTemp()
if err != nil {
return 0
}
_, tFine := d.calculateTemp(rawT)
h = float32(tFine - 76800)
h = float32(tFine) - 76800
if h == 0 {
return 0 // TODO err is 'invalid data' from Bosch - include errors or not?
}
h = (float32(rawH) - (float32(d.hc.h4) * 64.0) + // H4 double * 64.0 double
(float32(d.hc.h5) / 16384.0 * h)) // H5 double / 16384.0 * var_h
x := float32(rawH) - (float32(d.hc.h4)*64.0 +
(float32(d.hc.h5) / 16384.0 * h))
y :=
(float32(d.hc.h2) / 65536.0) * // H2 double / 65536.0
(1.0 + float32(d.hc.h6)/67108864.0*h) * // 1.0 + (H6 double / 67108664.0 * var_h
(1.0 + float32(d.hc.h3)/67108864.0*h) // 1.0 + H3 double / 67108864.0 * var_h
y := float32(d.hc.h2) / 65536.0 *
(1.0 + float32(d.hc.h6)/67108864.0*h*
(1.0+float32(d.hc.h3)/67108864.0*h))
return h * y
h = x * y
h = h * (1 - float32(d.hc.h1)*h/524288)
return h
}

View File

@ -7,8 +7,14 @@ import (
"gobot.io/x/gobot"
)
const (
bmp280RegisterControl = 0xf4
bmp280RegisterConfig = 0xf5
bmp280RegisterPressureData = 0xf7
bmp280RegisterTempData = 0xfa
)
const bmp280RegisterCalib00 = 0x88
const bme280RegisterPressureMSB = 0xf7
type bmp280CalibrationCoefficients struct {
t1 uint16
@ -98,7 +104,7 @@ func (d *BMP280Driver) Halt() (err error) {
// Temperature returns the current temperature, in celsius degrees.
func (d *BMP280Driver) Temperature() (temp float32, err error) {
var rawT int32
if rawT, _, err = d.rawTempPress(); err != nil {
if rawT, err = d.rawTemp(); err != nil {
return 0.0, err
}
temp, _ = d.calculateTemp(rawT)
@ -108,7 +114,11 @@ func (d *BMP280Driver) Temperature() (temp float32, err error) {
// Pressure returns the current barometric pressure, in Pa
func (d *BMP280Driver) Pressure() (press float32, err error) {
var rawT, rawP int32
if rawT, rawP, err = d.rawTempPress(); err != nil {
if rawT, err = d.rawTemp(); err != nil {
return 0.0, err
}
if rawP, err = d.rawPressure(); err != nil {
return 0.0, err
}
_, tFine := d.calculateTemp(rawT)
@ -120,7 +130,7 @@ func (d *BMP280Driver) initialization() (err error) {
// TODO: set sleep mode here...
var coefficients []byte
if coefficients, err = d.read(bmp280RegisterCalib00, 26); err != nil {
if coefficients, err = d.read(bmp280RegisterCalib00, 24); err != nil {
return err
}
buf := bytes.NewBuffer(coefficients)
@ -137,28 +147,43 @@ func (d *BMP280Driver) initialization() (err error) {
binary.Read(buf, binary.LittleEndian, &d.tpc.p8)
binary.Read(buf, binary.LittleEndian, &d.tpc.p9)
d.connection.WriteByteData(bmp280RegisterControl, 0x3F)
// TODO: set usage mode here...
// TODO: set default sea level here
return nil
}
func (d *BMP280Driver) rawTempPress() (temp int32, press int32, err error) {
func (d *BMP280Driver) rawTemp() (temp int32, err error) {
var data []byte
var tp0, tp1, tp2, tp3, tp4, tp5 byte
var tp0, tp1, tp2 byte
if data, err = d.read(bme280RegisterPressureMSB, 6); err != nil {
return 0, 0, err
if data, err = d.read(bmp280RegisterTempData, 3); err != nil {
return 0, err
}
buf := bytes.NewBuffer(data)
binary.Read(buf, binary.LittleEndian, &tp0)
binary.Read(buf, binary.LittleEndian, &tp1)
binary.Read(buf, binary.LittleEndian, &tp2)
temp = ((int32(tp2) >> 4) | (int32(tp1) << 4) | (int32(tp0) << 12))
return
}
func (d *BMP280Driver) rawPressure() (press int32, err error) {
var data []byte
var tp0, tp1, tp2 byte
if data, err = d.read(bmp280RegisterPressureData, 3); err != nil {
return 0, err
}
buf := bytes.NewBuffer(data)
binary.Read(buf, binary.LittleEndian, &tp0)
binary.Read(buf, binary.LittleEndian, &tp1)
binary.Read(buf, binary.LittleEndian, &tp2)
binary.Read(buf, binary.LittleEndian, &tp3)
binary.Read(buf, binary.LittleEndian, &tp4)
binary.Read(buf, binary.LittleEndian, &tp5)
temp = ((int32(tp5) >> 4) | (int32(tp4) << 4) | (int32(tp3) << 12))
press = ((int32(tp2) >> 4) | (int32(tp1) << 4) | (int32(tp0) << 12))
return
@ -174,22 +199,26 @@ func (d *BMP280Driver) calculateTemp(rawTemp int32) (float32, int32) {
}
func (d *BMP280Driver) calculatePress(rawPress int32, tFine int32) float32 {
pcvar1 := (float32(tFine) / 2.0) - 64000.0
pcvar2 := pcvar1 * pcvar1 * (float32(d.tpc.p6)) / 32768.0
pcvar2 = pcvar2 + pcvar1*(float32(d.tpc.p5))*2.0
pcvar2 = (pcvar2 / 4.0) + (float32(d.tpc.p4) * 65536.0)
pcvar1 = (float32(d.tpc.p3)*pcvar1*pcvar1/524288.0 + float32(d.tpc.p2)*pcvar1) / 524288.0
pcvar1 = (1.0 + pcvar1/32768.0) * (float32(d.tpc.p1))
if pcvar1 == 0.0 { // avoid divide by zero
return 0.0
}
pressureComp := 1048576.0 - float32(rawPress)
pressureComp = (pressureComp - (pcvar2 / 4096.0)) * (6250.0 / pcvar1)
pcvar1 = float32(d.tpc.p9) * pressureComp * pressureComp / 2147483648.0
pcvar2 = pressureComp * float32(d.tpc.p8) / 32768.0
pressureComp = pressureComp + (pcvar1+pcvar2+float32(d.tpc.p7))/16.0
var var1, var2, p int64
return pressureComp
var1 = int64(tFine) - 128000
var2 = var1 * var1 * int64(d.tpc.p6)
var2 = var2 + ((var1 * int64(d.tpc.p5)) << 17)
var2 = var2 + (int64(d.tpc.p4) << 35)
var1 = (var1 * var1 * int64(d.tpc.p3) >> 8) +
((var1 * int64(d.tpc.p2)) << 12)
var1 = ((int64(1) << 47) + var1) * (int64(d.tpc.p1)) >> 33
if var1 == 0 {
return 0 // avoid exception caused by division by zero
}
p = 1048576 - int64(rawPress)
p = (((p << 31) - var2) * 3125) / var1
var1 = (int64(d.tpc.p9) * (p >> 13) * (p >> 13)) >> 25
var2 = (int64(d.tpc.p8) * p) >> 19
p = ((p + var1 + var2) >> 8) + (int64(d.tpc.p7) << 4)
return float32(p) / 256
}
func (d *BMP280Driver) read(address byte, n int) ([]byte, error) {