Подключение датчика окружающей среды BME280 к Orange Pi, Banana Pi, Raspberry Pi

Подключение датчика окружающей среды BME280 к Orange Pi, Banana Pi, Raspberry PiBME280 представляет собой интегрированный датчик окружающей среды, разработанный специально для мобильных устройств, где размер и низкое энергопотребление являются ключевыми.

Датчик BME280 очень похож с BMP280, различие в том, что BME280 имеет датчик влажности от чего его корпус шире чем у BMP280. Количество выводов и их расположение на корпусах совпадают. Более детальное описание датчика вы можете найти на странице BME280 — датчик давления, температуры и влажности.

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

Схема подключения BME280 к Orange Pi/Banana Pi/Raspberry Pi

С этим датчиком я работаю только по I2C. Подключается BME280 к Orange Pi также, как к Banana Pi и Raspberry Pi, у всех GPIO (на 40 пинов) похожие. В данном случае я использовал порт /dev/i2c-2, потому что удобно расположен.

Подключение BME280 к Orange Pi, Banana Pi, Raspberry Pi - GPIO40

Код программы

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

BME280RawData.h

#include <stdint.h>

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

  uint8_t tmsb;
  uint8_t tlsb;
  uint8_t txsb;

  uint8_t hmsb;
  uint8_t hlsb;

  uint32_t temperature;
  uint32_t pressure;
  uint32_t humidity;
public:
  BME280RawData(uint8_t pmsb, uint8_t plsb, uint8_t pxsb, uint8_t tmsb, uint8_t tlsb, uint8_t txsb, uint8_t hmsb, uint8_t hlsb, uint32_t temperature, uint32_t pressure,
      uint32_t humidity) {
    this->pmsb = pmsb;
    this->plsb = plsb;
    this->pxsb = pxsb;
    this->tmsb = tmsb;
    this->tlsb = tlsb;
    this->txsb = txsb;
    this->hmsb = hmsb;
    this->hlsb = hlsb;
    this->temperature = temperature;
    this->pressure = pressure;
    this->humidity = humidity;
  }

  BME280RawData() {
    this->pmsb = 0;
    this->plsb = 0;
    this->pxsb = 0;
    this->tmsb = 0;
    this->tlsb = 0;
    this->txsb = 0;
    this->hmsb = 0;
    this->hlsb = 0;
    this->temperature = 0;
    this->pressure = 0;
    this->humidity = 0;
  }

  virtual ~BME280RawData() {
  }

  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;
  }

  void setHlsb(uint8_t hlsb) {
    this->hlsb = hlsb;
  }
  void setHmsb(uint8_t hmsb) {
    this->hmsb = hmsb;
  }
  void setHumidity(uint32_t humidity) {
    this->humidity = humidity;
  }
  uint8_t getHlsb() {
    return hlsb;
  }
  uint8_t getHmsb() {
    return hmsb;
  }
  uint32_t getHumidity() {
    return humidity;
  }
};

BME280CalibrationData.h

#include <stdint.h>

class BME280CalibrationData {
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;

  uint8_t H1;
  int16_t H2;
  uint8_t H3;
  int16_t H4;
  int16_t H5;
  int8_t H6;

public:
  BME280CalibrationData() {
    T1 = 0;
    T2 = 0;
    T3 = 0;
    P1 = 0;
    P2 = 0;
    P3 = 0;
    P4 = 0;
    P5 = 0;
    P6 = 0;
    P7 = 0;
    P8 = 0;
    P9 = 0;
    H1 = 0;
    H2 = 0;
    H3 = 0;
    H4 = 0;
    H5 = 0;
    H6 = 0;
  }

  BME280CalibrationData(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,
      uint8_t H1, int16_t H2, uint8_t H3, int16_t H4, int16_t H5, int8_t H6) {
    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;
    this->H1 = H1;
    this->H2 = H2;
    this->H3 = H3;
    this->H4 = H4;
    this->H5 = H5;
    this->H6 = H6;
  }

  virtual ~BME280CalibrationData() {
  }

  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;
  }

  void setH1(uint8_t H1) {
    this->H1 = H1;
  }
  void setH2(int16_t H2) {
    this->H2 = H2;
  }
  void setH3(uint8_t H3) {
    this->H3 = H3;
  }
  void setH4(int16_t H4) {
    this->H4 = H4;
  }
  void setH5(int16_t H5) {
    this->H5 = H5;
  }
  void setH6(int8_t H6) {
    this->H6 = H6;
  }
  uint8_t getH1() {
    return H1;
  }
  int16_t getH2() {
    return H2;
  }
  uint8_t getH3() {
    return H3;
  }
  int16_t getH4() {
    return H4;
  }
  int16_t getH5() {
    return H5;
  }
  int8_t getH6() {
    return H6;
  }
};

BME280Data.h

class BMP280Data {
private:
  double pressure;    // hPa
  double temperature; // m
  double humidity;    // %
  double altitude;    // °C
public:
  BMP280Data() {
    pressure = 0;
    temperature = 0;
    altitude = 0;
    humidity = 0;
  }
  BMP280Data(double pressure, double temperature, double humidity, double altitude) {
    this->pressure = pressure;
    this->temperature = temperature;
    this->humidity = humidity;
    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;
  }
  void setHumidity(double humidity) {
    this->humidity = humidity;
  }
  double getHumidity() {
    return humidity;
  }
};

bme280.h

#include <stdint.h>
#include "BME280CalibrationData.h"
#include "BME280RawData.h"
#include "BME280Data.h"

#define MEAN_SEA_LEVEL_PRESSURE       1013

