7typedef TinyWire TwoWire;
13#include "helper/mup_i2c_registers.h"
112 String BMP280_VERSION =
"0.1.0";
118 double temperatureValue, pressureValue, pressureNNValue;
119 unsigned long stateMachineClock;
120 int32_t rawTemperature;
121 double calibratedTemperature;
123 double calibratedPressure;
124 double baseRelativeNNPressure;
125 bool relativeAltitudeStarted;
126 bool captureRelative =
false;
129 int16_t dig_T2, dig_T3, dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9;
130 uint16_t dig_T1, dig_P1, dig_reserved;
133 enum BMPSensorState { UNAVAILABLE,
136 WAIT_NEXT_MEASUREMENT };
146 BMPSensorState sensorState;
147 unsigned long errs = 0;
148 unsigned long oks = 0;
149 unsigned long basePollRate = 500000L;
150 uint32_t pollRateMs = 2000;
151 uint32_t lastPollMs = 0;
152 uint16_t oversampleMode = 3;
153 uint16_t oversampleModePressure = 3;
154 uint16_t oversampleModeTemperature = 1;
155 enum FilterMode { FAST,
158#define MUP_BMP_INVALID_ALTITUDE -1000000.0
159 double referenceAltitudeMeters;
160 FilterMode filterMode;
162 ustd::sensorprocessor temperatureSensor = ustd::sensorprocessor(4, 600, 0.005);
163 ustd::sensorprocessor pressureSensor = ustd::sensorprocessor(4, 600, 0.005);
164 bool bActive =
false;
166 PressTempBMP280(String name, FilterMode filterMode = FilterMode::MEDIUM, uint8_t i2cAddress = 0x76)
167 : name(name), filterMode(filterMode), i2cAddress(i2cAddress) {
173 sensorState = BMPSensorState::UNAVAILABLE;
174 referenceAltitudeMeters = MUP_BMP_INVALID_ALTITUDE;
175 relativeAltitudeStarted =
false;
176 captureRelative =
false;
178 setFilterMode(filterMode,
true);
191 referenceAltitudeMeters = _referenceAltitudeMeters;
200 if (referenceAltitudeMeters != MUP_BMP_INVALID_ALTITUDE) {
201 captureRelative =
true;
209 return temperatureValue;
216 return pressureValue;
227 if (referenceAltitudeMeters != MUP_BMP_INVALID_ALTITUDE) {
228 double prNN = _pressure / pow((1.0 - (referenceAltitudeMeters / 44330.0)), 5.255);
235 oversampleMode = (uint16_t)_sampleMode;
236 oversampleModePressure = oversampleMode;
238 oversampleModeTemperature = 2;
240 oversampleModeTemperature = 1;
244 bool initBmpSensorConstants() {
247 if (!pI2C->readRegisterWordLE(0x88, (uint16_t *)&dig_T1))
return false;
248 if (!pI2C->readRegisterWordLE(0x8A, (uint16_t *)&dig_T2))
return false;
249 if (!pI2C->readRegisterWordLE(0x8C, (uint16_t *)&dig_T3))
return false;
250 if (!pI2C->readRegisterWordLE(0x8E, (uint16_t *)&dig_P1))
return false;
251 if (!pI2C->readRegisterWordLE(0x90, (uint16_t *)&dig_P2))
return false;
252 if (!pI2C->readRegisterWordLE(0x92, (uint16_t *)&dig_P3))
return false;
253 if (!pI2C->readRegisterWordLE(0x94, (uint16_t *)&dig_P4))
return false;
254 if (!pI2C->readRegisterWordLE(0x96, (uint16_t *)&dig_P5))
return false;
255 if (!pI2C->readRegisterWordLE(0x98, (uint16_t *)&dig_P6))
return false;
256 if (!pI2C->readRegisterWordLE(0x9A, (uint16_t *)&dig_P7))
return false;
257 if (!pI2C->readRegisterWordLE(0x9C, (uint16_t *)&dig_P8))
return false;
258 if (!pI2C->readRegisterWordLE(0x9E, (uint16_t *)&dig_P9))
return false;
260 dig_reserved = 0xffff;
269 pollRateMs = _pollRateMs;
270 pI2C =
new I2CRegisters(pWire, i2cAddress);
271 setSampleMode(_sampleMode);
273 auto ft = [=]() { this->loop(); };
274 tID = pSched->add(ft, name, basePollRate);
276 auto fnall = [=](String topic, String msg, String originator) {
277 this->subsMsg(topic, msg, originator);
279 pSched->subscribe(tID, name +
"/sensor/#", fnall);
281 pI2C->lastError = pI2C->checkAddress(i2cAddress);
282 if (pI2C->lastError == I2CRegisters::I2CError::OK) {
283 if (!pI2C->readRegisterByte(0xd0, &data)) {
285 Serial.print(
"Failed to inquire BMP280 chip-id at address 0x");
286 Serial.println(i2cAddress, HEX);
291 if (!initBmpSensorConstants()) {
293 Serial.print(
"Failed to read calibration data for sensor BMP280 at address 0x");
294 Serial.println(i2cAddress, HEX);
296 pI2C->lastError = I2CRegisters::I2CError::I2C_HW_ERROR;
300 Serial.print(
"BMP280 sensor active at address 0x");
301 Serial.println(i2cAddress, HEX);
303 sensorState = BMPSensorState::IDLE;
308 Serial.print(
"Wrong hardware (not BMP280) found at address 0x");
309 Serial.print(i2cAddress, HEX);
310 Serial.print(
" chip-id is ");
311 Serial.print(data, HEX);
312 Serial.println(
" expected: 0x58 for BMP280.");
314 pI2C->lastError = I2CRegisters::I2CError::I2C_WRONG_HARDWARE_AT_ADDRESS;
320 Serial.print(
"No BMP280 sensor found at address 0x");
321 Serial.println(i2cAddress, HEX);
327 void setFilterMode(FilterMode mode,
bool silent =
false) {
331 temperatureSensor.update(1, 2, 0.05);
332 pressureSensor.update(1, 2, 0.1);
336 temperatureSensor.update(4, 30, 0.1);
337 pressureSensor.update(4, 30, 0.5);
341 filterMode = LONGTERM;
342 temperatureSensor.update(10, 600, 0.1);
343 pressureSensor.update(50, 600, 0.5);
351 void publishTemperature() {
353 sprintf(buf,
"%6.2f", temperatureValue);
354 pSched->publish(name +
"/sensor/temperature", buf);
357 void publishPressure() {
359 sprintf(buf,
"%7.2f", pressureValue);
360 pSched->publish(name +
"/sensor/pressure", buf);
361 if (referenceAltitudeMeters != MUP_BMP_INVALID_ALTITUDE) {
362 sprintf(buf,
"%7.2f", pressureNNValue);
363 pSched->publish(name +
"/sensor/pressureNN", buf);
367 void publishError(String errMsg) {
368 pSched->publish(name +
"/sensor/error", errMsg);
371 void publishFilterMode() {
372 switch (filterMode) {
373 case FilterMode::FAST:
374 pSched->publish(name +
"/sensor/mode",
"FAST");
376 case FilterMode::MEDIUM:
377 pSched->publish(name +
"/sensor/mode",
"MEDIUM");
379 case FilterMode::LONGTERM:
380 pSched->publish(name +
"/sensor/mode",
"LONGTERM");
385 void publishOversampling() {
388 pSched->publish(name +
"/sensor/oversampling",
"ULTRA_LOW_POWER");
391 pSched->publish(name +
"/sensor/oversampling",
"LOW_POWER");
394 pSched->publish(name +
"/sensor/oversampling",
"STANDARD");
397 pSched->publish(name +
"/sensor/oversampling",
"HIGH_RESOLUTION");
400 pSched->publish(name +
"/sensor/oversampling",
"ULTRA_HIGH_RESOLUTION");
403 pSched->publish(name +
"/sensor/oversampling",
"INVALID");
408 void publishCalibrationData() {
410 sprintf(msg,
"dig_T1=%u, dig_T2=%d, dig_T3=%d, dig_P1=%u, dig_P2=%d, dig_P3=%d, dig_P4=%d, dig_P5=%d, dig_P6=%d, dig_P7=%d, dig_P8=%d, dig_P9=%d, dig_reserved=%u",
411 dig_T1, dig_T2, dig_T3, dig_P1, dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9, dig_reserved);
412 pSched->publish(
"sensor/calibrationdata", msg);
415 void publishReferenceAltitude() {
416 if (referenceAltitudeMeters != MUP_BMP_INVALID_ALTITUDE) {
418 sprintf(buf,
"%7.2f", referenceAltitudeMeters);
419 pSched->publish(name +
"/sensor/referencealtitude", buf);
421 pSched->publish(name +
"/sensor/referencealtitude",
"unknown");
425 void publishRelativeAltitude() {
427 if (relativeAltitudeStarted) {
428 double ralt = 44330.0 * (1.0 - pow(pressureValue / baseRelativeNNPressure, 1. / 5.255));
429 sprintf(buf,
"%7.2f", ralt);
430 pSched->publish(name +
"/sensor/relativealtitude", buf);
431 double dalt = ralt - referenceAltitudeMeters;
432 sprintf(buf,
"%7.2f", dalt);
433 pSched->publish(name +
"/sensor/deltaaltitude", buf);
437 bool sensorStateMachine() {
438 bool newData =
false;
442 const uint8_t status_register = 0xf3;
443 const uint8_t measure_mode_register = 0xf4;
444 const uint8_t config_register = 0xf5;
445 const uint8_t temperature_registers = 0xfa;
446 const uint8_t pressure_registers = 0xf7;
448 uint8_t normalmodeInactivity = 0, IIRfilter = 0;
449 switch (sensorState) {
450 case BMPSensorState::UNAVAILABLE:
452 case BMPSensorState::IDLE:
453 reg_data = (normalmodeInactivity << 5) + (IIRfilter << 2) + 0;
454 if (!pI2C->writeRegisterByte(config_register, reg_data)) {
456 sensorState = BMPSensorState::WAIT_NEXT_MEASUREMENT;
457 stateMachineClock = micros();
460 reg_data = (oversampleModeTemperature << 5) + (oversampleModePressure << 2) + 0x1;
461 if (!pI2C->writeRegisterByte(measure_mode_register, reg_data)) {
463 sensorState = BMPSensorState::WAIT_NEXT_MEASUREMENT;
464 stateMachineClock = micros();
467 sensorState = BMPSensorState::MEASUREMENT_WAIT;
468 stateMachineClock = micros();
471 case BMPSensorState::MEASUREMENT_WAIT:
472 if (!pI2C->readRegisterByte(status_register, &status)) {
475 sensorState = BMPSensorState::WAIT_NEXT_MEASUREMENT;
476 stateMachineClock = micros();
479 status = status & 0x09;
480 if (timeDiff(stateMachineClock, micros()) > 1 && status == 0) {
483 if (pI2C->readRegisterTripple(temperature_registers, &rt) && pI2C->readRegisterTripple(pressure_registers, &rp)) {
484 rawTemperature = rt >> 4;
485 rawPressure = rp >> 4;
486 sensorState = BMPSensorState::WAIT_NEXT_MEASUREMENT;
487 stateMachineClock = micros();
492 sensorState = BMPSensorState::WAIT_NEXT_MEASUREMENT;
493 stateMachineClock = micros();
497 case BMPSensorState::WAIT_NEXT_MEASUREMENT:
498 if (timeDiff(lastPollMs, millis()) > pollRateMs) {
499 sensorState = BMPSensorState::IDLE;
500 lastPollMs = millis();
511 double bmp280_compensate_T_double(int32_t adc_T, int32_t *pt_fine) {
512 double var1, var2, T;
513 var1 = (((double)adc_T) / 16384.0 - ((double)dig_T1) / 1024.0) * ((
double)dig_T2);
514 var2 = ((((double)adc_T) / 131072.0 - ((double)dig_T1) / 8192.0) *
515 (((
double)adc_T) / 131072.0 - ((
double)dig_T1) / 8192.0)) *
517 *pt_fine = (int32_t)(var1 + var2);
518 T = (var1 + var2) / 5120.0;
524 double bmp280_compensate_P_double(int32_t adc_P, int32_t t_fine) {
525 double var1, var2, p;
526 var1 = ((double)t_fine / 2.0) - 64000.0;
527 var2 = var1 * var1 * ((double)dig_P6) / 32768.0;
528 var2 = var2 + var1 * ((double)dig_P5) * 2.0;
529 var2 = (var2 / 4.0) + (((
double)dig_P4) * 65536.0);
530 var1 = (((double)dig_P3) * var1 * var1 / 524288.0 + ((double)dig_P2) * var1) / 524288.0;
531 var1 = (1.0 + var1 / 32768.0) * ((
double)dig_P1);
535 p = 1048576.0 - (double)adc_P;
536 p = (p - (var2 / 4096.0)) * 6250.0 / var1;
537 var1 = ((double)dig_P9) * p * p / 2147483648.0;
538 var2 = p * ((double)dig_P8) / 32768.0;
539 p = p + (var1 + var2 + ((double)dig_P7)) / 16.0;
543 bool calibrateRawData() {
546 calibratedTemperature = bmp280_compensate_T_double(rawTemperature, &t_fine);
548 calibratedPressure = bmp280_compensate_P_double(rawPressure, t_fine) / 100.0;
553 double tempVal, pressVal;
555 if (!sensorStateMachine())
return;
557 tempVal = (double)calibratedTemperature;
558 pressVal = (double)calibratedPressure;
559 if (temperatureSensor.filter(&tempVal)) {
560 temperatureValue = tempVal;
561 publishTemperature();
563 if (pressureSensor.filter(&pressVal)) {
564 pressureValue = pressVal;
565 if (referenceAltitudeMeters != MUP_BMP_INVALID_ALTITUDE) {
567 if (captureRelative) {
568 baseRelativeNNPressure = pressureNNValue;
569 relativeAltitudeStarted =
true;
570 captureRelative =
false;
574 if (relativeAltitudeStarted) publishRelativeAltitude();
579 void subsMsg(String topic, String msg, String originator) {
580 if (topic == name +
"/sensor/temperature/get") {
581 publishTemperature();
582 }
else if (topic == name +
"/sensor/pressure/get") {
584 }
else if (topic == name +
"/sensor/mode/get") {
586 }
else if (topic == name +
"/sensor/calibrationdata/get") {
587 publishCalibrationData();
588 }
else if (topic == name +
"/sensor/referencealtitude/get") {
589 publishReferenceAltitude();
590 }
else if (topic == name +
"/sensor/relativealtitude/get") {
591 publishRelativeAltitude();
592 }
else if (topic == name +
"/sensor/relativealtitude/set") {
594 }
else if (topic == name +
"/sensor/oversampling/get") {
595 publishOversampling();
596 }
else if (topic == name +
"/sensor/referencealtitude/set") {
597 double alt = atof(msg.c_str());
599 }
else if (topic == name +
"/sensor/mode/set") {
600 if (msg ==
"fast" || msg ==
"FAST") {
601 setFilterMode(FilterMode::FAST);
603 if (msg ==
"medium" || msg ==
"MEDIUM") {
604 setFilterMode(FilterMode::MEDIUM);
606 setFilterMode(FilterMode::LONGTERM);
609 }
else if (topic == name +
"/sensor/oversampling/set") {
610 if (msg ==
"ULTRA_LOW_POWER") {
613 if (msg ==
"LOW_POWER") {
616 if (msg ==
"STANDARD") {
619 if (msg ==
"HIGH_RESOLUTION") {
mupplet-sensor temperature and pressure with Bosch BMP280
Definition: mup_presstemp_bmp280.h:110
double getTemperature()
Definition: mup_presstemp_bmp280.h:205
BMPSampleMode
Definition: mup_presstemp_bmp280.h:139
@ HIGH_RESOLUTION
8 samples, pressure resolution 19bit / 0.33 Pa, rec temperature oversampling: x1
Definition: mup_presstemp_bmp280.h:143
@ ULTRA_HIGH_RESOLUTION
16 samples, pressure resolution 20bit / 0.16 Pa, rec temperature oversampling: x2
Definition: mup_presstemp_bmp280.h:144
@ ULTRA_LOW_POWER
1 samples, pressure resolution 16bit / 2.62 Pa, rec temperature oversampling: x1
Definition: mup_presstemp_bmp280.h:140
@ LOW_POWER
2 samples, pressure resolution 17bit / 1.31 Pa, rec temperature oversampling: x1
Definition: mup_presstemp_bmp280.h:141
@ STANDARD
4 samples, pressure resolution 18bit / 0.66 Pa, rec temperature oversampling: x1
Definition: mup_presstemp_bmp280.h:142
void startRelativeAltitude()
Definition: mup_presstemp_bmp280.h:194
double getPressureNN(double _pressure)
Definition: mup_presstemp_bmp280.h:219
double getPressure()
Definition: mup_presstemp_bmp280.h:212
PressTempBMP280(String name, FilterMode filterMode=FilterMode::MEDIUM, uint8_t i2cAddress=0x76)
Definition: mup_presstemp_bmp280.h:166
void setReferenceAltitude(double _referenceAltitudeMeters)
Definition: mup_presstemp_bmp280.h:187