Files
attinycore-makefile-tests/861-tinycore-bcm280-test/libraries/MyBME280/MyBME280.cpp
Thomas von Dein 9a428b72ec more tests
2020-02-25 21:21:49 +01:00

626 lines
17 KiB
C++

//MyBME280.cpp
//Code fuer Arduino und Attiny85
//Author Retian
//Version 2.1
/*
Abfrage eines Luftdruck-/Luftfeuchtesensors BME280 ueber I2C- oder SPI-Schnittstelle
(SPI-Schnittstelle nicht fuer Attiny)
MyBME280 Name(i2cAdd); //fuer I2C-Schnittstelle
MyBME280 Name(cs, interface); //fuer SPI-Schnittstelle; interface: BME280_SPI
Beispiel siehe unter:
http://arduino-projekte.webnode.at/meine-libraries/luftdruck-luftfeuchtesensor-bme280/
Funktionen siehe unter:
http://arduino-projekte.webnode.at/meine-libraries/luftdruck-luftfeuchtesensor-bme280/funktionen/
*/
//*************************************************************************
#include "Arduino.h"
#include "MyBME280.h"
MyBME280::MyBME280(byte i2cAdd) : _cs(-1)
{
_i2cAdd = i2cAdd;
Wire.begin();
setDefaultParameters();
}
MyBME280::MyBME280(byte cs, byte interface)
{
#if defined_ATtiny
//Keine Aktivitaet, wenn ein Attiny eingesetzt wird
#else
//"interface" wird nicht benoetigt, ist nur zur Unterscheidung
//beim Aufruf der Instanzen zwischen SPI- und I2C-Schnittstelle
_cs = cs;
pinMode(_cs, OUTPUT);
SPI.begin();
setDefaultParameters();
#endif
}
//*************************************************************************
//Setzen der Standard-Parameter
//(Interne Verwendung)
void MyBME280::setDefaultParameters()
{
controlVal = 0;
configVal = 0;
controlHumVal = 0;
//Setzen der Voreinstellungen
mode = BME280_NORMAL_MODE;
setMode(mode);
osrs_p = BME280_P_OVERSAMPLING_x8; //Pressure oversampling x8
setPressOversampling(osrs_p);
osrs_t = BME280_T_OVERSAMPLING_x2; //Temperature oversampling x2
setTempOversampling(osrs_t);
osrs_h = BME280_H_OVERSAMPLING_x8; //Humidity oversampling x8
setHumidityOversampling(osrs_h);
t_sb = BME280_STANDBY_TIME_1000; //Standby time (NORMAL_MODE) = 1000 ms
setStandbyTime(t_sb);
filter = BME280_FILTER_COEFF_4; //Filter-Koeffizient = 4 (5 Stufen fuer 75%)
setFilterCoeff(filter);
}
//*************************************************************************
//BME280 vorhanden ?
bool MyBME280::isReady()
{
if (read8(BMP280_CHIP_ID_REG) == BMP280_CHIP_ID) return true;
else return false;
}
//*************************************************************************
//BME280 initialisiern
void MyBME280::init()
{
//BME280 zuruecksetzen
reset();
delay(300);
//Kalibrierungskoeffizienten einlesen
//Wenn der BME280 gerade die Koeffizienten ins interne
//Image-Register liest, dann warte
while (read8(BME280_STATUS_REG) & 0x01) delay(1);
dig_T1 = (unsigned int)read16(BME280_DIG_T1_REG);
dig_T2 = read16(BME280_DIG_T2_REG);
dig_T3 = read16(BME280_DIG_T3_REG);
dig_P1 = (unsigned int)read16(BME280_DIG_P1_REG);
dig_P2 = read16(BME280_DIG_P2_REG);
dig_P3 = read16(BME280_DIG_P3_REG);
dig_P4 = read16(BME280_DIG_P4_REG);
dig_P5 = read16(BME280_DIG_P5_REG);
dig_P6 = read16(BME280_DIG_P6_REG);
dig_P7 = read16(BME280_DIG_P7_REG);
dig_P8 = read16(BME280_DIG_P8_REG);
dig_P9 = read16(BME280_DIG_P9_REG);
dig_H1 = (uint8_t)read8(BME280_DIG_H1_REG);
dig_H2 = read16(BME280_DIG_H2_REG);
dig_H3 = (uint8_t)read8(BME280_DIG_H3_REG);
dig_H4 = (read8(BME280_DIG_H4_REG) << 4) |
(read8(BME280_DIG_H4_REG + 1) & 0xF);
dig_H5 = (read8(BME280_DIG_H5_REG + 1) << 4) |
(read8(BME280_DIG_H5_REG) >> 4);
dig_H6 = (uint8_t)read8(BME280_DIG_H6_REG);
//Schreiben der gesetzten Parameter in die Register
//Aenderungen beim Humidity-Controll-Register werden erst nach einer
//Schreiboperation auf das Control-Register wirksam (lt. Datenblatt 5.4.3)
write8(BME280_CONFIG_REG, configVal);
write8(BME280_HUM_CONTROL_REG, controlHumVal);
write8(BME280_CONTROL_REG, controlVal);
}
//*************************************************************************
//Starte Einzelmessung (FORCED_MODE)
void MyBME280::startSingleMeas()
{
controlVal &= B11111100;
controlVal |= BME280_FORCED_MODE;
write8(BME280_CONTROL_REG, controlVal);
while (statusMeas()); //Warte bis Messzyklus beendet
}
//*************************************************************************
//Ermittlung der Lufttemperatur
float MyBME280::readTemp()
{
readRawData();
if (adc_T == 0x80000) //Rueckgabe, wenn Temperaturmesseung ausgeschaltet ist
return NAN;
return calcTemp();
}
//*************************************************************************
//Ermittlung des Luftdrucks
float MyBME280::readPress()
{
readRawData();
if (adc_P == 0x80000) //Rueckgabe, wenn Luftdruckmessung ausgeschaltet ist
return NAN;
calcTemp(); //calcPress() benoetigt t_fine aus calcTemp()
return calcPress();
}
//*************************************************************************
//Ermittlung der Luftfeuchtigkeit
float MyBME280::readHumidity()
{
readRawData();
if (adc_H == 0x8000) //Rueckgabe, wenn Luftfeuchtemessung ausgeschaltet ist
return NAN;
calcTemp(); //calcHumidity() benoetigt t_fine aus calcTemp()
return calcHumidity();
}
//*************************************************************************
//Reduzierten Luftdruck bezogen auf Meereshoehe ermitteln
float MyBME280::readReducedPress(int hoehe)
{
//Berechne reduzierten Luftdruck
int _hoehe = hoehe;
readRawData();
if (adc_P == 0x80000) //Rueckgabe, wenn Luftdruckmessung ausgeschaltet ist
return NAN;
calcTemp();
return (calcPress() / (pow(1.0 - ((float)_hoehe / 44330.0), 5.255)));
}
//*************************************************************************
//Einlesen von 8 Bytes (burst read) ueber die I2C-Schnittstelle
//(Interne Verwendung)
void MyBME280::readRawData()
{
while (statusMeas()); //Warte bis Messzyklus beendet
if (_cs == -1)
{
Wire.beginTransmission(_i2cAdd);
Wire.write(BME280_DATA_REG);
Wire.endTransmission();
Wire.requestFrom(_i2cAdd, (byte)8);
adc_P = Wire.read();
adc_P <<= 8;
adc_P |= Wire.read();
adc_P <<= 8;
adc_P |= Wire.read();
adc_P >>= 4;
adc_T = Wire.read();
adc_T <<= 8;
adc_T |= Wire.read();
adc_T <<= 8;
adc_T |= Wire.read();
adc_T >>= 4;
adc_H = Wire.read();
adc_H <<= 8;
adc_H |= Wire.read();
}
else
{
#if defined_ATtiny
//Keine Aktivitaet, wenn ein Attiny eingesetzt wird
#else
SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE0));
digitalWrite(_cs, LOW);
SPI.transfer(BME280_DATA_REG | 0x80);
adc_P = SPI.transfer(0);
adc_P <<= 8;
adc_P |= SPI.transfer(0);
adc_P <<= 8;
adc_P |= SPI.transfer(0);
adc_P >>= 4;
adc_T = SPI.transfer(0);
adc_T <<= 8;
adc_T |= SPI.transfer(0);
adc_T <<= 8;
adc_T |= SPI.transfer(0);
adc_T >>= 4;
adc_H = SPI.transfer(0);
adc_H <<= 8;
adc_H |= SPI.transfer(0);
digitalWrite(_cs, HIGH);
SPI.endTransaction();
#endif
}
}
//*************************************************************************
//Temperatur ermitteln
//(Interne Verwendung)
float MyBME280::calcTemp()
{
int32_t var1, var2;
int32_t temp;
//Berechne Temperatur
var1 = (((adc_T >> 3) - (dig_T1 << 1)) * dig_T2) >> 11;
var2 = (((((adc_T >> 4) - (dig_T1)) * ((adc_T >> 4) - dig_T1)) >> 12) * dig_T3) >> 14;
t_fine = var1 + var2;
temp = (t_fine * 5 + 128) >> 8;
return (float)temp / 100.0;
}
//*************************************************************************
//Luftdruck ermitteln
//(Interne Verwendung)
float MyBME280::calcPress()
{
int64_t var1, var2;
int64_t press;
//Berechne Luftdruck
var1 = ((int64_t)t_fine) - 128000;
var2 = var1 * var1 * (int64_t)dig_P6;
var2 = var2 + ((var1 * (int64_t)dig_P5) << 17);
var2 = var2 + (((int64_t)dig_P4) << 35);
var1 = ((var1 * var1 + (int64_t)dig_P3) >> 8) + ((var1 * (int64_t)dig_P2) << 12);
var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)dig_P1) >> 33;
if (var1 == 0) return 0;
press= 1048576 - adc_P;
press= (((press << 31) - var2) * 3125) / var1;
var1 = (((int64_t)dig_P9) * (press>> 13) * (press>> 13)) >> 25;
var2 = (((int64_t)dig_P8) * press) >> 19;
press = ((press + var1 + var2) >> 8) + (((int64_t)dig_P7) << 4);
press /= 256;
return (float) press / 100.0;
}
//*************************************************************************
//Luftfeuchte ermitteln
//(Interne Verwendung)
float MyBME280::calcHumidity()
{
int32_t v_x1_u32r;
uint32_t humidity;
//Berechne Luftfeuchtigkeit
v_x1_u32r = (t_fine - ((int32_t)76800));
v_x1_u32r = (((((adc_H << 14) - (((int32_t)dig_H4) << 20) - (((int32_t)dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) * (((((((v_x1_u32r * ((int32_t)dig_H6)) >> 10) * (((v_x1_u32r * ((int32_t)dig_H3)) >> 11) + ((int32_t)32768))) >> 10) +
((int32_t)2097152)) * ((int32_t)dig_H2) + 8192) >> 14));
v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) *
((int32_t)dig_H1)) >> 4));
v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
humidity = (uint32_t)(v_x1_u32r >> 12);
return (float)humidity / 1024.0;
}
//*************************************************************************
// Schreiben von 1 Byte ueber die I2C-Schnittstelle
//(Interne Verwendung)
void MyBME280::write8(byte add, byte val)
{
byte _add = add;
byte _val = val;
if (_cs == -1)
{
Wire.beginTransmission(_i2cAdd);
Wire.write(_add);
Wire.write(_val);
Wire.endTransmission();
}
else
{
#if defined_ATtiny
//Keine Aktivitaet, wenn ein Attiny eingesetzt wird
#else
digitalWrite(_cs, LOW);
SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE0));
SPI.transfer(_add & 0x7F);
SPI.transfer(val);
SPI.endTransaction();
digitalWrite(_cs, HIGH);
#endif
}
delay(5);
}
//*************************************************************************
// Einlesen von 1 Byte ueber die I2C-Schnittstelle
//(Interne Verwendung)
byte MyBME280::read8(byte adr)
{
byte _adr = adr;
byte val;
if (_cs == -1)
{
Wire.beginTransmission(_i2cAdd);
Wire.write(_adr);
Wire.endTransmission();
Wire.requestFrom(_i2cAdd, (byte)1);
val = Wire.read();
}
else
{
#if defined_ATtiny
//Keine Aktivitaet, wenn ein Attiny eingesetzt wird
#else
SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE0));
digitalWrite(_cs, LOW);
SPI.transfer(_adr | 0x80);
val = SPI.transfer(0);
digitalWrite(_cs, HIGH);
SPI.endTransaction();
#endif
}
return val;
}
//*************************************************************************
// Einlesen von 2 Bytes ueber die I2C-Schnittstelle
//(Interne Verwendung)
int MyBME280::read16(byte adr)
{
byte _adr = adr;
int val;
if (_cs == -1)
{
Wire.beginTransmission(_i2cAdd);
Wire.write(_adr);
Wire.endTransmission();
Wire.requestFrom(_i2cAdd, (byte)2);
val = Wire.read() | (Wire.read() << 8);
}
else
{
#if defined_ATtiny
//Keine Aktivitaet, wenn ein Attiny eingesetzt wird
#else
SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE0));
digitalWrite(_cs, LOW);
SPI.transfer(_adr | 0x80);
val = SPI.transfer(0) | (SPI.transfer(0) << 8);
digitalWrite(_cs, HIGH);
SPI.endTransaction();
#endif
}
return val;
}
//*************************************************************************
//Setzen des Modus
void MyBME280::setMode(byte mode)
{
byte _mode = mode;
controlVal &= B11111100; //Loesche mode
controlVal |= _mode;
}
//*************************************************************************
//Setzen Temperatur-Oversampling
void MyBME280::setTempOversampling(byte osrs_t)
{
byte _osrs_t = osrs_t;
controlVal &= ~(B111 << 5); //Loesche Temp.oversampling
controlVal |= (_osrs_t << 5);
}
//*************************************************************************
//Setzen Druck-Oversampling
void MyBME280::setPressOversampling(byte osrs_p)
{
byte _osrs_p = osrs_p;
controlVal &= ~(B111 << 2); //Loesche Press.oversampling
controlVal |= (_osrs_p << 2);
}
//*************************************************************************
//Setzen Feuchte-Oversampling
void MyBME280::setHumidityOversampling(byte osrs_h)
{
byte _osrs_h = osrs_h;
controlHumVal &= ~(B111); //Loesche Humid.oversampling
controlHumVal |= _osrs_h;
}
//*************************************************************************
//Setzen der Standby-Zeit (Normal-Modus)
void MyBME280::setStandbyTime(byte t_sb)
{
byte _t_sb = t_sb;
configVal &= ~(B111 << 5); //Loesche Standby Time
configVal |= (_t_sb << 5);
}
//*************************************************************************
//Setzen des Filterkoeffizienten
void MyBME280::setFilterCoeff(byte filter)
{
byte _filter = filter;
configVal &= ~(B111 << 2); //Loesche Filter
configVal |= (_filter << 2);
}
//*************************************************************************
//Abfrage des Controll-Register 0xF4
byte MyBME280::readControlReg(void)
{
return read8(BME280_CONTROL_REG);
}
//*************************************************************************
//Abfrage des Config-Register 0xF5
byte MyBME280::readConfigReg(void)
{
return read8(BME280_CONFIG_REG);
}
//*************************************************************************
//Abfrage des Humidity-Control-Register 0xF2
byte MyBME280::readHumidityControlReg(void)
{
return read8(BME280_HUM_CONTROL_REG);
}
//*************************************************************************
//Abfrage des Status des Measuring-Bit
//(Interne Verwendung)
bool MyBME280::statusMeas()
{
byte reg;
reg = read8(BME280_STATUS_REG);
return (reg & B00001000) >> 3;
}
//*************************************************************************
//Software-Reset
//(Interne Verwendung)
void MyBME280::reset()
{
write8(BME280_RESET_REG, BME280_RESET);
}
//*************************************************************************
//Voreinstellung fuer Weather Monitoring
void MyBME280::setWeatherMonitoring()
{
mode = BME280_FORCED_MODE;
setMode(mode);
osrs_p = BME280_P_OVERSAMPLING_x1; //Pressure oversampling x1
setPressOversampling(osrs_p);
osrs_t = BME280_T_OVERSAMPLING_x1; //Temperature oversampling x1
setTempOversampling(osrs_t);
osrs_h = BME280_H_OVERSAMPLING_x1; //Humidity oversampling x1
setHumidityOversampling(osrs_h);
/*Keine Bedeutung bei WeatherMonitoring (Forced Mode)
t_sb = BME280_STANDBY_TIME_62p5;
setStandbyTime(t_sb);
*/
filter = BME280_FILTER_COEFF_0; //Filter aus
setFilterCoeff(filter);
}
//*************************************************************************
//Voreinstellung fuer Humidity Sensing (Luftfeuchtemessung)
void MyBME280::setHumiditySensing()
{
mode = BME280_FORCED_MODE;
setMode(mode);
osrs_p = BME280_P_OVERSAMPLING_x0; //Pressure oversampling x0
setPressOversampling(osrs_p);
osrs_t = BME280_T_OVERSAMPLING_x1; //Temperature oversampling x1
setTempOversampling(osrs_t);
osrs_h = BME280_H_OVERSAMPLING_x1; //Humidity oversampling x1
setHumidityOversampling(osrs_h);
/*Keine Bedeutung bei Humidity Sensing (Forced Mode)
t_sb = BME280_STANDBY_TIME_62p5;
setStandbyTime(t_sb);
*/
filter = BME280_FILTER_COEFF_0; //Filter aus
setFilterCoeff(filter);
}
//*************************************************************************
//Voreinstellung fuer Indoor Navigation
void MyBME280::setIndoorNavigation()
{
mode = BME280_NORMAL_MODE;
setMode(mode);
osrs_p = BME280_P_OVERSAMPLING_x16; //Pressure oversampling x16
setPressOversampling(osrs_p);
osrs_t = BME280_T_OVERSAMPLING_x2; //Temperature oversampling x2
setTempOversampling(osrs_t);
osrs_h = BME280_H_OVERSAMPLING_x1; //Humidity oversampling x1
setHumidityOversampling(osrs_h);
t_sb = BME280_STANDBY_TIME_0p5; //Standby Time 0,5 ms
setStandbyTime(t_sb);
filter = BME280_FILTER_COEFF_16; //Filter-Koeffizient = 16 (22 Stufen fuer 75%)
setFilterCoeff(filter);
}
//*************************************************************************
//Voreinstellung fuer Gaming
void MyBME280::setGaming()
{
mode = BME280_NORMAL_MODE;
setMode(mode);
osrs_p = BME280_P_OVERSAMPLING_x4; //Pressure oversampling x4
setPressOversampling(osrs_p);
osrs_t = BME280_T_OVERSAMPLING_x1; //Temperature oversampling x1
setTempOversampling(osrs_t);
osrs_h = BME280_H_OVERSAMPLING_x0; //Humidity oversampling x0
setHumidityOversampling(osrs_h);
t_sb = BME280_STANDBY_TIME_0p5; //Standby Time 0,5 ms
setStandbyTime(t_sb);
filter = BME280_FILTER_COEFF_16; //Filter-Koeffizient = 16 (22 Stufen fuer 75%)
setFilterCoeff(filter);
}