/**\name    CHIP ID DEFINITION       */
/***********************************************/
#define BME280_CHIP_ID1     (0x60)
/************************************************/
/**\name    I2C ADDRESS DEFINITION       */
/***********************************************/
#define BME280_I2C_ADDRESS1                  (0x76)
#define BME280_I2C_ADDRESS2                  (0x77)
/************************************************/
/**\name    POWER MODE DEFINITION       */
/***********************************************/
/* Sensor Specific constants */
#define BME280_SLEEP_MODE                    (0x00)
#define BME280_FORCED_MODE                   (0x01)
#define BME280_NORMAL_MODE                   (0x03)
#define BME280_SOFT_RESET_CODE               (0xB6)
/************************************************/
/**\name    STANDBY TIME DEFINITION       */
/***********************************************/
#define BME280_STANDBY_TIME_1_MS              (0x00)
#define BME280_STANDBY_TIME_63_MS             (0x01)
#define BME280_STANDBY_TIME_125_MS            (0x02)
#define BME280_STANDBY_TIME_250_MS            (0x03)
#define BME280_STANDBY_TIME_500_MS            (0x04)
#define BME280_STANDBY_TIME_1000_MS           (0x05)
#define BME280_STANDBY_TIME_2000_MS           (0x06)
#define BME280_STANDBY_TIME_4000_MS           (0x07)
/************************************************/
/**\name    OVERSAMPLING DEFINITION       */
/***********************************************/
#define BME280_OVERSAMP_SKIPPED          (0x00)
#define BME280_OVERSAMP_1X               (0x01)
#define BME280_OVERSAMP_2X               (0x02)
#define BME280_OVERSAMP_4X               (0x03)
#define BME280_OVERSAMP_8X               (0x04)
#define BME280_OVERSAMP_16X              (0x05)
/************************************************/
/**\name    WORKING MODE DEFINITION       */
/***********************************************/
#define BME280_ULTRA_LOW_POWER_MODE          (0x00)
#define BME280_LOW_POWER_MODE                (0x01)
#define BME280_STANDARD_RESOLUTION_MODE      (0x02)
#define BME280_HIGH_RESOLUTION_MODE          (0x03)
#define BME280_ULTRA_HIGH_RESOLUTION_MODE    (0x04)

#define BME280_ULTRALOWPOWER_OVERSAMP_PRESSURE          BME280_OVERSAMP_1X
#define BME280_ULTRALOWPOWER_OVERSAMP_HUMIDITY          BME280_OVERSAMP_1X
#define BME280_ULTRALOWPOWER_OVERSAMP_TEMPERATURE       BME280_OVERSAMP_1X

#define BME280_LOWPOWER_OVERSAMP_PRESSURE               BME280_OVERSAMP_2X
#define BME280_LOWPOWER_OVERSAMP_HUMIDITY               BME280_OVERSAMP_2X
#define BME280_LOWPOWER_OVERSAMP_TEMPERATURE            BME280_OVERSAMP_1X

#define BME280_STANDARDRESOLUTION_OVERSAMP_PRESSURE     BME280_OVERSAMP_4X
#define BME280_STANDARDRESOLUTION_OVERSAMP_HUMIDITY     BME280_OVERSAMP_4X
#define BME280_STANDARDRESOLUTION_OVERSAMP_TEMPERATURE  BME280_OVERSAMP_1X

#define BME280_HIGHRESOLUTION_OVERSAMP_PRESSURE         BME280_OVERSAMP_8X
#define BME280_HIGHRESOLUTION_OVERSAMP_HUMIDITY         BME280_OVERSAMP_8X
#define BME280_HIGHRESOLUTION_OVERSAMP_TEMPERATURE      BME280_OVERSAMP_1X

#define BME280_ULTRAHIGHRESOLUTION_OVERSAMP_PRESSURE    BME280_OVERSAMP_16X
#define BME280_ULTRAHIGHRESOLUTION_OVERSAMP_HUMIDITY    BME280_OVERSAMP_16X
#define BME280_ULTRAHIGHRESOLUTION_OVERSAMP_TEMPERATURE BME280_OVERSAMP_2X
/************************************************/
/**\name    FILTER DEFINITION       */
/***********************************************/
#define BME280_FILTER_COEFF_OFF               (0x00)
#define BME280_FILTER_COEFF_2                 (0x01)
#define BME280_FILTER_COEFF_4                 (0x02)
#define BME280_FILTER_COEFF_8                 (0x03)
#define BME280_FILTER_COEFF_16                (0x04)
/************************************************/

/*
 * REGISTERS
 */
#define BME280_ADDRESS                      0x76
#define BME280_REGISTER_DIG_T1              0x88
#define BME280_REGISTER_DIG_T2              0x8A
#define BME280_REGISTER_DIG_T3              0x8C
#define BME280_REGISTER_DIG_P1              0x8E
#define BME280_REGISTER_DIG_P2              0x90
#define BME280_REGISTER_DIG_P3              0x92
#define BME280_REGISTER_DIG_P4              0x94
#define BME280_REGISTER_DIG_P5              0x96
#define BME280_REGISTER_DIG_P6              0x98
#define BME280_REGISTER_DIG_P7              0x9A
#define BME280_REGISTER_DIG_P8              0x9C
#define BME280_REGISTER_DIG_P9              0x9E
#define BME280_REGISTER_DIG_H1              0xA1
#define BME280_REGISTER_DIG_H2              0xE1
#define BME280_REGISTER_DIG_H3              0xE3
#define BME280_REGISTER_DIG_H4              0xE4
#define BME280_REGISTER_DIG_H5              0xE5
#define BME280_REGISTER_DIG_H6              0xE7
#define BME280_REGISTER_CHIPID              0xD0
#define BME280_REGISTER_VERSION             0xD1
#define BME280_REGISTER_SOFTRESET           0xE0
#define BME280_RESET                        0xB6
#define BME280_REGISTER_CAL26               0xE1
#define BME280_REGISTER_CONTROLHUMID        0xF2
#define BME280_REGISTER_STATUS              0xF3
#define BME280_REGISTER_CONTROL             0xF4
#define BME280_REGISTER_CONFIG              0xF5
#define BME280_REGISTER_PRESSUREDATA_MSB    0xF7
#define BME280_REGISTER_PRESSUREDATA_LSB    0xF8
#define BME280_REGISTER_PRESSUREDATA_XLSB   0xF9
#define BME280_REGISTER_TEMPDATA_MSB        0xFA
#define BME280_REGISTER_TEMPDATA_LSB        0xFB
#define BME280_REGISTER_TEMPDATA_XLSB       0xFC
#define BME280_REGISTER_HUMIDDATA_MSB       0xFD
#define BME280_REGISTER_HUMIDDATA_LSB       0xFE

