Подключение датчика атмосферного давления BMP280 к Orange Pi, Banana Pi, Raspberry Pi

Подключение BMP280 к Orange Pi, Banana Pi, Raspberry Pi - BMP280Подключить датчик атмосферного давления BMP280 к Orange Pi PC можно как по I2C, так и по SPI, благо их несколько у Orange Pi PC. Также для работы с GPIO необходимо установить WiringOP, если вы работаете с Orange Pi, а если у вас Banana Pi — BPI-WiringPi.

Барометр на BMP280

BMP280 – это датчик атмосферного давления от BOSCH Sensortec и является улучшенной версией датчика BMP180. Отличается от него меньшими размерами (2 x 2.5 x 0.95 мм), пониженным энергопотреблением, высокой точностью работы и наличием точной заводской калибровки и двумя последовательными интерфейсами: I2C и SPI.
Логика работы датчика BMP280 осталась такой же, но претерпела некоторые долгожданные улучшения.

В таблице приведены улучшения, которые претерпел датчик BMP280:

Параметр BMP180 BMP280
Размеры 3.6 x 3.8 mm 2.0 x 2.5 mm
Мин VDD 1.80 V 1.71 V
Мин VDDIO 1.62 V 1.20 V
Потребляемый ток @3 Pa RMS шум 12 μA 2.7 μA
RMS Шум 3 Pa 1.3 Pa
Разрешение давления 1 Pa 0.16 Pa
Разрешение температуры 0.1°C 0.01°C
Интерфейсы I²C I²C & SPI (3 и 4 линии связи,
mode ‘00’ and ‘11’)
Режимы измерения Только P или T, принудительное P и T, принудительное или периодическое
Частота измерений до 120 Гц до 157 Гц
Параметры фильтра Нет Пять параметров фильтрации

Режимами работы

От предыдущих моделей (BMP085 и BMP180) датчик отличается тремя режимами работы:

  1. SLEEP — режим пониженного энергопотребления
  2. FORCED – режим, аналогичный, режиму работы датчиков BMP085 и BMP180. По команде контроллера датчик выходит из режима сна, производит измерения, выдает результаты измерения контроллеру и переходит в режим пониженного энергопотребления
  3. NORMAL — уникальный для этого датчика режим. Датчик самостоятельно просыпается, производит измерения давления и температуры и засыпает. Все временные параметры этого режима программируются независимо. Считывать данные в этом режиме можно в любое время.

Фильтрация результатов измерений

В датчике предусмотрена фильтрация результатов измерений с настройкой таких параметров фильтрации:

  1. OVERSAMPLING для температуры (16, 17, 18, 19, 20 бит)
  2. OVERSAMPLING для давления (16, 17, 18, 19, 20 бит)
  3. TSB – время между между измерениями (0.5, 62.5, 125, 250, 500, 1000, 2000, 4000 мс)
  4. FILTER_COEFFICIENT – коэффициент фильтрации

Характеристики:

  • Напряжение питания: от 1.71 В до 3.6 В
  • Макс скорость I2C интерфейса: 3.4 МГц
  • Потребляемый ток: 2.7 мкA при частоте отсчетов в 1 Гц
  • Интерфейс: I2C, SPI (4 Провода), SPI (3 Провода)
  • Калибровка: заводская
  • Уровень шума: до 0.2 Па (1.7 см) и 0.01 температуры
  • Диапазон измеряемого давления: от 300 hPa до 1100 hPa (9000 м до -500 м)
  • Размер: 2.5 мм х 2.0 мм х 0.95 мм

BMP280 библиотека

BMP280RawData.h

#include <stdint.h>

class BMP280RawData {
private:
  uint8_t pmsb;
  uint8_t plsb;
  uint8_t pxsb;

  uint8_t tmsb;
  uint8_t tlsb;
  uint8_t txsb;

  uint32_t temperature;
  uint32_t pressure;
public:

  BMP280RawData(
    uint8_t pmsb, uint8_t plsb, uint8_t pxsb,
    uint8_t tmsb, uint8_t tlsb, uint8_t txsb,
    uint32_t temperature, uint32_t pressure) {
    this->pmsb = pmsb;
    this->plsb = plsb;
    this->pxsb = pxsb;
    this->tmsb = tmsb;
    this->tlsb = tlsb;
    this->txsb = txsb;
    this->temperature = temperature;
    this->pressure = pressure;
  }

  BMP280RawData() {
    this->pmsb = 0;
    this->plsb = 0;
    this->pxsb = 0;
    this->tmsb = 0;
    this->tlsb = 0;
    this->txsb = 0;
    this->temperature = 0;
    this->pressure = 0;
  }

  virtual ~BMP280RawData() {
  }

