Forum: Mikrocontroller und Digitale Elektronik BME280 Erfahrungen


von Alfred (Gast)


Lesenswert?

Schönen Tag allerseits!

Ich möchte hier kurz meine Erfahrungen mit dem BME280 von Bosch 
mitteilen. Um Freude zu haben, sollte man einige Punkte beachten:

1. Der gemessene Luftdruck (zuerst die Temperatur auslesen, sonst fehlt 
der notwendige Kalibrierwert!) stimmt erstens und zeigt zweitens den 
Luftdruck an dem Ort an, wo der Sensor sich tatsächlich befindet. Also 
bitte nicht im Zimmer messen, wenn man eine Wetterstation für draußen 
bauen will.

Der ausgegebene Wert für den Luftdruck entspricht aber jenem für die 
aktuelle Höhe und die aktuelle Temperatur. Das ev vorhandene Barometer 
zeigt aber wahrscheinlich den auf Meeresniveau "reduzierten" Wert (ist 
also höher als der vom BME280 angezeigte Wert).

Will man überprüfen, ob beide Geräte übereinstimmen, muß man den vom 
BME280 ausgegebenen Wert auf "Meeresniveau" umrechnen.

Das geht so:

pNN = ph * e (g*h/(R*(T+Ch*E+a*h/2)))

E = 6,112hPa * e (17,62*t(°C)/(243,12+t(°C)))   ACHTUNG: Magnusformel 
mit Koeffizienten für t = -45 bis +60°C

a = (Tm-Tb)/(hm-hb)    m ... Meßort  b ... Bezugsort

- pNN ist der auf Meeresniveau umgerechnete Luftdruckwert in hPa
- ph ist der vom BME280 ausgegebene tatsächliche Luftdruckwert am Meßort 
- in hPa
- e ist die e-Funktion
- g ist die Erdbeschleunigung, am 50. Breitengrad beträgt g=9,80665 m/s²
- h ist die Höhe (m) über Meeresniveau am Meßort
- R ist die Gaskonstante der Luft 287,058 J/(kg*K)
- t(°C) ist die Temperatur in °C am Meßort
- T ist die Temperatur in Kelvin T(K)=273,15+t(°C)
- Ch ist der Beiwert zu E zur Berücksichtigung der mittleren 
Dampfdruckänderung mit der Höhe (K/hPa)
- E (hPa) ist der Wasserdampfpartialdruck
- a (K/m) ist der vertikale Temperaturgradient

a ist oft unter Durchschnitts-Meeresniveau-Stardardbedingungen (t=15°C, 
pb=1013.25hPa, h=0m) mit 0.0065 angegeben - stimmt jedoch nicht 
wirklich, da durchaus in der Realität beträchtliche Abweichungen 
auftreten können >> also: besser selber berechnen!

Zur Überprüfung kann man den Meßwert des BME280 mit dem aus der 
Barometrischen Höhenformel ausgerechneten Wert vergleichen:

pz=pb*((1-a*(hz-hb)/(273,15+tb))^(0,03416/a))

a wird wie weiter oben berechnet, z bedeutet Werte am Zielort, b sind 
BEKANNTE Werte am Bezugsort (von einer offiziellen, naheliegenden 
meteorologischen Station abzufragen)

2. die gemessene Temperatur gibt lediglich einen Anhalt über die 
Umgebungstemperatur des BME280 (siehe Datenblatt). Wer genaue Werte für 
die Lufttemperatur haben will, muß schon einen externen Sensor (zB 
DS18B20) bemühen.

3. man findet in Softwarebibliotheken (va Arduino-Bibliotheken - 
Adafruit weist jedoch darauf hin!) häufig Funktionen, welche die 
Seehöhe=Höhe über Meeresniveau, berechnet aus den BME280-Meßwerten, 
ausgeben. Das ist leider völlig falsch!! Ohne einen genau bekannten 
Referenzpunkt (p,T auf Seehöhe oder besser einen naheliegenden Ort plus 
p,T am Zielort) kann die Höhe am Zielort aus den Sensorwerten NICHT 
ermittelt werden.

4. man kann weiters auch die Absolute Luftfeuchte

aF(kg/m³)=rF*E/(Rw*T)*10

mit Rw=461,51 J/(kg*K) und rF (relative Feuchte) als Quotient (nicht 
als%-Zahl!)

und den Taupunkt (wieder Magnusformel für t=-45 bis +60°C heranziehen)