class BME280 {
private:
  char * device;
  int devId;
  int fd;
  uint8_t chipId;
  BME280CalibrationData * bmp280CalibrationData;
  BME280RawData * bmp280RawData;

  void write8(uint8_t, uint8_t);
  int read8(uint8_t);
  uint8_t readU8(uint8_t);
  int8_t readS8(uint8_t);
  int 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 compensateTemperature(int32_t t_fine);
  double compensatePressure(int32_t adc_P, int32_t t_fine);
  double compensateHumidity(int32_t adc_H, int32_t t_fine);
  BME280CalibrationData * getCalibrationData();
  BME280RawData * getRawData();

public:
  BME280(const char*, int);
  BME280(int);
  virtual ~BME280();

  BME280CalibrationData * getBmp280CalibrationData();
  BMP280Data * getBMP280Data();

  int init();
  void reset();
  void spi3wEnable();
  void spi3wDisable();
  void setPowerMode(uint8_t);
  void setTemperatureOversampling(uint8_t);
  void setPressureOversampling(uint8_t);
  void setHumidityOversampling(uint8_t);
  void setStandbyTime(uint8_t);
  void setIrrFilter(uint8_t);
  uint8_t getPowerMode();
  uint8_t getPressureOversampling();
  uint8_t getHumidityOversampling();
  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 getControlHumidity();
  uint8_t getChipId();
  uint8_t getChipVersion();
  void setReset(uint8_t);
  void setConfig(uint8_t);
  void setStatus(uint8_t);
  void setControl(uint8_t);
  void setControlHumidity(uint8_t);
};

bme280.cpp

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

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

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

uint8_t BME280::readU8(uint8_t reg) {
  return (uint8_t) read8(reg);
}

int8_t BME280::readS8(uint8_t reg) {
  return (int8_t) read8(reg);
}

int BME280::read16(uint8_t reg) {
  return wiringPiI2CReadReg16(fd, reg);
}

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

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

BME280::BME280(const char * device, int devId) :
    fd(0), chipId(0), bmp280CalibrationData(0), bmp280RawData(0) {
  this->device = new char[strlen(device)];
  strcpy(this->device, device);
  this->devId = devId;
}

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

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