  void setPlsb(uint8_t plsb) {
    this->plsb = plsb;
  }

  void setPmsb(uint8_t pmsb) {
    this->pmsb = pmsb;
  }

  void setPressure(uint32_t pressure) {
    this->pressure = pressure;
  }

  void setPxsb(uint8_t pxsb) {
    this->pxsb = pxsb;
  }

  void setTemperature(uint32_t temperature) {
    this->temperature = temperature;
  }

  void setTlsb(uint8_t tlsb) {
    this->tlsb = tlsb;
  }

  void setTmsb(uint8_t tmsb) {
    this->tmsb = tmsb;
  }

  void setTxsb(uint8_t txsb) {
    this->txsb = txsb;
  }

  uint8_t getPlsb() {
    return plsb;
  }

  uint8_t getPmsb() {
    return pmsb;
  }

  uint32_t getPressure() {
    return pressure;
  }

  uint8_t getPxsb() {
    return pxsb;
  }

  uint32_t getTemperature() {
    return temperature;
  }

  uint8_t getTlsb() {
    return tlsb;
  }

  uint8_t getTmsb() {
    return tmsb;
  }

  uint8_t getTxsb() {
    return txsb;
  }
};

BMP280CalibrationData.h

#include <stdint.h>

class BMP280CalibrationData {
private:
  uint16_t T1;
  int16_t T2;
  int16_t T3;

  uint16_t P1;
  int16_t P2;
  int16_t P3;
  int16_t P4;
  int16_t P5;
  int16_t P6;
  int16_t P7;
  int16_t P8;
  int16_t P9;

public:

  BMP280CalibrationData() {
    T1 = 0;
    T2 = 0;
    T3 = 0;
    P1 = 0;
    P2 = 0;
    P3 = 0;
    P4 = 0;
    P5 = 0;
    P6 = 0;
    P7 = 0;
    P8 = 0;
    P9 = 0;
  }

  BMP280CalibrationData(
    uint16_t T1, int16_t T2, int16_t T3,
    uint16_t P1, int16_t P2, int16_t P3,
    int16_t P4, int16_t P5, int16_t P6,
    int16_t P7, int16_t P8, int16_t P9) {
    this->P1 = P1;
    this->P2 = P2;
    this->P3 = P3;
    this->P4 = P4;
    this->P5 = P5;
    this->P6 = P6;
    this->P7 = P7;
    this->P8 = P8;
    this->P9 = P9;
    this->T1 = T1;
    this->T2 = T2;
    this->T3 = T3;
  }

  virtual ~BMP280CalibrationData() {
  }

  void setP1(uint16_t P1) {
    this->P1 = P1;
  }

  void setP2(int16_t P2) {
    this->P2 = P2;
  }

  void setP3(int16_t P3) {
    this->P3 = P3;
  }

  void setP4(int16_t P4) {
    this->P4 = P4;
  }

  void setP5(int16_t P5) {
    this->P5 = P5;
  }

  void setP6(int16_t P6) {
    this->P6 = P6;
  }

  void setP7(int16_t P7) {
    this->P7 = P7;
  }

  void setP8(int16_t P8) {
    this->P8 = P8;
  }

  void setP9(int16_t P9) {
    this->P9 = P9;
  }

  void setT1(uint16_t T1) {
    this->T1 = T1;
  }

  void setT2(int16_t T2) {
    this->T2 = T2;
  }

  void setT3(int16_t T3) {
    this->T3 = T3;
  }

  uint16_t getP1() {
    return P1;
  }

  int16_t getP2() {
    return P2;
  }

  int16_t getP3() {
    return P3;
  }

  int16_t getP4() {
    return P4;
  }

  int16_t getP5() {
    return P5;
  }

  int16_t getP6() {
    return P6;
  }

  int16_t getP7() {
    return P7;
  }

  int16_t getP8() {
    return P8;
  }

  int16_t getP9() {
    return P9;
  }

  uint16_t getT1() {
    return T1;
  }

  int16_t getT2() {
    return T2;
  }

  int16_t getT3() {
    return T3;
  }
};

BMP280Data.h

class BMP280Data {
private:
  double pressure; // hPa
  double temperature; // m
  double altitude; // °C
public:

  BMP280Data() {
    pressure = 0;
    temperature = 0;
    altitude = 0;
  }

  BMP280Data(double pressure, double temperature, double altitude) {
    this->pressure = pressure;
    this->temperature = temperature;
    this->altitude = altitude;
  }

  virtual ~BMP280Data() {
  }

  void setAltitude(double altitude) {
    this->altitude = altitude;
  }

  void setPressure(double pressure) {
    this->pressure = pressure;
  }

  void setTemperature(double temperature) {
    this->temperature = temperature;
  }

