Browse Source

Support for BMP085 and BMP180 sensors (#1082)

alexa
Xose Pérez 5 years ago
parent
commit
165a386127
7 changed files with 312 additions and 25 deletions
  1. +1
    -0
      code/espurna/config/arduino.h
  2. +1
    -0
      code/espurna/config/hardware.h
  3. +3
    -0
      code/espurna/config/progmem.h
  4. +45
    -25
      code/espurna/config/sensors.h
  5. +1
    -0
      code/espurna/config/types.h
  6. +8
    -0
      code/espurna/sensor.ino
  7. +253
    -0
      code/espurna/sensors/BMP180Sensor.h

+ 1
- 0
code/espurna/config/arduino.h View File

@ -156,6 +156,7 @@
//#define AM2320_SUPPORT 1
//#define ANALOG_SUPPORT 1
//#define BH1750_SUPPORT 1
//#define BMP180_SUPPORT 1
//#define BMX280_SUPPORT 1
//#define CSE7766_SUPPORT 1
//#define DALLAS_SUPPORT 1


+ 1
- 0
code/espurna/config/hardware.h View File

@ -3265,6 +3265,7 @@
// If we dont got it, you don't want it!
#define AM2320_SUPPORT 1
#define BH1750_SUPPORT 1
#define BMP180_SUPPORT 1
#define BMX280_SUPPORT 1
#define SHT3X_I2C_SUPPORT 1
#define EMON_ADC121_SUPPORT 1


+ 3
- 0
code/espurna/config/progmem.h View File

@ -145,6 +145,9 @@ PROGMEM const char espurna_sensors[] =
#if BH1750_SUPPORT
"BH1750 "
#endif
#if BMP180_SUPPORT
"BMP180 "
#endif
#if BMX280_SUPPORT
"BMX280 "
#endif


+ 45
- 25
code/espurna/config/sensors.h View File

@ -135,37 +135,19 @@
#define BH1750_MODE BH1750_CONTINUOUS_HIGH_RES_MODE
//------------------------------------------------------------------------------
// VL53L1X
// Enable support by passing VL53L1X_SUPPORT=1 build flag
// BMP085/BMP180
// Enable support by passing BMP180_SUPPORT=1 build flag
//------------------------------------------------------------------------------
#ifndef VL53L1X_SUPPORT
#define VL53L1X_SUPPORT 0
#endif
#ifndef VL53L1X_I2C_ADDRESS
#define VL53L1X_I2C_ADDRESS 0x00 // 0x00 means auto
#ifndef BMP180_SUPPORT
#define BMP180_SUPPORT 0
#endif
#ifndef VL53L1X_DISTANCE_MODE
#define VL53L1X_DISTANCE_MODE VL53L1X::Long // The distance mode of the sensor. Can be one of
#endif // `VL53L1X::Short`, `VL53L1X::Medium`, or `VL53L1X::Long.
// Shorter distance modes are less affected by ambient light
// but have lower maximum ranges, especially in the dark.
#ifndef VL53L1X_MEASUREMENT_TIMING_BUDGET
#define VL53L1X_MEASUREMENT_TIMING_BUDGET 140000 // The time, in microseconds, allocated for a single
// measurement. A longer timing budget allows for more
// accurate at the cost of power. The minimum budget is
// 20 ms (20000 us) in short distance mode and 33 ms for
// medium and long distance modes.
#ifndef BMP180_ADDRESS
#define BMP180_ADDRESS 0x00 // 0x00 means auto
#endif
#ifndef VL53L1X_INTER_MEASUREMENT_PERIOD
#define VL53L1X_INTER_MEASUREMENT_PERIOD 50 // Period, in milliseconds, determining how
#endif // often the sensor takes a measurement.
#define BMP180_MODE 3 // 0 for ultra-low power, 1 for standard, 2 for high resolution and 3 for ultrahigh resolution
//------------------------------------------------------------------------------
// BME280/BMP280
@ -817,6 +799,39 @@
#define VEML6075_DYNAMIC_MODE VEML6075::DYNAMIC_NORMAL // The dynamic mode can either be normal or high. In high
#endif // dynamic mode, the resolution increases by about two
// times.
//------------------------------------------------------------------------------
// VL53L1X
// Enable support by passing VL53L1X_SUPPORT=1 build flag
//------------------------------------------------------------------------------
#ifndef VL53L1X_SUPPORT
#define VL53L1X_SUPPORT 0
#endif
#ifndef VL53L1X_I2C_ADDRESS
#define VL53L1X_I2C_ADDRESS 0x00 // 0x00 means auto
#endif
#ifndef VL53L1X_DISTANCE_MODE
#define VL53L1X_DISTANCE_MODE VL53L1X::Long // The distance mode of the sensor. Can be one of
#endif // `VL53L1X::Short`, `VL53L1X::Medium`, or `VL53L1X::Long.
// Shorter distance modes are less affected by ambient light
// but have lower maximum ranges, especially in the dark.
#ifndef VL53L1X_MEASUREMENT_TIMING_BUDGET
#define VL53L1X_MEASUREMENT_TIMING_BUDGET 140000 // The time, in microseconds, allocated for a single
// measurement. A longer timing budget allows for more
// accurate at the cost of power. The minimum budget is
// 20 ms (20000 us) in short distance mode and 33 ms for
// medium and long distance modes.
#endif
#ifndef VL53L1X_INTER_MEASUREMENT_PERIOD
#define VL53L1X_INTER_MEASUREMENT_PERIOD 50 // Period, in milliseconds, determining how
#endif // often the sensor takes a measurement.
//------------------------------------------------------------------------------
// EZOPH pH meter
// Enable support by passing EZOPH_SUPPORT=1 build flag
//------------------------------------------------------------------------------
@ -846,6 +861,7 @@
AM2320_SUPPORT || \
ANALOG_SUPPORT || \
BH1750_SUPPORT || \
BMP180_SUPPORT || \
BMX280_SUPPORT || \
CSE7766_SUPPORT || \
DALLAS_SUPPORT || \
@ -929,6 +945,10 @@
#include "../sensors/BH1750Sensor.h"
#endif
#if BMP180_SUPPORT
#include "../sensors/BMP180Sensor.h"
#endif
#if BMX280_SUPPORT
#include "../sensors/BMX280Sensor.h"
#endif


+ 1
- 0
code/espurna/config/types.h View File

@ -283,6 +283,7 @@
#define SENSOR_VEML6075_ID 31
#define SENSOR_VL53L1X_ID 32
#define SENSOR_EZOPH_ID 33
#define SENSOR_BMP180_ID 34
//--------------------------------------------------------------------------------
// Magnitudes


+ 8
- 0
code/espurna/sensor.ino View File

@ -432,6 +432,14 @@ void _sensorLoad() {
}
#endif
#if BMP180_SUPPORT
{
BMP180Sensor * sensor = new BMP180Sensor();
sensor->setAddress(BMP180_ADDRESS);
_sensors.push_back(sensor);
}
#endif
#if BMX280_SUPPORT
{
BMX280Sensor * sensor = new BMX280Sensor();


+ 253
- 0
code/espurna/sensors/BMP180Sensor.h View File

@ -0,0 +1,253 @@
// -----------------------------------------------------------------------------
// BMP085/BMP180 Sensor over I2C
// Copyright (C) 2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && BMP180_SUPPORT
#pragma once
#undef I2C_SUPPORT
#define I2C_SUPPORT 1 // Explicitly request I2C support.
#include "Arduino.h"
#include "I2CSensor.h"
#define BMP180_CHIP_ID 0x55
#define BMP180_REGISTER_CHIPID 0xD0
#define BMP180_REGISTER_CAL_AC1 0xAA
#define BMP180_REGISTER_CAL_AC2 0xAC
#define BMP180_REGISTER_CAL_AC3 0xAE
#define BMP180_REGISTER_CAL_AC4 0xB0
#define BMP180_REGISTER_CAL_AC5 0xB2
#define BMP180_REGISTER_CAL_AC6 0xB4
#define BMP180_REGISTER_CAL_B1 0xB6
#define BMP180_REGISTER_CAL_B2 0xB8
#define BMP180_REGISTER_CAL_MB 0xBA
#define BMP180_REGISTER_CAL_MC 0xBC
#define BMP180_REGISTER_CAL_MD 0xBE
#define BMP180_REGISTER_VERSION 0xD1
#define BMP180_REGISTER_SOFTRESET 0xE0
#define BMP180_REGISTER_CONTROL 0xF4
#define BMP180_REGISTER_TEMPDATA 0xF6
#define BMP180_REGISTER_PRESSUREDATA 0xF6
#define BMP180_REGISTER_READTEMPCMD 0x2E
#define BMP180_REGISTER_READPRESSURECMD 0x34
class BMP180Sensor : public I2CSensor {
public:
static unsigned char addresses[1];
// ---------------------------------------------------------------------
// Public
// ---------------------------------------------------------------------
BMP180Sensor(): I2CSensor() {
_sensor_id = SENSOR_BMP180_ID;
_count = 2;
}
// ---------------------------------------------------------------------
// Sensor API
// ---------------------------------------------------------------------
// Initialization method, must be idempotent
void begin() {
if (!_dirty) return;
_init();
_dirty = !_ready;
}
// Descriptive name of the sensor
String description() {
char buffer[20];
snprintf(buffer, sizeof(buffer), "BMP180 @ I2C (0x%02X)", _address);
return String(buffer);
}
// Type for slot # index
unsigned char type(unsigned char index) {
if (index == 0) return MAGNITUDE_TEMPERATURE;
if (index == 1) return MAGNITUDE_PRESSURE;
return MAGNITUDE_NONE;
}
// Pre-read hook (usually to populate registers with up-to-date data)
virtual void pre() {
if (_run_init) {
i2cClearBus();
_init();
}
if (_chip == 0) {
_error = SENSOR_ERROR_UNKNOWN_ID;
return;
}
_error = SENSOR_ERROR_OK;
_error = _read();
if (_error != SENSOR_ERROR_OK) {
_run_init = true;
}
}
// Current value for slot # index
double value(unsigned char index) {
if (index == 0) return _temperature;
if (index == 1) return _pressure / 100;
return 0;
}
protected:
void _init() {
// Make sure sensor had enough time to turn on. BMP180 requires 2ms to start up
nice_delay(10);
// I2C auto-discover
_address = _begin_i2c(_address, sizeof(BMP180Sensor::addresses), BMP180Sensor::addresses);
if (_address == 0) return;
// Check sensor correctly initialized
_chip = i2c_read_uint8(_address, BMP180_REGISTER_CHIPID);
if (_chip != BMP180_CHIP_ID) {
_chip = 0;
i2cReleaseLock(_address);
_previous_address = 0;
_error = SENSOR_ERROR_UNKNOWN_ID;
// Setting _address to 0 forces auto-discover
// This might be necessary at this stage if there is a
// different sensor in the hardcoded address
_address = 0;
return;
}
_readCoefficients();
_run_init = false;
_ready = true;
}
void _readCoefficients() {
_bmp180_calib.ac1 = i2c_read_int16(_address, BMP180_REGISTER_CAL_AC1);
_bmp180_calib.ac2 = i2c_read_int16(_address, BMP180_REGISTER_CAL_AC2);
_bmp180_calib.ac3 = i2c_read_int16(_address, BMP180_REGISTER_CAL_AC3);
_bmp180_calib.ac4 = i2c_read_uint16(_address, BMP180_REGISTER_CAL_AC4);
_bmp180_calib.ac5 = i2c_read_uint16(_address, BMP180_REGISTER_CAL_AC5);
_bmp180_calib.ac6 = i2c_read_uint16(_address, BMP180_REGISTER_CAL_AC6);
_bmp180_calib.b1 = i2c_read_int16(_address, BMP180_REGISTER_CAL_B1);
_bmp180_calib.b2 = i2c_read_int16(_address, BMP180_REGISTER_CAL_B2);
_bmp180_calib.mb = i2c_read_int16(_address, BMP180_REGISTER_CAL_MB);
_bmp180_calib.mc = i2c_read_int16(_address, BMP180_REGISTER_CAL_MC);
_bmp180_calib.md = i2c_read_int16(_address, BMP180_REGISTER_CAL_MD);
}
// Compute B5 coefficient used in temperature & pressure calcs.
// Based on Adafruit_BMP085_Unified library
long _computeB5(unsigned long t) {
long X1 = (t - (long)_bmp180_calib.ac6) * ((long)_bmp180_calib.ac5) >> 15;
long X2 = ((long)_bmp180_calib.mc << 11) / (X1+(long)_bmp180_calib.md);
return X1 + X2;
}
unsigned char _read() {
// Read raw temperature
i2c_write_uint8(_address, BMP180_REGISTER_CONTROL, BMP180_REGISTER_READTEMPCMD);
nice_delay(5);
unsigned long t = i2c_read_uint16(_address, BMP180_REGISTER_TEMPDATA);
// Compute B5 coeficient
long b5 = _computeB5(t);
// Final temperature
_temperature = ((double) ((b5 + 8) >> 4)) / 10.0;
// Read raw pressure
i2c_write_uint8(_address, BMP180_REGISTER_CONTROL, BMP180_REGISTER_READPRESSURECMD + (_mode << 6));
nice_delay(26);
unsigned long p1 = i2c_read_uint16(_address, BMP180_REGISTER_PRESSUREDATA);
unsigned long p2 = i2c_read_uint8(_address, BMP180_REGISTER_PRESSUREDATA+2);
long p = ((p1 << 8) + p2) >> (8 - _mode);
// Pressure compensation
long b6 = b5 - 4000;
long x1 = (_bmp180_calib.b2 * ((b6 * b6) >> 12)) >> 11;
long x2 = (_bmp180_calib.ac2 * b6) >> 11;
long x3 = x1 + x2;
long b3 = (((((int32_t) _bmp180_calib.ac1) * 4 + x3) << _mode) + 2) >> 2;
x1 = (_bmp180_calib.ac3 * b6) >> 13;
x2 = (_bmp180_calib.b1 * ((b6 * b6) >> 12)) >> 16;
x3 = ((x1 + x2) + 2) >> 2;
unsigned long b4 = (_bmp180_calib.ac4 * (uint32_t) (x3 + 32768)) >> 15;
unsigned long b7 = ((uint32_t) (p - b3) * (50000 >> _mode));
if (b7 < 0x80000000) {
p = (b7 << 1) / b4;
} else {
p = (b7 / b4) << 1;
}
x1 = (p >> 8) * (p >> 8);
x1 = (x1 * 3038) >> 16;
x2 = (-7357 * p) >> 16;
_pressure = p + ((x1 + x2 + 3791) >> 4);
return SENSOR_ERROR_OK;
}
// ---------------------------------------------------------------------
unsigned char _chip;
bool _run_init = false;
double _temperature = 0;
double _pressure = 0;
unsigned int _mode = BMP180_MODE;
typedef struct {
int16_t ac1;
int16_t ac2;
int16_t ac3;
uint16_t ac4;
uint16_t ac5;
uint16_t ac6;
int16_t b1;
int16_t b2;
int16_t mb;
int16_t mc;
int16_t md;
} bmp180_calib_t;
bmp180_calib_t _bmp180_calib;
};
// Static inizializations
unsigned char BMP180Sensor::addresses[1] = {0x77};
#endif // SENSOR_SUPPORT && BMP180_SUPPORT

Loading…
Cancel
Save