int BME280::init() {
  int fd = wiringPiI2CSetup(devId);
  if (fd < 0) {
    char buffer[256];
    sprintf(buffer, "Device not found: device ID = %d", devId);
    throw std::logic_error(buffer);
  }
  this->fd = fd;
  uint8_t chipId = getChipId();
  switch (chipId) {
  case BME280_CHIP_ID1:
    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;
}

BME280CalibrationData * BME280::getCalibrationData() {
  int8_t H6;
  uint8_t H1, H3;
  int16_t T2, T3, P2, P3, P4, P5, P6, P7, P8, P9, H2, H4, H5;
  uint16_t T1, P1;

  T1 = readU16(BME280_REGISTER_DIG_T1);
  T2 = readS16(BME280_REGISTER_DIG_T2);
  T3 = readS16(BME280_REGISTER_DIG_T3);
  P1 = readU16(BME280_REGISTER_DIG_P1);
  P2 = readS16(BME280_REGISTER_DIG_P2);
  P3 = readS16(BME280_REGISTER_DIG_P3);
  P4 = readS16(BME280_REGISTER_DIG_P4);
  P5 = readS16(BME280_REGISTER_DIG_P5);
  P6 = readS16(BME280_REGISTER_DIG_P6);
  P7 = readS16(BME280_REGISTER_DIG_P7);
  P8 = readS16(BME280_REGISTER_DIG_P8);
  P9 = readS16(BME280_REGISTER_DIG_P9);
  H1 = readU8(BME280_REGISTER_DIG_H1);
  H2 = readS16(BME280_REGISTER_DIG_H2);
  H3 = readU8(BME280_REGISTER_DIG_H3);
  H4 = (int16_t)((read8(BME280_REGISTER_DIG_H4) << 4) | (read8(BME280_REGISTER_DIG_H4 + 1) & 0xF));
  H5 = (int16_t)((read8(BME280_REGISTER_DIG_H5 + 1) << 4) | (read8(BME280_REGISTER_DIG_H5) >> 4));
  H6 = readS8(BME280_REGISTER_DIG_H6);

  return new BME280CalibrationData(T1, T2, T3, P1, P2, P3, P4, P5, P6, P7, P8, P9, H1, H2, H3, H4, H5, H6);
}

BME280CalibrationData * BME280::getBmp280CalibrationData() {
  return bmp280CalibrationData;
}

BME280RawData * BME280::getRawData() {
  uint8_t pmsb, plsb, pxsb;
  uint8_t tmsb, tlsb, txsb;
  uint8_t hmsb, hlsb;
  uint32_t temperature, pressure, humidity;

  plsb = readU8(BME280_REGISTER_PRESSUREDATA_LSB);
  pmsb = readU8(BME280_REGISTER_PRESSUREDATA_MSB);
  pxsb = readU8(BME280_REGISTER_PRESSUREDATA_XLSB);

  tmsb = readU8(BME280_REGISTER_TEMPDATA_MSB);
  tlsb = readU8(BME280_REGISTER_TEMPDATA_LSB);
  txsb = readU8(BME280_REGISTER_TEMPDATA_XLSB);

  hmsb = readU8(BME280_REGISTER_HUMIDDATA_MSB);
  hlsb = readU8(BME280_REGISTER_HUMIDDATA_LSB);

  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;

  humidity = 0;
  humidity = (humidity | hmsb) << 8;
  humidity = (humidity | hlsb);

  return new BME280RawData(pmsb, plsb, pxsb, tmsb, tlsb, txsb, hmsb, hlsb, temperature, pressure, humidity);
}

void BME280::reset() {
  setReset (BME280_SOFT_RESET_CODE);
}

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

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

void BME280::setPowerMode(uint8_t mode) {
  switch (mode) {
  case BME280_FORCED_MODE:
  case BME280_NORMAL_MODE:
  case BME280_SLEEP_MODE: {
    uint8_t curentMode = getControl() & 0b11111100;
    setControl(curentMode | mode);
    break;
  }
  default:
    break;
  }
}

void BME280::setTemperatureOversampling(uint8_t oversampling) {
  switch (oversampling) {
  case BME280_OVERSAMP_SKIPPED:
  case BME280_OVERSAMP_1X:
  case BME280_OVERSAMP_2X:
  case BME280_OVERSAMP_4X:
  case BME280_OVERSAMP_8X:
  case BME280_OVERSAMP_16X: {
    uint8_t curentOversampling = getControl() & 0b00011111;
    setControl(curentOversampling | (oversampling << 5));
    break;
  }
  default:
    break;
  }
}

void BME280::setPressureOversampling(uint8_t oversampling) {
  switch (oversampling) {
  case BME280_OVERSAMP_SKIPPED:
  case BME280_OVERSAMP_1X:
  case BME280_OVERSAMP_2X:
  case BME280_OVERSAMP_4X:
  case BME280_OVERSAMP_8X:
  case BME280_OVERSAMP_16X: {
    uint8_t curentOversampling = getControl() & 0b11100011;
    setControl(curentOversampling | (oversampling << 2));
    break;
  }
  default:
    break;
  }
}

void BME280::setHumidityOversampling(uint8_t oversampling) {
  switch (oversampling) {
  case BME280_OVERSAMP_SKIPPED:
  case BME280_OVERSAMP_1X:
  case BME280_OVERSAMP_2X:
  case BME280_OVERSAMP_4X:
  case BME280_OVERSAMP_8X:
  case BME280_OVERSAMP_16X: {
    setControlHumidity(0b00000111 & oversampling);
    break;
  }
  default:
    break;
  }
}

uint8_t BME280::getHumidityOversampling() {
  return getControlHumidity() & 0b00000111;
}

void BME280::setStandbyTime(uint8_t tStandby) {
  switch (tStandby) {
  case BME280_STANDBY_TIME_1_MS:
  case BME280_STANDBY_TIME_63_MS:
  case BME280_STANDBY_TIME_125_MS:
  case BME280_STANDBY_TIME_250_MS:
  case BME280_STANDBY_TIME_500_MS:
  case BME280_STANDBY_TIME_1000_MS:
  case BME280_STANDBY_TIME_2000_MS:
  case BME280_STANDBY_TIME_4000_MS: {
    uint8_t config = getConfig() & 0b00011111;
    setConfig(config | (tStandby << 5));
    break;
  }
  default:
    break;
  }
}

void BME280::setIrrFilter(uint8_t irrFilter) {
  switch (irrFilter) {
  case BME280_FILTER_COEFF_OFF:
  case BME280_FILTER_COEFF_2:
  case BME280_FILTER_COEFF_4:
  case BME280_FILTER_COEFF_8:
  case BME280_FILTER_COEFF_16: {
    uint8_t config = getConfig() & 0b11100011;
    setConfig(config | (irrFilter << 2));
    break;
  }
  default:
    break;
  }
}

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

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

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

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

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

uint8_t BME280::getSpi3w() {
  return (getConfig() & 0b00000001) >> 5;
}

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

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

uint8_t BME280::getConfig() {
  return readU8(BME280_REGISTER_CONFIG);
}

uint8_t BME280::getStatus() {
  return readU8(BME280_REGISTER_STATUS);
}

uint8_t BME280::getControl() {
  return readU8(BME280_REGISTER_CONTROL);
}

uint8_t BME280::getControlHumidity() {
  return readU8(BME280_REGISTER_CONTROLHUMID);
}

uint8_t BME280::getChipId() {
  return readU8(BME280_REGISTER_CHIPID);
}

uint8_t BME280::getChipVersion() {
  return readU8(BME280_REGISTER_VERSION);
}

void BME280::setReset(uint8_t value) {
  write8(BME280_REGISTER_SOFTRESET, value);
}

void BME280::setConfig(uint8_t value) {
  write8(BME280_REGISTER_CONFIG, value);
}

void BME280::setStatus(uint8_t value) {
  write8(BME280_REGISTER_STATUS, value);
}

void BME280::setControl(uint8_t value) {
  write8(BME280_REGISTER_CONTROL, value);
}

void BME280::setControlHumidity(uint8_t value) {
  write8(BME280_REGISTER_CONTROLHUMID, value);
}

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

int32_t BME280::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 BME280::compensateTemperature(int32_t t_fine) {
  double T = (t_fine * 5 + 128) >> 8;
  return T / 100;
}

double BME280::compensatePressure(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;
}

double BME280::compensateHumidity(int32_t adc_H, int32_t t_fine) {
  int32_t v_x1_u32r;

  v_x1_u32r = (t_fine - ((int32_t) 76800));

  v_x1_u32r = (((((adc_H << 14) - (((int32_t) bmp280CalibrationData->getH4()) << 20) - (((int32_t) bmp280CalibrationData->getH5()) * v_x1_u32r)) + ((int32_t) 16384)) >> 15)
      * (((((((v_x1_u32r * ((int32_t) bmp280CalibrationData->getH6())) >> 10) * (((v_x1_u32r * ((int32_t) bmp280CalibrationData->getH3())) >> 11) + ((int32_t) 32768))) >> 10)
          + ((int32_t) 2097152)) * ((int32_t) bmp280CalibrationData->getH2()) + 8192) >> 14));

  v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((int32_t) bmp280CalibrationData->getH1())) >> 4));

  v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r;
  v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r;
  double h = (v_x1_u32r >> 12);
  return h / 1024.0;
}