  double getAltitude() {
    return altitude;
  }

  double getPressure() {
    return pressure;
  }

  double getTemperature() {
    return temperature;
  }
};

bmp280.h

#include <stdint.h>
#include "BMP280CalibrationData.h"
#include "BMP280RawData.h"
#include "BMP280Data.h"

#define MEAN_SEA_LEVEL_PRESSURE       1013

/**\name	CHIP ID DEFINITION       */
/***********************************************/
#define BMP280_CHIP_ID1  (0x56)
#define BMP280_CHIP_ID2  (0x57)
#define BMP280_CHIP_ID3  (0x58)
/************************************************/
/**\name	I2C ADDRESS DEFINITION       */
/***********************************************/
#define BMP280_I2C_ADDRESS1                  (0x76)
#define BMP280_I2C_ADDRESS2                  (0x77)
/************************************************/
/**\name	POWER MODE DEFINITION       */
/***********************************************/
/* Sensor Specific constants */
#define BMP280_SLEEP_MODE                    (0x00)
#define BMP280_FORCED_MODE                   (0x01)
#define BMP280_NORMAL_MODE                   (0x03)
#define BMP280_SOFT_RESET_CODE               (0xB6)
/************************************************/
/**\name	STANDBY TIME DEFINITION       */
/***********************************************/
#define BMP280_STANDBY_TIME_1_MS              (0x00)
#define BMP280_STANDBY_TIME_63_MS             (0x01)
#define BMP280_STANDBY_TIME_125_MS            (0x02)
#define BMP280_STANDBY_TIME_250_MS            (0x03)
#define BMP280_STANDBY_TIME_500_MS            (0x04)
#define BMP280_STANDBY_TIME_1000_MS           (0x05)
#define BMP280_STANDBY_TIME_2000_MS           (0x06)
#define BMP280_STANDBY_TIME_4000_MS           (0x07)
/************************************************/
/**\name	OVERSAMPLING DEFINITION       */
/***********************************************/
#define BMP280_OVERSAMP_SKIPPED          (0x00)
#define BMP280_OVERSAMP_1X               (0x01)
#define BMP280_OVERSAMP_2X               (0x02)
#define BMP280_OVERSAMP_4X               (0x03)
#define BMP280_OVERSAMP_8X               (0x04)
#define BMP280_OVERSAMP_16X              (0x05)
/************************************************/
/**\name	WORKING MODE DEFINITION       */
/***********************************************/
#define BMP280_ULTRA_LOW_POWER_MODE          (0x00)
#define BMP280_LOW_POWER_MODE                (0x01)
#define BMP280_STANDARD_RESOLUTION_MODE      (0x02)
#define BMP280_HIGH_RESOLUTION_MODE          (0x03)
#define BMP280_ULTRA_HIGH_RESOLUTION_MODE    (0x04)

#define BMP280_ULTRALOWPOWER_OVERSAMP_PRESSURE          BMP280_OVERSAMP_1X
#define BMP280_ULTRALOWPOWER_OVERSAMP_TEMPERATURE       BMP280_OVERSAMP_1X

#define BMP280_LOWPOWER_OVERSAMP_PRESSURE          BMP280_OVERSAMP_2X
#define BMP280_LOWPOWER_OVERSAMP_TEMPERATURE          BMP280_OVERSAMP_1X

#define BMP280_STANDARDRESOLUTION_OVERSAMP_PRESSURE     BMP280_OVERSAMP_4X
#define BMP280_STANDARDRESOLUTION_OVERSAMP_TEMPERATURE  BMP280_OVERSAMP_1X

#define BMP280_HIGHRESOLUTION_OVERSAMP_PRESSURE         BMP280_OVERSAMP_8X
#define BMP280_HIGHRESOLUTION_OVERSAMP_TEMPERATURE      BMP280_OVERSAMP_1X

#define BMP280_ULTRAHIGHRESOLUTION_OVERSAMP_PRESSURE       BMP280_OVERSAMP_16X
#define BMP280_ULTRAHIGHRESOLUTION_OVERSAMP_TEMPERATURE    BMP280_OVERSAMP_2X
/************************************************/
/**\name	FILTER DEFINITION       */
/***********************************************/
#define BMP280_FILTER_COEFF_OFF               (0x00)
#define BMP280_FILTER_COEFF_2                 (0x01)
#define BMP280_FILTER_COEFF_4                 (0x02)
#define BMP280_FILTER_COEFF_8                 (0x03)
#define BMP280_FILTER_COEFF_16                (0x04)
/************************************************/

/*
 * REGISTERS
 */
enum {
  BMP280_REGISTER_DIG_T1 = 0x88,
  BMP280_REGISTER_DIG_T2 = 0x8A,
  BMP280_REGISTER_DIG_T3 = 0x8C,