τ(φ,ϑ) = K3 ⋅ ((K2 ⋅ ϑ)/(K3 + ϑ) + ln⁡ φ)/(K2 ⋅ K3/(K3 + ϑ) − lnφ)

φ: relative Luftfeuchte (Quotient)     ϑ: Temperatur in °C
K1=6.112hPa
K2=17,62
K3=243,12K

aus den Meßwerten herleiten (Details bitte aus dem Internet entnehmen).

von Alfred (Gast)


Lesenswert?

Nachtrag: Ch hat einen Wert von 0.12 K/hPa

von Juergen P. (optronik)


Lesenswert?

Danke für diese Informationen, gerade wenn man sich mit der Materie 
nicht so beschäftigt und nur den Druck messen will kann man schnell mal 
den Offset von NN übersehen.

von daVinciClaude (Gast)


Lesenswert?

Wow. Vielen Dank für die Infos. Habe auch ein Projekt mit dem Bosch 
Sensor in der Pipeline. Werde Deine Infos auf jeden Fall noch genauer 
studieren.

LG
Claude

von Gerhard G. (xmega)


Lesenswert?

Hallo,

schaut sehr professionell aus. Jetzt ist die normale C-Routine für dem 
BME280 schon aufwendig. Nun kommt nochmals eine mathematische Routine 
dazu.
Schafft das ein normaler Mikrocontroller?

Zeige mal Deine C-Routine als Beispiel.
Ist der Mehraufwand gerechtfertigt?


Gruß G.G.

von Gerd E. (robberknight)


Lesenswert?

In diesem Vergleichstest hat der BME280 zumindest für die 
Luftfeuchtigkeit sehr gut abgeschnitten:
http://www.kandrsmith.org/RJS/Misc/Hygrometers/calib_many.html

von Alfred (Gast)


Lesenswert?

Hallo Gerhard G.!

Anbei ein rasch zusammengezimmertes Beispiel für obige Überlegungen mit 
der Sparkfun-Bibliothek und dem umgebauten Sparkfun-Beispiel:
1
******************************************************************************
2
Board:  Arduino UNO
3
Sensor: BME280
4
5
ACHTUNG: bei der Berechnung der Seehöhe muß man den aktuellen Luftdruckwert (Pa) 
6
         auf Meeresniveau als Parameter übergeben >> sonst kommt Mist heraus
7
******************************************************************************/
8
9
#include <stdint.h>
10
#include "SparkFunBME280.h"
11
//Library allows either I2C or SPI, so include both.
12
#include "Wire.h"
13
#include "SPI.h"
14
#include <math.h>
15
16
#define a 0.00602      // ACHTUNG: 0.0065 gilt nur für Standardbedingungen h=0m T=15°C p=1013,25hPa
17
                      // besser aktuell berechnen: a= (Tz-Tb)/(hz-hb)   z=Zielpunkt   b=Bezugspunkt (kann Ort am Meer sein)
