219 lines
8.5 KiB
C++
219 lines
8.5 KiB
C++
#include "GyverBME280.h"
|
||
|
||
/* ============ Utilities ============ */
|
||
|
||
float pressureToAltitude(float pressure) {
|
||
if (!pressure) return 0; // If the pressure module has been disabled return '0'
|
||
pressure /= 100.0F; // Convert [Pa] to [hPa]
|
||
return 44330.0f * (1.0f - pow(pressure / 1013.25f, 0.1903f)); // Сalculate altitude
|
||
}
|
||
|
||
float pressureToMmHg(float pressure) {
|
||
return (float)(pressure * 0.00750061683f); // Convert [Pa] to [mm Hg]
|
||
}
|
||
|
||
/* ============ Setup & begin ============ */
|
||
|
||
GyverBME280::GyverBME280(TwoWire &wire) {
|
||
_wire = &wire;
|
||
}
|
||
|
||
bool GyverBME280::begin() {
|
||
return begin(0x76);
|
||
}
|
||
|
||
bool GyverBME280::begin(uint8_t address) {
|
||
_i2c_address = address;
|
||
/* === Start I2C bus & check BME280 === */
|
||
if (!reset()) return false; // BME280 software reset & ack check
|
||
uint8_t ID = readRegister(0xD0);
|
||
if (ID != 0x60 && ID != 0x58) return false; // Check chip ID (bme/bmp280)
|
||
readCalibrationData(); // Read all calibration values
|
||
|
||
/* === Load settings to BME280 === */
|
||
writeRegister(0xF2, _hum_oversampl); // write hum oversampling value
|
||
writeRegister(0xF2, readRegister(0xF2)); // rewrite hum oversampling register
|
||
writeRegister(0xF4, ((_temp_oversampl << 5) | (_press_oversampl << 2) | _operating_mode)); // write temp & press oversampling value , normal mode
|
||
writeRegister(0xF5, ((_standby_time << 5) | (_filter_coef << 2))); // write standby time & filter coef
|
||
return true;
|
||
}
|
||
|
||
void GyverBME280::setMode(uint8_t mode) {
|
||
_operating_mode = mode;
|
||
}
|
||
|
||
|
||
void GyverBME280::setFilter(uint8_t mode) {
|
||
_filter_coef = mode;
|
||
}
|
||
|
||
void GyverBME280::setStandbyTime(uint8_t mode) {
|
||
_standby_time = mode;
|
||
}
|
||
|
||
void GyverBME280::setHumOversampling(uint8_t mode) {
|
||
_hum_oversampl = mode;
|
||
}
|
||
|
||
void GyverBME280::setTempOversampling(uint8_t mode) {
|
||
_temp_oversampl = mode;
|
||
}
|
||
|
||
void GyverBME280::setPressOversampling(uint8_t mode) {
|
||
_press_oversampl = mode;
|
||
}
|
||
|
||
/* ============ Reading ============ */
|
||
|
||
int32_t GyverBME280::readTempInt(void) {
|
||
int32_t temp_raw = readRegister24(0xFA); // Read 24-bit value
|
||
if (temp_raw == 0x800000) return 0; // If the temperature module has been disabled return '0'
|
||
|
||
temp_raw >>= 4; // Start temperature reading in integers
|
||
int32_t value_1 = ((((temp_raw >> 3) - ((int32_t)CalibrationData._T1 << 1))) *
|
||
((int32_t)CalibrationData._T2)) >> 11;
|
||
int32_t value_2 = (((((temp_raw >> 4) - ((int32_t)CalibrationData._T1)) *
|
||
((temp_raw >> 4) - ((int32_t)CalibrationData._T1))) >> 12) * ((int32_t)CalibrationData._T3)) >> 14;
|
||
|
||
return ((int32_t)value_1 + value_2); // Return temperature in integers
|
||
}
|
||
|
||
|
||
float GyverBME280::readTemperature(void) {
|
||
int32_t temp_raw = readTempInt();
|
||
float T = (temp_raw * 5 + 128) >> 8;
|
||
return T / 100.0; // Return temperature in float
|
||
}
|
||
|
||
|
||
float GyverBME280::readPressure(void) {
|
||
uint32_t press_raw = readRegister24(0xF7); // Read 24-bit value
|
||
if (press_raw == 0x800000) return 0; // If the pressure module has been disabled return '0'
|
||
|
||
press_raw >>= 4; // Start pressure converting
|
||
int64_t value_1 = ((int64_t)readTempInt()) - 128000;
|
||
int64_t value_2 = value_1 * value_1 * (int64_t)CalibrationData._P6;
|
||
value_2 = value_2 + ((value_1 * (int64_t)CalibrationData._P5) << 17);
|
||
value_2 = value_2 + (((int64_t)CalibrationData._P4) << 35);
|
||
value_1 = ((value_1 * value_1 * (int64_t)CalibrationData._P3) >> 8) + ((value_1 * (int64_t)CalibrationData._P2) << 12);
|
||
value_1 = (((((int64_t)1) << 47) + value_1)) * ((int64_t)CalibrationData._P1) >> 33;
|
||
|
||
if (!value_1) return 0; // Avoid division by zero
|
||
|
||
int64_t p = 1048576 - press_raw;
|
||
p = (((p << 31) - value_2) * 3125) / value_1;
|
||
value_1 = (((int64_t)CalibrationData._P9) * (p >> 13) * (p >> 13)) >> 25;
|
||
value_2 = (((int64_t)CalibrationData._P8) * p) >> 19;
|
||
p = ((p + value_1 + value_2) >> 8) + (((int64_t)CalibrationData._P7) << 4);
|
||
|
||
return (float)p / 256; // Return pressure in float
|
||
}
|
||
|
||
|
||
float GyverBME280::readHumidity(void) {
|
||
_wire->beginTransmission(_i2c_address); // Start I2C transmission
|
||
_wire->write(0xFD); // Request humidity data register
|
||
if (_wire->endTransmission() != 0) return 0;
|
||
_wire->requestFrom(_i2c_address, 2); // Request humidity data
|
||
int32_t hum_raw = ((uint16_t)_wire->read() << 8) | (uint16_t)_wire->read(); // Read humidity data
|
||
if (hum_raw == 0x8000) return 0; // If the humidity module has been disabled return '0'
|
||
|
||
int32_t value = (readTempInt() - ((int32_t)76800)); // Start humidity converting
|
||
value = (((((hum_raw << 14) - (((int32_t)CalibrationData._H4) << 20) -
|
||
(((int32_t)CalibrationData._H5) * value)) +((int32_t)16384)) >> 15) *
|
||
(((((((value * ((int32_t)CalibrationData._H6)) >> 10) *(((value *
|
||
((int32_t)CalibrationData._H3)) >> 11) + ((int32_t)32768))) >> 10) +
|
||
((int32_t)2097152)) * ((int32_t)CalibrationData._H2) + 8192) >> 14));
|
||
value = (value - (((((value >> 15) * (value >> 15)) >> 7) * ((int32_t)CalibrationData._H1)) >> 4));
|
||
value = (value < 0) ? 0 : value;
|
||
value = (value > 419430400) ? 419430400 : value;
|
||
float h = (value >> 12);
|
||
|
||
return h / 1024.0; // Return humidity in float
|
||
}
|
||
|
||
/* ============ Misc ============ */
|
||
|
||
bool GyverBME280::isMeasuring(void) {
|
||
return (bool)((readRegister(0xF3) & 0x08) >> 3); // Read status register & mask bit "measuring"
|
||
}
|
||
|
||
void GyverBME280::oneMeasurement(void) {
|
||
writeRegister(0xF4 , ((readRegister(0xF4) & 0xFC) | 0x02)); // Set the operating mode to FORCED_MODE
|
||
}
|
||
|
||
/* ============ Private ============ */
|
||
|
||
/* = BME280 software reset = */
|
||
bool GyverBME280::reset(void) {
|
||
if (!writeRegister(0x0E , 0xB6)) return false;
|
||
delay(10);
|
||
return true;
|
||
}
|
||
|
||
|
||
/* = Read and combine three BME280 registers = */
|
||
uint32_t GyverBME280::readRegister24(uint8_t address) {
|
||
_wire->beginTransmission(_i2c_address);
|
||
_wire->write(address);
|
||
if (_wire->endTransmission() != 0) return 0x800000;
|
||
_wire->requestFrom(_i2c_address, 3);
|
||
return (((uint32_t)_wire->read() << 16) | ((uint32_t)_wire->read() << 8) | (uint32_t)_wire->read());
|
||
}
|
||
|
||
|
||
/* = Write one 8-bit BME280 register = */
|
||
bool GyverBME280::writeRegister(uint8_t address , uint8_t data) {
|
||
_wire->beginTransmission(_i2c_address);
|
||
_wire->write(address);
|
||
_wire->write(data);
|
||
if (_wire->endTransmission() != 0) return false;
|
||
return true;
|
||
}
|
||
|
||
|
||
/* = Read one 8-bit BME280 register = */
|
||
uint8_t GyverBME280::readRegister(uint8_t address) {
|
||
_wire->beginTransmission(_i2c_address);
|
||
_wire->write(address);
|
||
if (_wire->endTransmission() != 0) return 0;
|
||
_wire->requestFrom(_i2c_address , 1);
|
||
return _wire->read();
|
||
}
|
||
|
||
/* = Structure to store all calibration values = */
|
||
void GyverBME280::readCalibrationData(void) {
|
||
/* first part request*/
|
||
_wire->beginTransmission(_i2c_address);
|
||
_wire->write(0x88);
|
||
if (_wire->endTransmission() != 0) return;
|
||
_wire->requestFrom(_i2c_address , 25);
|
||
/* reading */
|
||
CalibrationData._T1 = (_wire->read() | (_wire->read() << 8));
|
||
CalibrationData._T2 = (_wire->read() | (_wire->read() << 8));
|
||
CalibrationData._T3 = (_wire->read() | (_wire->read() << 8));
|
||
CalibrationData._P1 = (_wire->read() | (_wire->read() << 8));
|
||
CalibrationData._P2 = (_wire->read() | (_wire->read() << 8));
|
||
CalibrationData._P3 = (_wire->read() | (_wire->read() << 8));
|
||
CalibrationData._P4 = (_wire->read() | (_wire->read() << 8));
|
||
CalibrationData._P5 = (_wire->read() | (_wire->read() << 8));
|
||
CalibrationData._P6 = (_wire->read() | (_wire->read() << 8));
|
||
CalibrationData._P7 = (_wire->read() | (_wire->read() << 8));
|
||
CalibrationData._P8 = (_wire->read() | (_wire->read() << 8));
|
||
CalibrationData._P9 = (_wire->read() | (_wire->read() << 8));
|
||
CalibrationData._H1 = _wire->read();
|
||
|
||
/* second part request*/
|
||
_wire->beginTransmission(_i2c_address);
|
||
_wire->write(0xE1);
|
||
_wire->endTransmission();
|
||
_wire->requestFrom(_i2c_address , 8);
|
||
/* reading */
|
||
CalibrationData._H2 = (_wire->read() | (_wire->read() << 8));
|
||
CalibrationData._H3 = _wire->read();
|
||
CalibrationData._H4 = (_wire->read() << 4);
|
||
uint8_t interVal = _wire->read();
|
||
CalibrationData._H4 |= (interVal & 0xF);
|
||
CalibrationData._H5 = (((interVal & 0xF0) >> 4) | (_wire->read() << 4));
|
||
CalibrationData._H6 = _wire->read();
|
||
} |