  BMP280_REGISTER_DIG_P1 = 0x8E,
  BMP280_REGISTER_DIG_P2 = 0x90,
  BMP280_REGISTER_DIG_P3 = 0x92,
  BMP280_REGISTER_DIG_P4 = 0x94,
  BMP280_REGISTER_DIG_P5 = 0x96,
  BMP280_REGISTER_DIG_P6 = 0x98,
  BMP280_REGISTER_DIG_P7 = 0x9A,
  BMP280_REGISTER_DIG_P8 = 0x9C,
  BMP280_REGISTER_DIG_P9 = 0x9E,

  BMP280_REGISTER_CHIPID = 0xD0,
  BMP280_REGISTER_VERSION = 0xD1,
  BMP280_REGISTER_SOFTRESET = 0xE0,

  BMP280_REGISTER_CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0

  BMP280_REGISTER_STATUS = 0xF3,
  BMP280_REGISTER_CONTROL = 0xF4,
  BMP280_REGISTER_CONFIG = 0xF5,
  BMP280_REGISTER_PRESSUREDATA_MSB = 0xF7,
  BMP280_REGISTER_PRESSUREDATA_LSB = 0xF8,
  BMP280_REGISTER_PRESSUREDATA_XLSB = 0xF9,
  BMP280_REGISTER_TEMPDATA_MSB = 0xFA,
  BMP280_REGISTER_TEMPDATA_LSB = 0xFB,
  BMP280_REGISTER_TEMPDATA_XLSB = 0xFC
};

class BMP280 {
private:
  char * device;
  int devId;
  int fd;
  uint8_t chipId;
  BMP280CalibrationData * bmp280CalibrationData;
  BMP280RawData * bmp280RawData;

  void write8(uint8_t, uint8_t);
  uint8_t read8(uint8_t);
  uint16_t read16(uint8_t);
  int16_t readS16(uint8_t);
  uint16_t readU16(uint8_t);

  int32_t getTemperatureC(int32_t adc_T);
  double getAltitude(double pressure);
  double compensateT(int32_t t_fine);
  double compensateP(int32_t adc_P, int32_t t_fine);
  BMP280CalibrationData * getCalibrationData();
  BMP280RawData * getRawData();

public:
  BMP280(int);
  BMP280(char *, int);
  virtual ~BMP280();

  BMP280CalibrationData * getBmp280CalibrationData();
  BMP280Data * getBMP280Data();

  int init();
  void reset();
  void spi3wEnable();
  void spi3wDisable();
  void setPowerMode(uint8_t);
  void setTemperatureOversampling(uint8_t);
  void setPressureOversampling(uint8_t);
  void setStandbyTime(uint8_t);
  void setIrrFilter(uint8_t);
  
  uint8_t getPowerMode();
  uint8_t getPressureOversampling();
  uint8_t getTemperatureOversampling();
  uint8_t getIrrFilter();
  uint8_t getStandbyTime();
  uint8_t getSpi3w();
  uint8_t getMeasuringStatus();
  uint8_t getImUpdateStatus();
  uint8_t getConfig();
  uint8_t getStatus();
  uint8_t getControl();
  uint8_t getChipId();
  uint8_t getChipVersion();
  
  void setReset(uint8_t);
  void setConfig(uint8_t);
  void setStatus(uint8_t);
  void setControl(uint8_t);
  void setDevice(char *);
};

bmp280.cpp

#include <string.h>
#include <stdint.h>
#include <stdexcept>
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <wiringPiI2C.h>
#include <wiringPi.h>
#include "bmp280.h"

BMP280::BMP280(char * device, int devId) : fd(0), chipId(0), bmp280CalibrationData(0), bmp280RawData(0) {
    setDevice(device);
    this->devId = devId;
}

BMP280::BMP280(int devId) : device(0), fd(0), chipId(0), bmp280CalibrationData(0), bmp280RawData(0) {
    this->devId = devId;
}

BMP280::~BMP280() {
    delete bmp280CalibrationData;
    delete bmp280RawData;
    delete[] device;
}