18
19
#define pSL 100800.0
20
21
//Global sensor object
22
BME280 mySensor;
23
24
float La, RH, TP, E, H, T, pNN, pH;
25
26
void setup()
27
{
28
  //***Driver settings********************************//
29
  //commInterface can be I2C_MODE or SPI_MODE
30
  //specify chipSelectPin using arduino pin names
31
  //specify I2C address.  Can be 0x77(default) or 0x76
32
  
33
  //For I2C, enable the following and disable the SPI section
34
  //mySensor.settings.commInterface = I2C_MODE;
35
  //mySensor.settings.I2CAddress = 0x77;
36
  
37
  //For SPI enable the following and dissable the I2C section
38
  mySensor.settings.commInterface = SPI_MODE;
39
  mySensor.settings.chipSelectPin = 10;
40
41
42
  //***Operation settings*****************************//
43
  
44
  //renMode can be:
45
  //  0, Sleep mode
46
  //  1 or 2, Forced mode
47
  //  3, Normal mode
48
  mySensor.settings.runMode = 3; //Normal mode
49
  
50
  //tStandby can be:
51
  //  0, 0.5ms
52
  //  1, 62.5ms
53
  //  2, 125ms
54
  //  3, 250ms
55
  //  4, 500ms
56
  //  5, 1000ms
57
  //  6, 10ms
58
  //  7, 20ms
59
  mySensor.settings.tStandby = 0;
60
  
61
  //filter can be off or number of FIR coefficients to use:
62
  //  0, filter off
63
  //  1, coefficients = 2
64
  //  2, coefficients = 4
65
  //  3, coefficients = 8
66
  //  4, coefficients = 16
67
  mySensor.settings.filter = 0;
68
  
69
  //tempOverSample can be:
70
  //  0, skipped
71
  //  1 through 5, oversampling *1, *2, *4, *8, *16 respectively
72
  mySensor.settings.tempOverSample = 1;
73
74
  //pressOverSample can be:
75
  //  0, skipped
76
  //  1 through 5, oversampling *1, *2, *4, *8, *16 respectively
77
    mySensor.settings.pressOverSample = 1;
78
  
79
  //humidOverSample can be:
80
  //  0, skipped
81
  //  1 through 5, oversampling *1, *2, *4, *8, *16 respectively
82
  mySensor.settings.humidOverSample = 1;
83
  
84
  Serial.begin(57600);
85
  Serial.print("Program Started\n");
86
  Serial.print("Starting BME280... result of .begin(): 0x");
87
  
88
  //Calling .begin() causes the settings to be loaded
89
  delay(10);  //Make sure sensor had enough time to turn on. BME280 requires 2ms to start up.
90
  Serial.println(mySensor.begin(), HEX);
91
92
  Serial.print("Displaying ID, reset and ctrl regs\n");
93
  
94
  Serial.print("ID(0xD0): 0x");
95
  Serial.println(mySensor.readRegister(BME280_CHIP_ID_REG), HEX);
96
  Serial.print("Reset register(0xE0): 0x");
97
  Serial.println(mySensor.readRegister(BME280_RST_REG), HEX);
98
  Serial.print("ctrl_meas(0xF4): 0x");
99
  Serial.println(mySensor.readRegister(BME280_CTRL_MEAS_REG), HEX);
100
  Serial.print("ctrl_hum(0xF2): 0x");
101
  Serial.println(mySensor.readRegister(BME280_CTRL_HUMIDITY_REG), HEX);
102
103
  Serial.print("\n\n");
104
105
  Serial.print("Displaying all regs\n");
106
  uint8_t memCounter = 0x80;
107
  uint8_t tempReadData;
108
  for(int rowi = 8; rowi < 16; rowi++ )
109
  {
110
    Serial.print("0x");
111
    Serial.print(rowi, HEX);
112
    Serial.print("0:");
113
    for(int coli = 0; coli < 16; coli++ )
114
    {
115
      tempReadData = mySensor.readRegister(memCounter);
116
      Serial.print((tempReadData >> 4) & 0x0F, HEX);//Print first hex nibble
117
      Serial.print(tempReadData & 0x0F, HEX);//Print second hex nibble
118
      Serial.print(" ");
119
      memCounter++;
120
    }
121
    Serial.print("\n");
122
  }
123
  
124
  
125
  Serial.print("\n\n");
126
  
127
  Serial.print("Displaying concatenated calibration words\n");
128
  Serial.print("dig_T1, uint16: ");
129
  Serial.println(mySensor.calibration.dig_T1);
130
  Serial.print("dig_T2, int16: ");
131
  Serial.println(mySensor.calibration.dig_T2);
132
  Serial.print("dig_T3, int16: ");
133
  Serial.println(mySensor.calibration.dig_T3);
134
  
135
  Serial.print("dig_P1, uint16: ");
136
  Serial.println(mySensor.calibration.dig_P1);
137
  Serial.print("dig_P2, int16: ");
138
  Serial.println(mySensor.calibration.dig_P2);
139
  Serial.print("dig_P3, int16: ");
140
  Serial.println(mySensor.calibration.dig_P3);
141
  Serial.print("dig_P4, int16: ");
142
  Serial.println(mySensor.calibration.dig_P4);
143
  Serial.print("dig_P5, int16: ");
144
  Serial.println(mySensor.calibration.dig_P5);
145
  Serial.print("dig_P6, int16: ");
146
  Serial.println(mySensor.calibration.dig_P6);
147
  Serial.print("dig_P7, int16: ");
148
  Serial.println(mySensor.calibration.dig_P7);
149
  Serial.print("dig_P8, int16: ");
150
  Serial.println(mySensor.calibration.dig_P8);
151
  Serial.print("dig_P9, int16: ");
152
  Serial.println(mySensor.calibration.dig_P9);
153
  
154
  Serial.print("dig_H1, uint8: ");
155
  Serial.println(mySensor.calibration.dig_H1);
156
  Serial.print("dig_H2, int16: ");
157
  Serial.println(mySensor.calibration.dig_H2);
158
  Serial.print("dig_H3, uint8: ");
159
  Serial.println(mySensor.calibration.dig_H3);
160
  Serial.print("dig_H4, int16: ");
161
  Serial.println(mySensor.calibration.dig_H4);
162
  Serial.print("dig_H5, int16: ");
163
  Serial.println(mySensor.calibration.dig_H5);
164
  Serial.print("dig_H6, uint8: ");
165
  Serial.println(mySensor.calibration.dig_H6);
166
    
167
  Serial.println();
168
  delay(5000);
169
}
170
171
void loop()
172
{
173
  //Each loop, take a reading.
174
  //Start with temperature, as that data is needed for accurate compensation.
175
  //Reading the temperature updates the compensators of the other functions
176
  //in the background.
177
178
  T=mySensor.readTempC();
179
  Serial.print("Temperatur: ");
180
  Serial.print(T,2);
181
  Serial.println(" °C");
182
183
  /*Serial.print("Temperature: ");
184
  Serial.print(mySensor.readTempF(), 2);
185
  Serial.println(" degrees F");*/
186
187
  pH=mySensor.readFloatPressure()/100.0;
188
  Serial.print("Luftdruck vor Ort: ");
189
  Serial.print(pH, 2);
190
  Serial.println(" hPa");
191
192
  H=mySensor.readFloatAltitudeMeters(pSL);
193
194
  E=6.112*exp((17.62*T)/(243.12+T));
195
  pNN=pH*exp(9.80665*H/(287.058*((273.15+T)+0.12*E+a*H/2)));
196
197
  Serial.print("Luftdruck reduziert: ");
198
  Serial.print(pNN, 2);
199
  Serial.println(" hPa");
200
201
  Serial.print("Höhe über Meer: ");
202
  Serial.print(H, 2);
203
  Serial.println("m");
204
205
  /*Serial.print("Altitude: ");
206
  Serial.print(mySensor.readFloatAltitudeFeet(), 2);
207
  Serial.println("ft"); */
208
209
  RH=mySensor.readFloatHumidity();
210
  Serial.print("Relative Luftfeuchte: ");
211
  Serial.print(RH, 2);
212
  Serial.println(" %");
213
214
  La=RH*E/(461.51*(273.15+T))*10000.0;
215
216
  Serial.print("Absolute Luftfeuchte: ");
217
  Serial.print(La, 2);
218
  Serial.println(" g/m³");
219
220
  TP=243.12*((17.62*T)/(243.12+T)+log(RH/100.0))/((17.62*243.12)/(243.12+T)-log(RH/100.0));
221
  Serial.print("Taupunkt: ");
222
  Serial.print(TP, 2);
223
  Serial.println(" °C");    
224
  
225
  Serial.println();
226
  
227
  delay(5000);
228
229
}


