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).
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.
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
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.
In diesem Vergleichstest hat der BME280 zumindest für die Luftfeuchtigkeit sehr gut abgeschnitten: http://www.kandrsmith.org/RJS/Misc/Hygrometers/calib_many.html
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.
Hallo Alfred, danke für die rasche Antwort. Werde mich die nächsten Tage mit der Effizienz des Codes beschäftigen. Gruß G.G.
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)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.