int BMP280::init() {
    int fd = -1;
    if (device) {
        fd = wiringPiI2CSetupInterface(device, devId);
    } else {
        int rev = piBoardRev();

        if (rev == 1) {
            setDevice("/dev/i2c-0");
        } else if (rev == 2) {
            setDevice("/dev/i2c-1");
        } else if (rev == 3) {
            setDevice("/dev/i2c-2");
        } else {
            setDevice("/dev/i2c-3");
        }

        fd = wiringPiI2CSetupInterface(device, devId);
    }
    if (fd < 0) {
        char buffer[256];
        sprintf(buffer, "Device not found: I2C device: %s, device ID: %d", device, devId);
        throw std::logic_error(buffer);
    }
    this->fd = fd;

    uint8_t chipId = getChipId();
    switch (chipId) {
        case BMP280_CHIP_ID1:
        case BMP280_CHIP_ID2:
        case BMP280_CHIP_ID3:
            this->chipId = chipId;
            break;
        default:
        {
            char buffer[256];
            sprintf(buffer, "Device Chip ID error: chip ID = %d", chipId);
            throw std::logic_error(buffer);
        }
    }
    if (bmp280CalibrationData) {
        delete bmp280CalibrationData;
    }
    bmp280CalibrationData = getCalibrationData();
    return fd;
}

BMP280CalibrationData * BMP280::getCalibrationData() {
    uint16_t T1, P1;
    int16_t T2, T3, P2, P3, P4, P5, P6, P7, P8, P9;

    T1 = readU16(BMP280_REGISTER_DIG_T1);
    T2 = readS16(BMP280_REGISTER_DIG_T2);
    T3 = readS16(BMP280_REGISTER_DIG_T3);
    P1 = readU16(BMP280_REGISTER_DIG_P1);
    P2 = readS16(BMP280_REGISTER_DIG_P2);
    P3 = readS16(BMP280_REGISTER_DIG_P3);
    P4 = readS16(BMP280_REGISTER_DIG_P4);
    P5 = readS16(BMP280_REGISTER_DIG_P5);
    P6 = readS16(BMP280_REGISTER_DIG_P6);
    P7 = readS16(BMP280_REGISTER_DIG_P7);
    P8 = readS16(BMP280_REGISTER_DIG_P8);
    P9 = readS16(BMP280_REGISTER_DIG_P9);

    return new BMP280CalibrationData(T1, T2, T3, P1, P2, P3, P4, P5, P6, P7, P8, P9);
}

BMP280CalibrationData * BMP280::getBmp280CalibrationData() {
    return bmp280CalibrationData;
}

BMP280RawData * BMP280::getRawData() {
    uint8_t pmsb, plsb, pxsb;
    uint8_t tmsb, tlsb, txsb;
    uint32_t temperature, pressure;

    plsb = read8(BMP280_REGISTER_PRESSUREDATA_LSB);
    pmsb = read8(BMP280_REGISTER_PRESSUREDATA_MSB);
    pxsb = read8(BMP280_REGISTER_PRESSUREDATA_XLSB);

    tmsb = read8(BMP280_REGISTER_TEMPDATA_MSB);
    tlsb = read8(BMP280_REGISTER_TEMPDATA_LSB);
    txsb = read8(BMP280_REGISTER_TEMPDATA_XLSB);

    temperature = 0;
    temperature = (temperature | tmsb) << 8;
    temperature = (temperature | tlsb) << 8;
    temperature = (temperature | txsb) >> 4;

    pressure = 0;
    pressure = (pressure | pmsb) << 8;
    pressure = (pressure | plsb) << 8;
    pressure = (pressure | pxsb) >> 4;

    return new BMP280RawData(pmsb, plsb, pxsb, tmsb, tlsb, txsb, temperature, pressure);
}

void BMP280::reset() {
    setReset(BMP280_SOFT_RESET_CODE);
}

void BMP280::spi3wEnable() {
    uint8_t config = getConfig();
    setConfig(config | 0b00000001);
}

void BMP280::spi3wDisable() {
    uint8_t config = getConfig();
    setConfig(config & 0b11111110);
}

void BMP280::setPowerMode(uint8_t mode) {
    switch (mode) {
        case BMP280_FORCED_MODE:
        case BMP280_NORMAL_MODE:
        case BMP280_SLEEP_MODE:
        {
            uint8_t curentMode = getControl() & 0b11111100;
            setControl(curentMode | mode);
            break;
        }
        default:break;
    }
}

void BMP280::setTemperatureOversampling(uint8_t oversampling) {
    switch (oversampling) {
        case BMP280_OVERSAMP_SKIPPED:
        case BMP280_OVERSAMP_1X:
        case BMP280_OVERSAMP_2X:
        case BMP280_OVERSAMP_4X:
        case BMP280_OVERSAMP_8X:
        case BMP280_OVERSAMP_16X:
        {
            uint8_t curentOversampling = getControl() & 0b00011111;
            setControl(curentOversampling | (oversampling << 5));
            break;
        }
        default:break;
    }
}