Verwendet wurde ein herkömmliches chinesisches Arduino-UNO-board.

Die IDE gibt beim Kompilieren folgendes aus:

"Sketch uses 12746 bytes (39%) of program storage space. Maximum is 
32256 bytes. Global variables use 1171 bytes (57%) of dynamic memory, 
leaving 877 bytes for local variables. Maximum is 2048 bytes."

Bei dem völlig un-optimierten Code scheint mir der Speicherbedarf 
eigentlich nicht zu groß zu sein.

von Gerhard G. (xmega)


Lesenswert?

Hallo Alfred,

danke für die rasche Antwort. Werde mich die nächsten Tage mit der 
Effizienz des Codes beschäftigen.





Gruß G.G.

von Hanspeter Roth (Gast)


Lesenswert?

readFloatAltitudeMeters()
Use to get altitude in units of meters, as a float. This function 
calculates based off the measured pressure. Takes no Arguments.

But in the Example You Need:
#define pSL 100800.0

[H=mySensor.readFloatAltitudeMeters(pSL);]


and the result is:

LCD_PressureTemperature_Ro:246:42: error: no matching function for call 
to 'BME280::readFloatAltitudeMeters(double)'

    H=mySensor.readFloatAltitudeMeters(pSL);


Can You help me? (I'm german language)

von my2ct (Gast)


Lesenswert?

Alfred schrieb:
> 1. Der gemessene Luftdruck (zuerst die Temperatur auslesen, sonst fehlt
> der notwendige Kalibrierwert!) stimmt erstens und zeigt zweitens den
> Luftdruck an dem Ort an, wo der Sensor sich tatsächlich befindet. Also
> bitte nicht im Zimmer messen, wenn man eine Wetterstation für draußen
> bauen will.

Ob der Luftdruck im Zimmer oder draußen gemessen wird, ist nun wirklich 
schnuppe, solange man in einem normalen Haus ohne aktive Lüftung wohnt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.