mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-18 13:43:58 +00:00
bme280: improve config support
This commit is contained in:
+115
-5
@@ -7,6 +7,7 @@ package bme280
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
)
|
)
|
||||||
@@ -33,11 +34,27 @@ type calibrationCoefficients struct {
|
|||||||
h6 int8
|
h6 int8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Oversampling byte
|
||||||
|
type Mode byte
|
||||||
|
type FilterCoefficient byte
|
||||||
|
type Period byte
|
||||||
|
|
||||||
|
// Config contains settings for filtering, sampling, and modes of operation
|
||||||
|
type Config struct {
|
||||||
|
Pressure Oversampling
|
||||||
|
Temperature Oversampling
|
||||||
|
Humidity Oversampling
|
||||||
|
Period Period
|
||||||
|
Mode Mode
|
||||||
|
IIR FilterCoefficient
|
||||||
|
}
|
||||||
|
|
||||||
// Device wraps an I2C connection to a BME280 device.
|
// Device wraps an I2C connection to a BME280 device.
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.I2C
|
bus drivers.I2C
|
||||||
Address uint16
|
Address uint16
|
||||||
calibrationCoefficients calibrationCoefficients
|
calibrationCoefficients calibrationCoefficients
|
||||||
|
Config Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new BME280 connection. The I2C bus must already be
|
// New creates a new BME280 connection. The I2C bus must already be
|
||||||
@@ -51,9 +68,34 @@ func New(bus drivers.I2C) Device {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure sets up the device for communication and
|
// ConfigureWithSettings sets up the device for communication and
|
||||||
// read the calibration coefficientes.
|
// read the calibration coefficients.
|
||||||
|
//
|
||||||
|
// The default configuration is the Indoor Navigation settings
|
||||||
|
// from the BME280 datasheet.
|
||||||
func (d *Device) Configure() {
|
func (d *Device) Configure() {
|
||||||
|
d.ConfigureWithSettings(Config{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigureWithSettings sets up the device for communication and
|
||||||
|
// read the calibration coefficients.
|
||||||
|
//
|
||||||
|
// The default configuration if config is left at defaults is
|
||||||
|
// the Indoor Navigation settings from the BME280 datasheet.
|
||||||
|
func (d *Device) ConfigureWithSettings(config Config) {
|
||||||
|
d.Config = config
|
||||||
|
|
||||||
|
// If config is not initialized, use Indoor Navigation defaults.
|
||||||
|
if d.Config == (Config{}) {
|
||||||
|
d.Config = Config{
|
||||||
|
Mode: ModeNormal,
|
||||||
|
Period: Period0_5ms,
|
||||||
|
Temperature: Sampling2X,
|
||||||
|
Humidity: Sampling1X,
|
||||||
|
Pressure: Sampling16X,
|
||||||
|
IIR: Coeff16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var data [24]byte
|
var data [24]byte
|
||||||
err := d.bus.ReadRegister(uint8(d.Address), REG_CALIBRATION, data[:])
|
err := d.bus.ReadRegister(uint8(d.Address), REG_CALIBRATION, data[:])
|
||||||
@@ -93,10 +135,18 @@ func (d *Device) Configure() {
|
|||||||
d.calibrationCoefficients.h4 = 0 + (int16(h2lsb[3]) << 4) | (int16(h2lsb[4] & 0x0F))
|
d.calibrationCoefficients.h4 = 0 + (int16(h2lsb[3]) << 4) | (int16(h2lsb[4] & 0x0F))
|
||||||
d.calibrationCoefficients.h5 = 0 + (int16(h2lsb[5]) << 4) | (int16(h2lsb[4]) >> 4)
|
d.calibrationCoefficients.h5 = 0 + (int16(h2lsb[5]) << 4) | (int16(h2lsb[4]) >> 4)
|
||||||
|
|
||||||
d.bus.WriteRegister(uint8(d.Address), CTRL_HUMIDITY_ADDR, []byte{0x3f})
|
d.Reset()
|
||||||
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{0xB7})
|
|
||||||
d.bus.WriteRegister(uint8(d.Address), CTRL_CONFIG, []byte{0x00})
|
|
||||||
|
|
||||||
|
d.bus.WriteRegister(uint8(d.Address), CTRL_CONFIG, []byte{byte(d.Config.Period<<5) | byte(d.Config.IIR<<2)})
|
||||||
|
d.bus.WriteRegister(uint8(d.Address), CTRL_HUMIDITY_ADDR, []byte{byte(d.Config.Humidity)})
|
||||||
|
|
||||||
|
// Normal mode, start measuring now
|
||||||
|
if d.Config.Mode == ModeNormal {
|
||||||
|
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{
|
||||||
|
byte(d.Config.Temperature<<5) |
|
||||||
|
byte(d.Config.Pressure<<2) |
|
||||||
|
byte(d.Config.Mode)})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connected returns whether a BME280 has been found.
|
// Connected returns whether a BME280 has been found.
|
||||||
@@ -112,6 +162,20 @@ func (d *Device) Reset() {
|
|||||||
d.bus.WriteRegister(uint8(d.Address), CMD_RESET, []byte{0xB6})
|
d.bus.WriteRegister(uint8(d.Address), CMD_RESET, []byte{0xB6})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetMode can set the device to Sleep, Normal or Forced mode
|
||||||
|
//
|
||||||
|
// Calling this method is optional, Configure can be used to set the
|
||||||
|
// initial mode if no mode change is desired. This method is most
|
||||||
|
// useful to switch between Sleep and Normal modes.
|
||||||
|
func (d *Device) SetMode(mode Mode) {
|
||||||
|
d.Config.Mode = mode
|
||||||
|
|
||||||
|
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{
|
||||||
|
byte(d.Config.Temperature<<5) |
|
||||||
|
byte(d.Config.Pressure<<2) |
|
||||||
|
byte(d.Config.Mode)})
|
||||||
|
}
|
||||||
|
|
||||||
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
|
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
|
||||||
func (d *Device) ReadTemperature() (int32, error) {
|
func (d *Device) ReadTemperature() (int32, error) {
|
||||||
data, err := d.readData()
|
data, err := d.readData()
|
||||||
@@ -186,6 +250,16 @@ func readIntLE(msb byte, lsb byte) int16 {
|
|||||||
// readData does a burst read from 0xF7 to 0xF0 according to the datasheet
|
// readData does a burst read from 0xF7 to 0xF0 according to the datasheet
|
||||||
// resulting in an slice with 8 bytes 0-2 = pressure / 3-5 = temperature / 6-7 = humidity
|
// resulting in an slice with 8 bytes 0-2 = pressure / 3-5 = temperature / 6-7 = humidity
|
||||||
func (d *Device) readData() (data [8]byte, err error) {
|
func (d *Device) readData() (data [8]byte, err error) {
|
||||||
|
if d.Config.Mode == ModeForced {
|
||||||
|
// Write the CTRL_MEAS register to trigger a measurement
|
||||||
|
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{
|
||||||
|
byte(d.Config.Temperature<<5) |
|
||||||
|
byte(d.Config.Pressure<<2) |
|
||||||
|
byte(d.Config.Mode)})
|
||||||
|
|
||||||
|
time.Sleep(d.measurementDelay())
|
||||||
|
}
|
||||||
|
|
||||||
err = d.bus.ReadRegister(uint8(d.Address), REG_PRESSURE, data[:])
|
err = d.bus.ReadRegister(uint8(d.Address), REG_PRESSURE, data[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println(err)
|
println(err)
|
||||||
@@ -256,3 +330,39 @@ func (d *Device) calculateHumidity(data [8]byte, tFine int32) int32 {
|
|||||||
return int32(100 * h)
|
return int32(100 * h)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// measurementDelay returns how much time each measurement will take
|
||||||
|
// on the device.
|
||||||
|
//
|
||||||
|
// This is used in forced mode to wait until a measurement is complete.
|
||||||
|
func (d *Device) measurementDelay() time.Duration {
|
||||||
|
const MeasOffset = 1250
|
||||||
|
const MeasDur = 2300
|
||||||
|
const HumMeasOffset = 575
|
||||||
|
const MeasScalingFactor = 1000
|
||||||
|
|
||||||
|
// delay is based on over-sampling rate - this table converts from
|
||||||
|
// setting to number samples
|
||||||
|
sampleRateConv := []int{0, 1, 2, 4, 8, 16}
|
||||||
|
|
||||||
|
tempOsr := 16
|
||||||
|
if d.Config.Temperature <= Sampling16X {
|
||||||
|
tempOsr = sampleRateConv[d.Config.Temperature]
|
||||||
|
}
|
||||||
|
|
||||||
|
presOsr := 16
|
||||||
|
if d.Config.Temperature <= Sampling16X {
|
||||||
|
presOsr = sampleRateConv[d.Config.Pressure]
|
||||||
|
}
|
||||||
|
|
||||||
|
humOsr := 16
|
||||||
|
if d.Config.Temperature <= Sampling16X {
|
||||||
|
humOsr = sampleRateConv[d.Config.Humidity]
|
||||||
|
}
|
||||||
|
|
||||||
|
max_delay := ((MeasOffset + (MeasDur * tempOsr) +
|
||||||
|
((MeasDur * presOsr) + HumMeasOffset) +
|
||||||
|
((MeasDur * humOsr) + HumMeasOffset)) / MeasScalingFactor)
|
||||||
|
|
||||||
|
return time.Duration(max_delay) * time.Millisecond
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,6 +20,50 @@ const (
|
|||||||
CHIP_ID = 0x60
|
CHIP_ID = 0x60
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Increasing sampling rate increases precision but also the wait time for measurements. The datasheet has a table of
|
||||||
|
// suggested values for oversampling, output data rates, and iir filter coefficients by use case.
|
||||||
|
const (
|
||||||
|
SamplingOff Oversampling = iota
|
||||||
|
Sampling1X
|
||||||
|
Sampling2X
|
||||||
|
Sampling4X
|
||||||
|
Sampling8X
|
||||||
|
Sampling16X
|
||||||
|
)
|
||||||
|
|
||||||
|
// In normal mode (the default) the sensor takes masurements periodically. In forced
|
||||||
|
// mode, the sensor takes a measurement only when requested.
|
||||||
|
//
|
||||||
|
// For use-cases with infrequent sampling, forced mode is more power efficient.
|
||||||
|
const (
|
||||||
|
ModeNormal Mode = 0x03
|
||||||
|
ModeForced Mode = 0x01
|
||||||
|
ModeSleep Mode = 0x00
|
||||||
|
)
|
||||||
|
|
||||||
|
// IIR filter coefficients, higher values means steadier measurements but slower reaction times
|
||||||
|
const (
|
||||||
|
Coeff0 FilterCoefficient = iota
|
||||||
|
Coeff2
|
||||||
|
Coeff4
|
||||||
|
Coeff8
|
||||||
|
Coeff16
|
||||||
|
)
|
||||||
|
|
||||||
|
// Period of standby in normal mode which controls how often measurements are taken
|
||||||
|
//
|
||||||
|
// Note Period10ms and Period20ms are out of sequence, but are per the datasheet
|
||||||
|
const (
|
||||||
|
Period0_5ms Period = 0b000
|
||||||
|
Period62_5ms = 0b001
|
||||||
|
Period125ms = 0b010
|
||||||
|
Period250ms = 0b011
|
||||||
|
Period500ms = 0b100
|
||||||
|
Period1000ms = 0b101
|
||||||
|
Period10ms = 0b110
|
||||||
|
Period20ms = 0b111
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SEALEVEL_PRESSURE float32 = 1013.25 // in hPa
|
SEALEVEL_PRESSURE float32 = 1013.25 // in hPa
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user