void BMP280::setPressureOversampling(uint8_t oversampling) {
    switch (oversampling) {
        case BMP280_OVERSAMP_SKIPPED:
        case BMP280_OVERSAMP_1X:
        case BMP280_OVERSAMP_2X:
        case BMP280_OVERSAMP_4X:
        case BMP280_OVERSAMP_8X:
        case BMP280_OVERSAMP_16X:
        {
            uint8_t curentOversampling = getControl() & 0b11100011;
            setControl(curentOversampling | (oversampling << 2));
            break;
        }
        default:break;
    }
}

void BMP280::setStandbyTime(uint8_t tStandby) {
    switch (tStandby) {
        case BMP280_STANDBY_TIME_1_MS:
        case BMP280_STANDBY_TIME_63_MS:
        case BMP280_STANDBY_TIME_125_MS:
        case BMP280_STANDBY_TIME_250_MS:
        case BMP280_STANDBY_TIME_500_MS:
        case BMP280_STANDBY_TIME_1000_MS:
        case BMP280_STANDBY_TIME_2000_MS:
        case BMP280_STANDBY_TIME_4000_MS:
        {
            uint8_t config = getConfig() & 0b00011111;
            setConfig(config | (tStandby << 5));
            break;
        }
        default:break;
    }
}

void BMP280::setIrrFilter(uint8_t irrFilter) {
    switch (irrFilter) {
        case BMP280_FILTER_COEFF_OFF:
        case BMP280_FILTER_COEFF_2:
        case BMP280_FILTER_COEFF_4:
        case BMP280_FILTER_COEFF_8:
        case BMP280_FILTER_COEFF_16:
        {
            uint8_t config = getConfig() & 0b11100011;
            setConfig(config | (irrFilter << 2));
            break;
        }
        default:break;
    }
}

uint8_t BMP280::getPowerMode() {
    return getControl() & 0b00000011;
}

uint8_t BMP280::getPressureOversampling() {
    return (getControl() & 0b00011100) >> 2;
}

uint8_t BMP280::getTemperatureOversampling() {
    return (getControl() & 0b11100000) >> 5;
}

uint8_t BMP280::getIrrFilter() {
    return (getConfig() & 0b00011100) >> 2;
}

uint8_t BMP280::getStandbyTime() {
    return (getConfig() & 0b11100000) >> 5;
}

uint8_t BMP280::getSpi3w() {
    return (getConfig() & 0b00000001);
}

uint8_t BMP280::getMeasuringStatus() {
    return (getStatus() >> 3) & 0b00000001;
}

uint8_t BMP280::getImUpdateStatus() {
    return getStatus() & 0b00000001;
}

uint8_t BMP280::getConfig() {
    return read8(BMP280_REGISTER_CONFIG);
}

uint8_t BMP280::getStatus() {
    return read8(BMP280_REGISTER_STATUS);
}

uint8_t BMP280::getControl() {
    return read8(BMP280_REGISTER_CONTROL);
}

uint8_t BMP280::getChipId() {
    return read8(BMP280_REGISTER_CHIPID);
}

uint8_t BMP280::getChipVersion() {
    return read8(BMP280_REGISTER_VERSION);
}

void BMP280::setReset(uint8_t value) {
    write8(BMP280_REGISTER_SOFTRESET, value);
}

void BMP280::setConfig(uint8_t value) {
    return write8(BMP280_REGISTER_CONFIG, value);
}

void BMP280::setStatus(uint8_t value) {
    return write8(BMP280_REGISTER_STATUS, value);
}

void BMP280::setControl(uint8_t value) {
    return write8(BMP280_REGISTER_CONTROL, value);
}

double BMP280::getAltitude(double pressure) {
    return 44330.0 * (1.0 - pow(pressure / MEAN_SEA_LEVEL_PRESSURE, 0.190294957));
}

int32_t BMP280::getTemperatureC(int32_t adc_T) {
    int32_t var1 = ((((adc_T >> 3) - ((int32_t) bmp280CalibrationData->getT1() << 1))) *
            ((int32_t) bmp280CalibrationData->getT2())) >> 11;

    int32_t var2 = (((((adc_T >> 4) - ((int32_t) bmp280CalibrationData->getT1())) *
            ((adc_T >> 4) - ((int32_t) bmp280CalibrationData->getT1()))) >> 12) *
            ((int32_t) bmp280CalibrationData->getT3())) >> 14;

    return var1 + var2;
}

double BMP280::compensateT(int32_t t_fine) {
    double T = (t_fine * 5 + 128) >> 8;
    return T / 100;
}

