muwerk mupplet Sensor Library
muwerk applets; mupplets: functional units that support specific hardware or reusable applications for sensors
Loading...
Searching...
No Matches
mup_presstemp_bmp180.h
1// mup_presstemp_bmp180.h
2#pragma once
3
4#ifndef tiny_twi_h
5#include <Wire.h>
6#else
7typedef TinyWire TwoWire;
8#endif
9
10#include "scheduler.h"
11#include "sensors.h"
12
13#include "helper/mup_i2c_registers.h"
14
15namespace ustd {
16
17// clang-format off
110// clang-format on
112 private:
113 String BMP180_VERSION = "0.1.0";
114 Scheduler *pSched;
115 TwoWire *pWire;
116 I2CRegisters *pI2C;
117 int tID;
118 String name;
119 double temperatureValue, pressureValue, pressureNNValue;
120 unsigned long stateMachineClock;
121 int32_t rawTemperature;
122 double calibratedTemperature;
123 int32_t rawPressure;
124 double calibratedPressure;
125 double baseRelativeNNPressure;
126 bool relativeAltitudeStarted;
127 bool captureRelative = false;
128 unsigned long basePollRateUs = 500000L;
129 uint32_t pollRateMs;
130 uint32_t lastPollMs;
131
132 // BMP Sensor calibration data
133 int16_t CD_AC1, CD_AC2, CD_AC3, CD_B1, CD_B2, CD_MB, CD_MC, CD_MD;
134 uint16_t CD_AC4, CD_AC5, CD_AC6;
135
136 public:
137 enum BMPSensorState { UNAVAILABLE,
138 IDLE,
139 TEMPERATURE_WAIT,
140 PRESSURE_WAIT,
141 WAIT_NEXT_MEASUREMENT };
142
149 };
150 BMPSensorState sensorState;
151 unsigned long errs = 0;
152 unsigned long oks = 0;
153 uint16_t oversampleMode = 2; // 0..3, see BMPSampleMode.
154 enum FilterMode { FAST,
155 MEDIUM,
156 LONGTERM };
157#define MUP_BMP_INVALID_ALTITUDE -1000000.0
158 double referenceAltitudeMeters;
159 FilterMode filterMode;
160 uint8_t i2cAddress;
161 ustd::sensorprocessor temperatureSensor = ustd::sensorprocessor(4, 600, 0.005);
162 ustd::sensorprocessor pressureSensor = ustd::sensorprocessor(4, 600, 0.005);
163 bool bActive = false;
164
165 PressTempBMP180(String name, FilterMode filterMode = FilterMode::MEDIUM, uint8_t i2cAddress = 0x77)
166 : name(name), filterMode(filterMode), i2cAddress(i2cAddress) {
172 sensorState = BMPSensorState::UNAVAILABLE;
173 referenceAltitudeMeters = MUP_BMP_INVALID_ALTITUDE;
174 relativeAltitudeStarted = false;
175 captureRelative = false;
176 pI2C = nullptr;
177 lastPollMs = 0;
178 setFilterMode(filterMode, true);
179 }
180
182 if (pI2C) {
183 delete pI2C;
184 }
185 }
186
187 void setReferenceAltitude(double _referenceAltitudeMeters) {
191 referenceAltitudeMeters = _referenceAltitudeMeters;
192 }
193
200 if (referenceAltitudeMeters != MUP_BMP_INVALID_ALTITUDE) {
201 captureRelative = true;
202 }
203 }
204
205 double getTemperature() {
209 return temperatureValue;
210 }
211
212 double getPressure() {
216 return pressureValue;
217 }
218
219 double getPressureNN(double _pressure) {
227 if (referenceAltitudeMeters != MUP_BMP_INVALID_ALTITUDE) {
228 double prNN = _pressure / pow((1.0 - (referenceAltitudeMeters / 44330.0)), 5.255);
229 return prNN;
230 }
231 return 0.0;
232 }
233
234 void setSampleMode(BMPSampleMode _sampleMode) {
235 oversampleMode = (uint16_t)_sampleMode;
236 }
237
238 bool initBmpSensorConstants() {
239 if (!pI2C->readRegisterWord(0xaa, (uint16_t *)&CD_AC1)) return false;
240 if (!pI2C->readRegisterWord(0xac, (uint16_t *)&CD_AC2)) return false;
241 if (!pI2C->readRegisterWord(0xae, (uint16_t *)&CD_AC3)) return false;
242 if (!pI2C->readRegisterWord(0xb0, (uint16_t *)&CD_AC4)) return false;
243 if (!pI2C->readRegisterWord(0xb2, (uint16_t *)&CD_AC5)) return false;
244 if (!pI2C->readRegisterWord(0xb4, (uint16_t *)&CD_AC6)) return false;
245 if (!pI2C->readRegisterWord(0xb6, (uint16_t *)&CD_B1)) return false;
246 if (!pI2C->readRegisterWord(0xb8, (uint16_t *)&CD_B2)) return false;
247 if (!pI2C->readRegisterWord(0xba, (uint16_t *)&CD_MB)) return false;
248 if (!pI2C->readRegisterWord(0xbc, (uint16_t *)&CD_MC)) return false;
249 if (!pI2C->readRegisterWord(0xbe, (uint16_t *)&CD_MD)) return false;
250 return true;
251 }
252
253 void begin(Scheduler *_pSched, TwoWire *_pWire = &Wire, uint32_t _pollRateMs = 2000, BMPSampleMode _sampleMode = BMPSampleMode::STANDARD) {
254 pSched = _pSched;
255 setSampleMode(_sampleMode);
256 pWire = _pWire;
257 pollRateMs = _pollRateMs;
258 uint8_t data;
259
260 auto ft = [=]() { this->loop(); };
261 tID = pSched->add(ft, name, basePollRateUs); // 500us
262
263 auto fnall = [=](String topic, String msg, String originator) {
264 this->subsMsg(topic, msg, originator);
265 };
266 pSched->subscribe(tID, name + "/sensor/#", fnall);
267
268 pI2C = new I2CRegisters(pWire, i2cAddress);
269
270 pI2C->lastError = pI2C->checkAddress(i2cAddress);
271 if (pI2C->lastError == I2CRegisters::I2CError::OK) {
272 if (!pI2C->readRegisterByte(0xd0, &data)) { // 0xd0: chip-id register
273 bActive = false;
274 } else {
275 if (data == 0x55) { // 0x55: signature of BMP180
276 if (!initBmpSensorConstants()) {
277 pI2C->lastError = I2CRegisters::I2CError::I2C_HW_ERROR;
278 bActive = false;
279 } else {
280 sensorState = BMPSensorState::IDLE;
281 bActive = true;
282 }
283 } else {
284
285 pI2C->lastError = I2CRegisters::I2CError::I2C_WRONG_HARDWARE_AT_ADDRESS;
286 bActive = false;
287 }
288 }
289 } else {
290 bActive = false;
291 }
292 }
293
294 void setFilterMode(FilterMode mode, bool silent = false) {
295 switch (mode) {
296 case FAST:
297 filterMode = FAST;
298 temperatureSensor.update(1, 2, 0.05); // muwerk 0.6.3 API
299 pressureSensor.update(1, 2, 0.1);
300 break;
301 case MEDIUM:
302 filterMode = MEDIUM;
303 temperatureSensor.update(4, 30, 0.1);
304 pressureSensor.update(4, 30, 0.5);
305 break;
306 case LONGTERM:
307 default:
308 filterMode = LONGTERM;
309 temperatureSensor.update(10, 600, 0.1);
310 pressureSensor.update(50, 600, 0.5);
311 break;
312 }
313 if (!silent)
314 publishFilterMode();
315 }
316
317 private:
318 void publishTemperature() {
319 char buf[32];
320 sprintf(buf, "%6.2f", temperatureValue);
321 pSched->publish(name + "/sensor/temperature", buf);
322 }
323
324 void publishPressure() {
325 char buf[32];
326 sprintf(buf, "%7.2f", pressureValue);
327 pSched->publish(name + "/sensor/pressure", buf);
328 if (referenceAltitudeMeters != MUP_BMP_INVALID_ALTITUDE) {
329 sprintf(buf, "%7.2f", pressureNNValue);
330 pSched->publish(name + "/sensor/pressureNN", buf);
331 }
332 }
333
334 void publishError(String errMsg) {
335 pSched->publish(name + "/sensor/error", errMsg);
336 }
337
338 void publishFilterMode() {
339 switch (filterMode) {
340 case FilterMode::FAST:
341 pSched->publish(name + "/sensor/mode", "FAST");
342 break;
343 case FilterMode::MEDIUM:
344 pSched->publish(name + "/sensor/mode", "MEDIUM");
345 break;
346 case FilterMode::LONGTERM:
347 pSched->publish(name + "/sensor/mode", "LONGTERM");
348 break;
349 }
350 }
351
352 void publishOversampling() {
353 switch ((BMPSampleMode)oversampleMode) {
355 pSched->publish(name + "/sensor/oversampling", "ULTRA_LOW_POWER");
356 break;
358 pSched->publish(name + "/sensor/oversampling", "STANDARD");
359 break;
361 pSched->publish(name + "/sensor/oversampling", "HIGH_RESOLUTION");
362 break;
364 pSched->publish(name + "/sensor/oversampling", "ULTRA_HIGH_RESOLUTION");
365 break;
366 default:
367 pSched->publish(name + "/sensor/oversampling", "INVALID");
368 break;
369 }
370 }
371
372 void publishCalibrationData() {
373 char msg[256];
374 sprintf(msg, "AC1=%d, AC2=%d, AC3=%d, AC4=%u, AC5=%u, AC6=%u, B1=%d, B2=%d, MB=%d, MC=%d, MD=%d", CD_AC1, CD_AC2, CD_AC3, CD_AC4, CD_AC5, CD_AC6, CD_B1, CD_B2, CD_MB, CD_MC, CD_MD);
375 pSched->publish("sensor/calibrationdata", msg);
376 }
377
378 void publishReferenceAltitude() {
379 if (referenceAltitudeMeters != MUP_BMP_INVALID_ALTITUDE) {
380 char buf[32];
381 sprintf(buf, "%7.2f", referenceAltitudeMeters);
382 pSched->publish(name + "/sensor/referencealtitude", buf);
383 } else {
384 pSched->publish(name + "/sensor/referencealtitude", "unknown");
385 }
386 }
387
388 void publishRelativeAltitude() {
389 char buf[32];
390 if (relativeAltitudeStarted) {
391 double ralt = 44330.0 * (1.0 - pow(pressureValue / baseRelativeNNPressure, 1. / 5.255));
392 sprintf(buf, "%7.2f", ralt);
393 pSched->publish(name + "/sensor/relativealtitude", buf);
394 double dalt = ralt - referenceAltitudeMeters;
395 sprintf(buf, "%7.2f", dalt);
396 pSched->publish(name + "/sensor/deltaaltitude", buf);
397 }
398 }
399
400 bool sensorStateMachine() {
401 bool newData = false;
402 uint16_t rt;
403 uint32_t rp;
404 unsigned long convTimeOversampling[4] = {4500, 7500, 13500, 25500}; // sample time dependent on oversample-mode for pressure.
405 switch (sensorState) {
406 case BMPSensorState::UNAVAILABLE:
407 break;
408 case BMPSensorState::IDLE:
409 if (!pI2C->writeRegisterByte(0xf4, 0x2e)) {
410 ++errs;
411 sensorState = BMPSensorState::WAIT_NEXT_MEASUREMENT;
412 stateMachineClock = micros();
413 break;
414 } else { // Start temperature read
415 sensorState = BMPSensorState::TEMPERATURE_WAIT;
416 stateMachineClock = micros();
417 }
418 break;
419 case BMPSensorState::TEMPERATURE_WAIT:
420 if (timeDiff(stateMachineClock, micros()) > 4500) { // 4.5ms for temp meas.
421 rt = 0;
422 if (pI2C->readRegisterWord(0xf6, &rt)) {
423 rawTemperature = rt;
424 uint8_t cmd = 0x34 | (oversampleMode << 6);
425 if (!pI2C->writeRegisterByte(0xf4, cmd)) {
426 ++errs;
427 sensorState = BMPSensorState::WAIT_NEXT_MEASUREMENT;
428 stateMachineClock = micros();
429 } else {
430 sensorState = BMPSensorState::PRESSURE_WAIT;
431 stateMachineClock = micros();
432 }
433 } else {
434 ++errs;
435 sensorState = BMPSensorState::WAIT_NEXT_MEASUREMENT;
436 stateMachineClock = micros();
437 }
438 }
439 break;
440 case BMPSensorState::PRESSURE_WAIT:
441 if (timeDiff(stateMachineClock, micros()) > convTimeOversampling[oversampleMode]) { // Oversamp. dep. for press meas.
442 rp = 0;
443 if (pI2C->readRegisterTripple(0xf6, &rp)) {
444 rawPressure = rp >> (8 - oversampleMode);
445 ++oks;
446 newData = true;
447 sensorState = BMPSensorState::WAIT_NEXT_MEASUREMENT;
448 stateMachineClock = micros();
449 } else {
450 ++errs;
451 sensorState = BMPSensorState::WAIT_NEXT_MEASUREMENT;
452 stateMachineClock = micros();
453 }
454 }
455 break;
456 case BMPSensorState::WAIT_NEXT_MEASUREMENT:
457 if (timeDiff(lastPollMs, millis()) > pollRateMs) {
458 sensorState = BMPSensorState::IDLE; // Start next cycle.
459 lastPollMs = millis();
460 }
461 break;
462 }
463 return newData;
464 }
465
466 bool calibrateRawData() {
467 // Temperature
468 int32_t x1 = (((uint32_t)rawTemperature - (uint32_t)CD_AC6) * (uint32_t)CD_AC5) >> 15;
469 int32_t x2 = ((int32_t)CD_MC << 11) / (x1 + (int32_t)CD_MD);
470 int32_t b5 = x1 + x2;
471 calibratedTemperature = ((double)b5 + 8.0) / 160.0;
472 // Pressure
473 int32_t b6 = b5 - (int32_t)4000;
474 x1 = ((int32_t)CD_B2 * ((b6 * b6) >> 12)) >> 11;
475 x2 = ((int32_t)CD_AC2 * b6) >> 11;
476 int32_t x3 = x1 + x2;
477 int32_t b3 = ((((int32_t)CD_AC1 * 4L + x3) << oversampleMode) + 2L) / 4;
478
479 // char msg[128];
480 // sprintf(msg,"x1=%d,x2=%d, x3=%d,b3=%d,rt=%d,rp=%d",x1,x2,x3,b3,rawTemperature,rawPressure);
481 // pSched->publish("myBMP180/sensor/debug1",msg);
482
483 x1 = ((int32_t)CD_AC3 * b6) >> 13;
484 x2 = ((int32_t)CD_B1 * ((b6 * b6) >> 12)) >> 16;
485 x3 = ((x1 + x2) + 2) >> 2;
486 uint32_t b4 = ((uint32_t)CD_AC4 * (uint32_t)(x3 + (uint32_t)32768)) >> 15;
487 uint32_t b7 = ((uint32_t)rawPressure - b3) * ((uint32_t)50000 >> oversampleMode);
488
489 // sprintf(msg,"x1=%d,x2=%d, x3=%d,b4=%u,b7=%u",x1,x2,x3,b4,b7);
490 // pSched->publish("myBMP180/sensor/debug2",msg);
491
492 int32_t p;
493 if (b7 < (uint32_t)0x80000000) {
494 p = (b7 * 2) / b4;
495 } else {
496 p = (b7 / b4) * 2;
497 }
498 x1 = (p >> 8) * (p >> 8);
499 x1 = (x1 * (int32_t)3038) >> 16;
500 x2 = (((int32_t)-7357) * p) >> 16;
501
502 int32_t cp = p + ((x1 + x2 + (int32_t)3791) >> 4);
503
504 // sprintf(msg,"x1=%d,x2=%d,p=%d,cp=%d",x1,x2,p,cp);
505 // pSched->publish("myBMP180/sensor/debug3",msg);
506
507 calibratedPressure = cp / 100.0; // hPa;
508 return true;
509 }
510
511 void loop() {
512 double tempVal, pressVal;
513 if (bActive) {
514 if (!sensorStateMachine()) return; // no new data
515 calibrateRawData();
516 tempVal = (double)calibratedTemperature;
517 pressVal = (double)calibratedPressure;
518 if (temperatureSensor.filter(&tempVal)) {
519 temperatureValue = tempVal;
520 publishTemperature();
521 }
522 if (pressureSensor.filter(&pressVal)) {
523 pressureValue = pressVal;
524 if (referenceAltitudeMeters != MUP_BMP_INVALID_ALTITUDE) {
525 pressureNNValue = getPressureNN(pressureValue);
526 if (captureRelative) {
527 baseRelativeNNPressure = pressureNNValue;
528 relativeAltitudeStarted = true;
529 captureRelative = false;
530 }
531 }
532 publishPressure();
533 if (relativeAltitudeStarted) publishRelativeAltitude();
534 }
535 }
536 }
537
538 void subsMsg(String topic, String msg, String originator) {
539 if (topic == name + "/sensor/temperature/get") {
540 publishTemperature();
541 } else if (topic == name + "/sensor/pressure/get") {
542 publishPressure();
543 } else if (topic == name + "/sensor/mode/get") {
544 publishFilterMode();
545 } else if (topic == name + "/sensor/calibrationdata/get") {
546 publishCalibrationData();
547 } else if (topic == name + "/sensor/referencealtitude/get") {
548 publishReferenceAltitude();
549 } else if (topic == name + "/sensor/relativealtitude/get") {
550 publishRelativeAltitude();
551 } else if (topic == name + "/sensor/relativealtitude/set") {
553 } else if (topic == name + "/sensor/oversampling/get") {
554 publishOversampling();
555 } else if (topic == name + "/sensor/referencealtitude/set") {
556 double alt = atof(msg.c_str());
558 } else if (topic == name + "/sensor/mode/set") {
559 if (msg == "fast" || msg == "FAST") {
560 setFilterMode(FilterMode::FAST);
561 } else {
562 if (msg == "medium" || msg == "MEDIUM") {
563 setFilterMode(FilterMode::MEDIUM);
564 } else {
565 setFilterMode(FilterMode::LONGTERM);
566 }
567 }
568 } else if (topic == name + "/sensor/oversampling/set") {
569 if (msg == "ULTRA_LOW_POWER") {
570 setSampleMode(BMPSampleMode::ULTRA_LOW_POWER);
571 } else {
572 if (msg == "STANDARD") {
573 setSampleMode(BMPSampleMode::STANDARD);
574 } else {
575 if (msg == "HIGH_RESOLUTION") {
576 setSampleMode(BMPSampleMode::HIGH_RESOLUTION);
577 } else {
579 }
580 }
581 }
582 }
583 }
584}; // PressTempBMP
585
586} // namespace ustd
mupplet-sensor temperature and pressure with Bosch BMP180
Definition: mup_presstemp_bmp180.h:111
double getTemperature()
Definition: mup_presstemp_bmp180.h:205
PressTempBMP180(String name, FilterMode filterMode=FilterMode::MEDIUM, uint8_t i2cAddress=0x77)
Definition: mup_presstemp_bmp180.h:165
double getPressure()
Definition: mup_presstemp_bmp180.h:212
void startRelativeAltitude()
Definition: mup_presstemp_bmp180.h:194
BMPSampleMode
Definition: mup_presstemp_bmp180.h:144
@ ULTRA_LOW_POWER
1 samples, 4.5ms conversion time, 3uA current at 1 sample/sec, 0.06 RMS noise typ....
Definition: mup_presstemp_bmp180.h:145
@ STANDARD
2 samples, 7.5ms conversion time, 5uA current at 1 sample/sec, 0.05 RMS noise typ....
Definition: mup_presstemp_bmp180.h:146
@ ULTRA_HIGH_RESOLUTION
8 samples, 25.5ms conversion time, 12uA current at 1 sample/sec, 0.03 RMS noise typ....
Definition: mup_presstemp_bmp180.h:148
@ HIGH_RESOLUTION
4 samples, 13.5ms conversion time, 7uA current at 1 sample/sec, 0.04 RMS noise typ....
Definition: mup_presstemp_bmp180.h:147
void setReferenceAltitude(double _referenceAltitudeMeters)
Definition: mup_presstemp_bmp180.h:187
double getPressureNN(double _pressure)
Definition: mup_presstemp_bmp180.h:219