BMP280Data * BME280::getBMP280Data() {
  int32_t t_fine;
  double t, p, h, a;
  while (getMeasuringStatus()) {
  }
  if (bmp280RawData) {
    delete bmp280RawData;
  }
  bmp280RawData = getRawData();
  t_fine = getTemperatureC(bmp280RawData->getTemperature());
  t = compensateTemperature(t_fine); // C
  p = compensatePressure(bmp280RawData->getPressure(), t_fine) / 100; // hPa
  h = compensateHumidity(bmp280RawData->getHumidity(), t_fine);
  a = getAltitude(p);                         // meters

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

main.cpp

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

int main() {
// char * device = "/dev/i2c-0";
// char * device = "/dev/i2c-1";
  char * device = "/dev/i2c-2";
// char * device = "/dev/i2c-3";
  int devId = BME280_I2C_ADDRESS1;
  try {
    BME280 * bme280 = new BME280(device, devId);
    int fd = bme280->init();
    bme280->reset();

    if (fd < 0) {
      printf("Device not found");
      return -1;
    }

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

    bme280->reset();
    bme280->setPowerMode(BME280_NORMAL_MODE);
    bme280->setTemperatureOversampling(BME280_ULTRAHIGHRESOLUTION_OVERSAMP_TEMPERATURE);
    bme280->setPressureOversampling(BME280_ULTRAHIGHRESOLUTION_OVERSAMP_PRESSURE);
    bme280->setHumidityOversampling(BME280_ULTRAHIGHRESOLUTION_OVERSAMP_HUMIDITY);
    bme280->setIrrFilter(BME280_FILTER_COEFF_16);
    bme280->setStandbyTime(BME280_STANDBY_TIME_250_MS);

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

    while (1) {
      delay(1000);
      BMP280Data * bme280Data = bme280->getBMP280Data();
      printf("pressure   : %.2f \tmm Hg\n", bme280Data->getPressure() / 1.3332239);
      printf("humidity   : %.2f \t%c\n", bme280Data->getHumidity(), '%');
      printf("temperature: %.2f \t°C\n", bme280Data->getTemperature());
      printf("altitude   : %.2f \tm\n\n", bme280Data->getAltitude());
    }
    delete bme280;
  } catch (std::exception & e) {
    printf("%s\n", e.what());
  }
  return 0;
}

Результат

Подключение датчика окружающей среды BME280 к Orange Pi, Banana Pi, Raspberry Pi
Подключение датчика окружающей среды BME280 к Orange Pi, Banana Pi, Raspberry Pi
Подключение датчика окружающей среды BME280 к Orange Pi, Banana Pi, Raspberry Pi
Подключение датчика окружающей среды BME280 к Orange Pi, Banana Pi, Raspberry Pi

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

CodeLite проект: BME280_Banana_Pi_M3.zip
Flyer: BST-BME280-FL000-02
Datasheet: BST-BME280-DS001-11
Handling, soldering & mounting instructions: BST-BME280-HS001-06
Shipment & packaging details: BST-BME280-SP000-00
Driver: BME280 driver

Купить BME280 на AliExpress

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

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

  • Добрый день. Не понятно, что делать с кодом, куда вставлять? Создать файлы, куда их помещать, какими командами запускать в терминале? Компилировать нужно? Как это делать? Для кого эта инструкция?

  • Здравствуйте. у меня Raspberry pi 3. как подключить два датчика BME 280 по протоколу I2C?

    • С помощью вывода SDO. Когда вы оставляете вывод SDO от одного датчика неподключенным, вы говорите этому датчику использовать адрес I2C по умолчанию (0x77).
      Но когда вы подключаете вывод SDO от второго датчика к GND, вы указываете ему использовать альтернативный адрес I2C (0x76).

      /************************************************/
      /**\name    I2C ADDRESS DEFINITION       */
      /***********************************************/
      #define BME280_I2C_ADDRESS1                  (0x76)
      #define BME280_I2C_ADDRESS2                  (0x77)
      /************************************************/

      После чего создаёте два объекта:

      BME280 * bme2801 = new BME280(device, BME280_I2C_ADDRESS1);
      BME280 * bme2802 = new BME280(device, BME280_I2C_ADDRESS2);
  • BME-280 от BMP-280 отличается наличием датчика атмосферного давления, а от ширины корпуса зависит только от напряжения питания. Широкий — 3.3В Узкий — 5В.

  • Проблема дубликатов номеров: как решить этот вопрос, эффективные советы для владельцев автомобилей.
    Как распознать дубликат номера на авто, которые помогут подделку.
    Секреты определения настоящего автомобильного номера, если вы хотите.
    Что делать, если вам подделали номер на автомобиле, и как вести себя в этой ситуации.
    Как избежать покупки автомобиля с фальшивым номером, для новичков в автомире купить авто.
    Этапы проверки подлинности номерного знака на автомобиле, которые помогут избежать неприятностей.
    Какие последствия могут быть при использовании дубликата автомобильного номера, и что важно знать в случае обнаружения поддельного номера.
    Меры предосторожности при покупке авто для избежания дублированных номеров, и что делать, чтобы избежать неприятностей.
    изготовление автомобильных номеров http://www.dublikatznakov.ru/ .

  • Что делать, если вы столкнулись с дубликатами номеров на своем транспортном средстве, эффективные советы для водителей.
    Знакомство с признаками дубликата автомобильного номера, которые помогут подделку.
    Секреты определения настоящего автомобильного номера, если вы хотите.
    Что делать, если вам подделали номер на автомобиле, и что важно помнить в такой ситуации.
    Что нужно знать, чтобы не стать жертвой мошенничества, если вы только начинаете оценивать купить авто.
    Подробная инструкция по проверке номера автомобиля при покупке, которые помогут избежать неприятностей.
    Признаки фальшивого номера и как не нарваться на подделку, и что делать, если вы столкнулись с такой ситуацией.
    Как защитить свой автомобиль от подделки номера, и как предотвратить возможные проблемы.
    изготовление дубликатов номеров http://dublikatznakov.ru/ .

  • Проблема дубликатов номеров: как решить этот вопрос, подробное руководство для владельцев автомобилей.
    Как распознать дубликат номера на авто, быстро разобраться подделку.
    Как отличить оригинальный номер от дубликата, для тех, кто желает.
    Что делать, если вам подделали номер на автомобиле, и что важно помнить в такой ситуации.
    Что нужно знать, чтобы не стать жертвой мошенничества, если вы только начинаете оценивать купить авто.
    Как провести проверку номера машины перед покупкой, которые помогут вам сэкономить время и деньги.
    Признаки фальшивого номера и как не нарваться на подделку, и что делать, если вы столкнулись с такой ситуацией.
    Что нужно знать, чтобы не стать жертвой мошенников, и что делать, чтобы избежать неприятностей.
    изготовление номеров на автомобиль https://dublikatznakov.ru/ .

  • Что делать, если вы столкнулись с дубликатами номеров на своем транспортном средстве, эффективные советы для владельцев автомобилей.
    Знакомство с признаками дубликата автомобильного номера, чтобы избежать подделку.
    Как отличить оригинальный номер от дубликата, для тех, кто желает.
    Куда обращаться, если вы обнаружили подделку номера, и какие шаги следует предпринять незамедлительно.
    Советы по проверке подлинности номера при покупке машины, для новичков в автомире купить авто.
    Подробная инструкция по проверке номера автомобиля при покупке, которые помогут избежать неприятностей.
    Какие последствия могут быть при использовании дубликата автомобильного номера, и как избежать проблем с законом.
    Меры предосторожности при покупке авто для избежания дублированных номеров, и что делать, чтобы избежать неприятностей.
    заказать номера на автомобиль https://www.dublikatznakov.ru/ .

  • Познакомьтесь один-другой нашим проф коллективом, яже создаёт чудесную этажерка, воплощая ваши грезы на реальность https://www.cehitae2kuhnishki.ru.

  • Фотофабрика кухонных гарнитуров в течение С-петербурге — это чемодан надежный партнер в течение создании кухонных интерьеров. Я специализируемся на разработке, фабрике равно аппарате высококачественных кухонных гарнитуров, каковые соединяют в течение себе стиль, функциональность равно долговечность. Наша послание – позволить клиентам отдельные резолюции, созданные один-два учётом их пожеланий и еще необходимостей, чтобы всякая кухня выходила приятным также спокойным местом для жизни и творчества http://www.tivokya0kuhnishki.ru.

  • Наша юкос «Фотосайт по мебели чтобы кухни» берется организацией равно реализацией лучшей кашеварной мебели. Пишущий эти строки делаем отличное предложение широченный прибор продукции, яже парирует наиболее сегодняшним шаблонам также направленностям дизайна http://sufebey8kuhnishki.ru/.


  • Продажа мини-погрузчиков Lonking

    Продажа мини-погрузчиков Lonking на территории России от официального
    дистрибьютора. Новая многофункциональная техника для любых задач.
    Наши машины предназначены для того, чтобы упростить вашу работу:
    от строительных площадок до складских операций.

    Высокая эффективность, надежность и инновационные решения — все,
    что вам нужно для успешных проектов. Погрузите свой бизнес в будущее
    с мини-погрузчиками Lonking!

    47% российских покупателей выбрали мини-погрузчики Lonking в 2023 году продано более 1200 единиц.
    Мини-погрузчики Lonking

  • Наш этношоп НашаМебель предлагает широченный прибор кухонь, которые посодействуют создать уют (а) также удобство на вашем фамилии http://notahye4kuhnishki.ru/.

  • Наша юкос «Фотосайт числом мебели для кухни» захватывается учреждением равно реализацией лучшей кашеварной мебели. Автор предлагаем широкий гарнитура продукции, яже дает ответ наиболее прогрессивным шаблонам (а) также направленностям дизайна http://sufebey8kuhnishki.ru.

  • Фабрика кухонных гарнитуров в течение Санкт-петербурге — этто чемодан фундаментальный партнер в создании кашеварных интерьеров. Автор этих строк специализируемся сверху исследованию, производстве равно аппарате высококачественных кашеварных гарнитуров, какие соединяют в течение себя стиль, работоспособность а также долговечность. Наша задача – вверить посетителям индивидуальные ответа, сформированные один-два учётом ихний пожеланий а также необходимостей, чтоб всякая шакша стало быть уютным и удобным местностью чтобы бытия а также творчества https://www.tivokya0kuhnishki.ru.

  • Познакомьтесь один-другой нашим профессиональным коллективом, который творит уникальную мебель, воплощая ваши грезы в течение явь https://www.cehitae2kuhnishki.ru.

  • Фотофабрика кухонных гарнитуров в Санкт-петербурге — этто ваш надежный партнер на создании кашеварных интерьеров. Мы работаем на разработке, изготовлении и аппарате первоклассных кашеварных гарнитуров, каковые соединяют на себя язык, функциональность а также долговечность. Наша миссия – выделить посетителям индивидуальные резолюции, учрежденные не без; учётом их пожеланий (а) также надобностей, чтоб любая шакша стала уютным также спокойным площадью для жизни а также творчества https://tivokya0kuhnishki.ru.

  • Если вы ищете возможность получить вооружение, без покидая со квартиры, мы рекомендуем вам обратить внимание на целевой канал в Telegram. Тут ты увидите разнообразный выбор огнестрельного и холодного или колюще-режущего оружия, как и аксессуаров.

    Что предлагает канал:

    Свежие предложения и акции Транспортировка в городу Консультации а сопровождение клиентов Присоединяйтесь в каналу и имейте возможность к эксклюзивным предложениям! купить патроны на травмат В нынешнем веке проблема защищённости делается всё ещё насущным. Наличие пистолета при вас способно стать ключевым моментом в обстановке, когда необходимо оградить человека и своих.

    Прежде всего, оружие является надежным способом самозащиты. Оно позволяет не только отпугнуть потенциальных преступников, но и защитить личность в случае реальной риска. Чувство уверенности в том, что у человека есть возможность оградиться, может существенно повысить уровень своей безопасности.

    Кроме того, обладание пистолета имеет возможность вызвать эмоциональное влияние на людей вокруг. Персонажи, которые знают, что вы способны себя оборонить, в большинстве случаев относятся к вам с осторожностью и осторожностью.

    В завершение, в определённых ситуациях оружие способно стать одним способом предотвращения враждебности. Важно помнить, что с огромной мощью связано и весомая ответственность. Уместное применение и осознание законодательства об пистолетах — важные детали, которые следует держать в голове.

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

  • Идеи для изготовления креативных квадратных номеров, Идеи для дизайна квадратных номеров в стиле лофт

  • Если ты ищете возможность получить огнестрельное оружие, без покидая со дома, мы советуем тебе уделить взор к особый канал в Telegram. Здесь ты найдете большой выбор огнестрельного и холодного и холодного вооружения, а также дополнительных предметов.

    Что может предложить данный канал:

    Свежие акции а акции Транспортировка по городу Консультации и поддержка клиентов Присоединяйтесь в нашему каналу и получите возможность к эксклюзивным предложениям! [url=https://telegra.ph/kuplyu-travmat-pistolet-v-moskve-10-09]купить оружие для самообороны[/url] В текущем мире тема защищённости превращается всё сильнее важным. Присутствие пистолета при вас способно оказаться ключевым условием в ситуации, когда необходимо защитить себя и близких.

    Во-первых, оружие является надежным инструментом защищённости. Оно помогает не только отпугнуть потенциальных злоумышленников, но и обезопасить вас в случае непосредственной риска. Чувство уверенности в том, что у человека есть возможность оградиться, может значительно повысить границу своей охраны.

    Следом за этим, обладание оружия способно вызвать внутреннее эффект на окружающих. Персонажи, которые знают, что вы можете вас оградить, чаще всего относятся к вам с уважением и вниманием.

    В завершение, в некоторых обстоятельствах пистолет имеет возможность быть уникальным способом прекращения враждебности. Нужно осознавать, что с большой властью связано и серьёзная обязанность. Правильное применение и понимание правил об вооружении — ключевые моменты, которые важно учитывать.

    Таким образом, обладание оружия способно сыграть важную роль в обеспечении персональной безопасности, однако, его использование требует серьёзного отношения и выполнения всех обязательных правил.


  • Интернет-магазин плитки и керамики «ИнфоПлитка»

    Интернет-магазин керамической плитки и керамогранита «Infoplitka» (infoplitka.ru)
    предлагает широкий ассортимент высококачественной плитки и керамогранита от ведущих производителей.
    Мы стремимся предложить нашим клиентам только лучшее, поэтому в ассортименте представлены товары,
    отвечающие самым высоким стандартам качества и дизайна.

    Мы понимаем, что выбор керамической плитки и керамогранита – это важный этап в создании
    комфортного и стильного интерьера. Поэтому наша команда профессионалов готова помочь вам в
    подборе идеального варианта для вашего проекта. Независимо от того, нужны ли вам плитка
    для ванной комнаты, кухни, гостиной, или же керамогранит для облицовки пола, вы всегда найдете
    у нас разнообразные и актуальные коллекции, соответствующие последним тенденциям в области
    дизайна интерьеров.
    Официальный сайт «ИнфоПлитка»

  • Как не допустить дублирование номеров, проверьте свой номер на уникальность, будьте осторожны и изучите, Правила безопасного выбора номера, не допустите ошибок при выборе номера
    дубликаты гос номера https://dublikat-gos-nomer.ru/ .

  • Отечественный этношоп НашаМебель приглашает широченный ассортимент кухонь, которые посодействуют создать устроенность и удобства в течение вашем фамилии http://www.notahye4kuhnishki.ru.

  • индивидуалки Донецк проститутки
    Ищете заказать девушку легкого поведения в городе Донецк? Мы предлагаем лучшие индивидуалки этого города для наслаждения! У нас всегда надёжные девушки с шикарной внешностью и лучшим сервисом. Желаете вызвать индивидуалку на вечер? Обращайтесь к нам, и все ваши желания будут выполнены!

    Не пропустите возможность встретиться с самыми горячими индивидуалками города Донецк.

  • Как не допустить дублирование номеров, избегайте повторения номеров, обратите внимание на важные моменты, нашли дубликаты? Действуйте сразу, примените рекомендации перед регистрацией
    изготовление дубликатов гос номера https://dublikat-gos-nomer.ru/ .

  • которые вы должны знать.
    Экстренные меры при обнаружении дубликатов номеров, немедленно действуя.
    Полезные приемы для быстрой очистки от дубликатов номеров, которые сэкономят ваше время.
    Способы предотвращения штрафов за дубликаты номеров, которые защитят ваш бюджет.
    Дубликаты номеров: как это влияет на рейтинг сайта, и как сохранить позиции в поисковых системах.

    изготовление дубликата http://www.gosdublikati.ru .

  • Найти специалиста по независимой экспертизе и оценке!

    Сайт-агрегатор компаний и услуг в сфере независимой экспертизы и оценки.
    Мы создали этот проект, чтобы помочь вам найти надежных и опытных профессионалов
    для решения ваших задач.

    Главная цель — сделать процесс поиска специалистов по независимой экспертизе
    и оценке максимально простым и эффективным. Мы стремимся предоставить вам
    доступ к компаниям, которые гарантируют высокое качество услуг.
    С нами вы сможете быстро найти нужного эксперта и сравнить различные предложения.

    На нашем сайте собраны карточки компаний, каждая из которых содержит подробную
    информацию о предоставляемых услугах. Посетители могут фильтровать предложения
    по различным критериям:

    Локация
    Направление экспертизы
    Стоимость услуг
    Отзывы клиентов

    Наш сайт Специалисты по независимой экспертизе и оценке.

  • досуг Донецк проститутки
    Ищете заказать проститутку в Донецке? Мы предлагаем профессиональные индивидуалки этого города для вашего удовольствия и релакса! У нас только проверенные девушки с идеальной внешностью и лучшим сервисом. Хотите вызвать индивидуалку на вечер? Обращайтесь к нам, и ваши фантазии станут реальностью!

    Не пропустите возможность провести время с самыми привлекательными проститутками города Донецк.

  • проститутки выезд Донецк
    Задумались, где заказать индивидуалку в городе Донецк? Мы предлагаем профессиональные индивидуалки Донецка для вашего удовольствия! У нас всегда профессиональные проститутки с безупречным внешним видом и лучшим сервисом. Желаете вызвать индивидуалку на вечер? Свяжитесь с нами, и ваши мечты осуществятся!

    Не пропустите возможность провести время с самыми горячими девушками Донецка.

  • которые стоит учесть.
    Что делать, если обнаружены дубликаты номеров, не откладывая на потом.
    Способы быстрого поиска и удаления дубликатов номеров, которые ускорят процесс.
    Важные рекомендации по избежанию штрафов за дубликаты номеров, которые сэкономят ваши финансы.
    Дубликаты номеров: как это влияет на рейтинг сайта, и как сохранить позиции в поисковых системах.

    дубликат номера авто http://gosdublikati.ru/ .

  • которые помогут вам.
    Экстренные меры при обнаружении дубликатов номеров, немедленно действуя.
    Эффективные методы поиска и устранения дубликатов номеров, которые ускорят процесс.
    Способы предотвращения штрафов за дубликаты номеров, которые помогут сохранить ваш бюджет.
    Последствия дубликатов номеров для рейтинга сайта, и как обезопасить свой сайт от негативного воздействия.

    дубликат госномера на автомобиль https://www.gosdublikati.ru/ .

  • Полезные советы по предотвращению дубликатов номеров, для более эффективного контроля.

    Способы выявления дубликатов номеров, которые помогут в оптимизации процесса.

    Чем опасны дубликаты номеров в бизнесе, для поддержания доверия клиентов.

    Инструкция по поиску и удалению дубликатов номеров, для ускорения работы программы.

    Как обеспечить уникальность номеров при регистрации, и избежать проблем с базой данных.

    Практические советы по предотвращению недобросовестного использования номеров, для гарантированной безопасности данных.

    Как найти и удалить дубликаты номеров в интернете, для повышения эффективности.

    Что делать, если столкнулся с дубликатами номеров, для минимизации ошибок.
    номера на заказ на машину https://www.htpps://dublikatgosnomer.ru/ .

  • Sent us home with dr visit on day four for weight check.
    FDA launching campaign to warn consumers of dangers in buying european pharmacy hydrocodone at cheap prices
    Persons with milder allergic reactions to eggs such as hives only should speak with their vaccine or health care provider first.

  • If you think your child has appendicitis, contact a doctor immediately.
    amounts with discountsExperience health benefits when you buy cialis tablets with wholesale discounts
    Inability to concentrate, remember or think straight sometimes mistaken for dementia.

  • The ticks are most commonly carried by deer and by the white-footed mouse, but other carriers have been found as well.
    Look at discount offers to get a great deal when you can mdma online pharmacy from Canada to gain your trust.
    How reliable is the information?

  • The sad part is that the condition is frequently triggered by trauma or sometimes the death of a spouse.
    Spectacular products about ED at when is the best time to take cialis after you compare online offerings
    Below are links to clinical trials for inflammatory breast cancer patients.

  • Tillman whether a trip to the vet is necessary.
    Life is meaningful again at botox online pharmacy are much better deals than in local stores.
    Following tissue removal, the incision is closed with sutures.

  • It then pierces the dura and reaches the cerebrospinal fluid.
    Check expiration dates when you pharmacy store hours or in a regular pharmacy?
    Most patients with type 2 DM who are treated with oral antihyperglycemic drugs maintain acceptable glucose levels when fasting and may not require insulin in the perioperative period.

  • Thank you for this insight.
    When you are looking to https://ivermectinfastmed.com/ ivermectin cream uk shipped to your door in low-cost high-value deal
    Coughing 0 1 2 3 4 5 6 7 21.

  • However, some older people with mild anemia have no symptoms at all, particularly when anemia develops gradually, as it often does in older people.
    Do I need a doctor’s prescription to buy https://ivermectinfastmed.com/ ivermectin ebay prices. Great savings on all drugs!
    Claudia French IMVA KARAOKE JUNKIE My long term Nexium use is due to Barretts esophagus.

  • A person’s long term outcome depends upon how much of the brain is damaged, how quickly treatment begins, and several other factors.
    Buy direct from our online pharmacy. Your https://cilisfastmed.com/ does cialis help with premature ejaculation from legitimate pharmacies if you desire cheap discounts
    Laboratory tests including blood tests and imaging of the brain’s structure.

  • It is accompanied by shifting alertness, resulting in moments of sleepiness alternating with moments of agitation.
    Where can I find information that compares https://cilisfastmed.com/ what is better viagra or cialis at cheap prices after comparing offers
    See separate leaflet called Medication After a Myocardial Infarction which discusses this more fully.

  • Шаг за шагом: создание номера на авто, оригинальные идеи для номера, как сделать номер самостоятельно: подробное руководство, сделай сам: уникальный номер на машину, подборка лучших идей для номера на авто, сделайте уникальный номер для машины за минуты, топ-10 идей для номеров на авто, как сделать номер на машину своими руками: пошаговая инструкция, советы по выбору номера для машины, как изменить номер на автомобиле: подробная инструкция, DIY: создание оригинального номера на авто, лучшие способы изготовления номеров на автомобиль, как сделать номер на автомобиль красиво и аккуратно, стильные варианты номеров для автомобиля, как сделать стильный номер для машины, DIY: как сделать креативный номер на авто, как сделать номер для автомобиля с минимальными затратами, подборка лучших вариантов номеров для авто, как сделать стильный номер на машину за минуты.
    авто номера авто номера .

  • Полезные советы по предотвращению дубликатов номеров, для более эффективного контроля.

    Как распознать дубликаты номеров в базе данных, для улучшения качества данных.

    Последствия дубликатов номеров для компании, для обеспечения безопасности информации.

    Как удалить дубликаты номеров из Excel, для улучшения качества данных.

    Советы по предотвращению дубликатов номеров в регистрационных формах, для улучшения пользовательского опыта.

    Как защититься от нежелательных дубликатов номеров, для предотвращения мошенничества.

    Как обнаружить дубликаты номеров в онлайн-базе, для очистки базы данных.

    Как предотвратить повторное появление дубликатов, для улучшения системы контроля.
    номера автомобильные изготовление https://htpps://dublikatgosnomer.ru/ .

Добавить комментарий

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