double BMP280::compensateP(int32_t adc_P, int32_t t_fine) {
    int64_t var1, var2, p;

    var1 = ((int64_t) t_fine) - 128000;
    var2 = var1 * var1 * (int64_t) bmp280CalibrationData->getP6();
    var2 = var2 + ((var1 * (int64_t) bmp280CalibrationData->getP5()) << 17);
    var2 = var2 + (((int64_t) bmp280CalibrationData->getP4()) << 35);
    var1 = ((var1 * var1 * (int64_t) bmp280CalibrationData->getP3()) >> 8) +
            ((var1 * (int64_t) bmp280CalibrationData->getP2()) << 12);
    var1 = (((((int64_t) 1) << 47) + var1))*((int64_t) bmp280CalibrationData->getP1()) >> 33;

    if (var1 == 0) {
        return 0; // avoid exception caused by division by zero
    }
    p = 1048576 - adc_P;
    p = (((p << 31) - var2)*3125) / var1;
    var1 = (((int64_t) bmp280CalibrationData->getP9()) * (p >> 13) * (p >> 13)) >> 25;
    var2 = (((int64_t) bmp280CalibrationData->getP8()) * p) >> 19;

    p = ((p + var1 + var2) >> 8) + (((int64_t) bmp280CalibrationData->getP7()) << 4);
    return (double) p / 256;
}

BMP280Data * BMP280::getBMP280Data() {
    int32_t t_fine;
    double t, p, a;
    while (getMeasuringStatus()) {
    }
    if (bmp280RawData) {
        delete bmp280RawData;
    }
    bmp280RawData = getRawData();
    t_fine = getTemperatureC(bmp280RawData->getTemperature());
    t = compensateT(t_fine); // C
    p = compensateP(bmp280RawData->getPressure(), t_fine) / 100; // hPa
    a = getAltitude(p); // meters

    return new BMP280Data(p, t, a);
}

void BMP280::setDevice(char * device) {
    if (device) {
        this->device = new char[strlen(device)];
        strcpy(this->device, device);
    }
}

void BMP280::write8(uint8_t reg, uint8_t value) {
    wiringPiI2CWriteReg8(fd, reg, value);
}

uint8_t BMP280::read8(uint8_t reg) {
    return wiringPiI2CReadReg8(fd, reg);
}

uint16_t BMP280::read16(uint8_t reg) {
    return wiringPiI2CReadReg16(fd, reg);
}

int16_t BMP280::readS16(uint8_t reg) {
    return (int16_t) read16(reg);
}

uint16_t BMP280::readU16(uint8_t reg) {
    return (uint16_t) read16(reg);
}

Схема подключения BMP280 к Orange Pi

Подключение BMP280 к Orange Pi, Banana Pi, Raspberry Pi - GPIO40Я с этими датчиками работаю только по I2C. Подключяется BMP280 к Orange Pi очень просто: на Vcc даём 3.3 В, GND, SCL и SDA.

Рабочее напряжение датчика от 1.71 В до 3.6 В. Не стоит питать от 5 В, так как вероятность того, что он выйдет из строя, очень высока.

Ниже приведён пример программы для проверки вышеуказанной библиотеки.

Данная программа создаёт новый объект для работы с датчиком:

BMP280 * bmp280 = new BMP280(device, devId);

соединяется с датчиком:

int fd = bmp280->init();

и сбрасывает все его настройки:

bmp280->reset();

после чего задаёт новые настройки (режим работы, фильтры и др.):

bmp280->setPowerMode(BMP280_NORMAL_MODE);
bmp280->setTemperatureOversampling(BMP280_ULTRAHIGHRESOLUTION_OVERSAMP_TEMPERATURE);
bmp280->setPressureOversampling(BMP280_ULTRAHIGHRESOLUTION_OVERSAMP_PRESSURE);
bmp280->setIrrFilter(BMP280_FILTER_COEFF_16);
bmp280->setStandbyTime(BMP280_STANDBY_TIME_250_MS);

и раз в секунду читает и выводит на экран данные с BMP280:

while (1) {
  delay(1000);
  BMP280Data * bmp280Data = bmp280->getBMP280Data();
  printf("pressure   : %.2f hPa\n", bmp280Data->getPressure());
  printf("temperature: %.2f °C\n", bmp280Data->getTemperature());
  printf("altitude   : %.2f m\n\n", bmp280Data->getAltitude());
  delete bmp280Data;
}

main.cpp

#include <stdio.h>
#include <iostream>
#include <stdexcept>
#include <wiringPi.h>
#include "bmp280.h"

int main(int argc, char **argv) {
    //	char * device = "/dev/i2c-0";
    //	char * device = "/dev/i2c-1";
    char * device = "/dev/i2c-2";
    //	char * device = "/dev/i2c-3";
    int devId = BMP280_I2C_ADDRESS1;

    try {
        BMP280 * bmp280 = new BMP280(device, devId);
        int fd = bmp280->init();
        if (fd < 0) {
            printf("Device not found");
            return -1;
        }

        printf("fd       : 0x%02x\n", fd);
        printf("chip id  : 0x%02x\n", bmp280->getChipId());
        printf("chip ver : 0x%02x\n", bmp280->getChipVersion());

        bmp280->reset();
        bmp280->setPowerMode(BMP280_NORMAL_MODE);
        bmp280->setTemperatureOversampling(BMP280_ULTRAHIGHRESOLUTION_OVERSAMP_TEMPERATURE);
        bmp280->setPressureOversampling(BMP280_ULTRAHIGHRESOLUTION_OVERSAMP_PRESSURE);
        bmp280->setIrrFilter(BMP280_FILTER_COEFF_16);
        bmp280->setStandbyTime(BMP280_STANDBY_TIME_250_MS);

        printf("---------------\n");
        printf("pw mode  : 0x%02x\n", bmp280->getPowerMode());
        printf("osrs_p   : 0x%02x\n", bmp280->getPressureOversampling());
        printf("osrs_t   : 0x%02x\n", bmp280->getTemperatureOversampling());
        printf("---------------\n");
        printf("filter   : 0x%02x\n", bmp280->getIrrFilter());
        printf("t_sb     : 0x%02x\n", bmp280->getStandbyTime());
        printf("---------------\n");
        printf("spi3w sts: 0x%02x\n", bmp280->getSpi3w());
        printf("measuring: 0x%02x\n", bmp280->getMeasuringStatus());
        printf("im_update: 0x%02x\n", bmp280->getImUpdateStatus());
        printf("---------------\n");

        while (1) {
            delay(1000);
            BMP280Data * bmp280Data = bmp280->getBMP280Data();
            printf("pressure   : %.2f hPa\n", bmp280Data->getPressure());
            printf("temperature: %.2f °C\n", bmp280Data->getTemperature());
            printf("altitude   : %.2f m\n\n", bmp280Data->getAltitude());
            delete bmp280Data;
        }
        delete bmp280;
    } catch (std::exception & e) {
        printf("%s\n", e.what());
    }
    return 0;
}

Результат

Подключение BMP280 к Orange Pi, Banana Pi, Raspberry Pi - Результат

Скачать проект CodeLite

Для программирования на С/С++ я использую CodeLite IDE, так как с Code::Blocks у меня были проблемы.

Проект: BMP280_Banana_Pi_M3.zip
Flyer: BST-BMP280-FL000-00 (Bosch_Sensortec_Flyer_BMP280_onl.pdf)
Datasheet: BST-BMP280-DS001-12 (BST-BMP280-DS001-12.pdf)
Driver: BMP280 driver

Купить BME280 на AliExpress

Похожие записи

Комментарии 9

  • Добрый день! Есть вопрос по данному поводу, подскажите пожалуйста, сколько датчиков BMP280 можно подключать к одному gpio?

    • Добрый день. К примеру, на Orange Pi есть два I2C/TWI порта, так что можно подключать только два датчика. На одну шину невозможно по причине того, что нельзя менять адрес датчика.

  • Добрый день! А есть инструкция как подключить по командам? Как здесь, например https://www.rlocman.ru/review/article.html?di=337909 я просто новичек в этом деле и не сосем понимаю, что к чему.

    • Здравствуйте! Можно так:

      wget https://micro-pi.ru/wp-content/uploads/2017/02/BMP280_Banana_Pi_M3.zip
      unzip BMP280_Banana_Pi_M3.zip
      cd BMP280_Banana_Pi_M3
      g++ -Wall -o bmp280 bmp280.cpp  main.cpp -lwiringPi -lpthread
      ./bmp280

      Можете использовать:

      nano main.cpp

      чтобы редактировать главный файл, а именно переменную device, если у вас один I2C порт:

          char * device = "/dev/i2c-0";
          //  char * device = "/dev/i2c-1";
          // char * device = "/dev/i2c-2";
          //  char * device = "/dev/i2c-3";
          int devId = BMP280_I2C_ADDRESS1;
      
      • Спасибо большое! У меня RPi zero, сейчас попробую

        • Тогда вам нужно будет раскомментировать

          char * device = "/dev/i2c-0";

          и комментировать

          // char * device = "/dev/i2c-2";

          потому что там только /dev/i2c-0, и компилировать снова

          g++ -Wall -o bmp280 bmp280.cpp  main.cpp -lwiringPi -lpthread
          • Все запустилось! Температура 23, давление 995, влажность 46. Спасибо еще раз за оперативную помощь и отзывчивость!)

  • Спасибо за код. А можно ли его модернизировать так, что бы он не все время спамил, а передавал данные по изменению давления? А если изменений не происходит, то, допустим, через 5 минут, выдавал повторные данные.

Добавить комментарий для HLesetSopeak Отменить ответ

Ваш e-mail не будет опубликован. Обязательные поля помечены *