Raspberry-Pi-Projekte: Luftdruckmessung mit Bosch BMP280

Prof. Jürgen Plate

Luftdruckmessung mit Bosch BMP280

Allgemeines

Unser Wetter wird deutlich vom Luftdruck und den damit einhergehenden Luftströmungen beeinflusst. Hoher Luftdruck steht meist für sonniges und trockenes Wetter, wogegen Tiefdruck Regen bedeutet. Starke Veränderungen des Luftdrucks innerhalb kurzer Zeit signalisieren einen bevorstehenden Wetterumschwung oder sogar einen Sturm. Der Luftdruck an einem beliebigen Ort der Erdatmosphäre ist der hydrostatische Druck der Luft, der an diesem Ort herrscht. Dieser Druck entsteht durch die Gewichtskraft der Luftsäule, die auf der Erdoberfläche oder einem Körper steht. Ein Barometer misst den aktuellen Luftdruck. Neben dem Wetter beeinflusst auch die Höhe des Ortes den Luftdruck. Kennt man den aktuellen Luftdruck bezogen auf die Höhe des Meeresspiegels kann man mit Hilfe der barometrischen Höhenformel aus dem aktuellen Luftdruck die aktuelle Höhe, beispielsweise eines Flugzeugs, bestimmen. Um für meteorologische Zwecke vergleichbare Luftdruckwerte zu bekommen, rechnet man den gemessenen Luftdruck immer auf Meereshöhe (Normal-Null) um.

Die international verwendete Maßeinheit für den Luftdruck ist das Pascal (Pa). Um gut handhabbare Zahlenwerte zu erhalten, wird der Luftdruck meist in Hektopascal (hPa) angegeben. Dieser Wert ist dann auch identisch mit der früher verwendeten Einheit Millibar. Der mittlere Luftdruck der Atmosphäre, bezogen auf Meereshöhe, beträgt normgemäß 101325 Pa = 1013,25 hPa ≈ 1 bar. Der Luftdruck ist einer täglich wiederkehrenden Periodik unterworfen, die zwei Maximal- und zwei Minimalwerte pro Tag aufweist. Grund sind die täglichen Schwankungen der Lufttemperatur. Die Maxima finden sich gegen 10 und 22 Uhr, die Minima gegen 4 und 16 Uhr. Der Luftdruck bewegt sich in der Regel zwischen 900 und 1050 hPa (der tiefste überlieferte Wert war ca. 870 hPa, der höchste Wert lag bei 1085 hPa).

Der Sensor BMP280 von Bosch

Der BMP280 ist ein kombiniertes Luftdruck- und Temperatur Sensor Modul. Im Vergleich zum Vorgänger BMP180 erreicht der BMP280 bei der Luftdruck- und Temperaturbestimmung eine wesentlich höhere Auflösung. Wie der BMP180 basiert auch der BMP280 auf der bewährten Piezo-resistiven Drucksensorik von Bosch mit hoher Genauigkeit, Linearität und Langzeitstabilität. Der BMP280 hat eine Auflösung von 0,12 Pa. Im Bezug der Temperaturmessung erreicht der BMP280 Sensor gar die 10-fache Genauigkeit im Vergleich zum BMP180. Das Sensormodul ist in einer äußerst kompakten Gehäuse untergebracht. Seine geringen Abmessungen und seine geringe Leistungsaufnahme ermöglichen die Implementierung in batteriebetriebenen Geräten. Der BMP280 verfügt über ein digitales I2C- bzw. SPI-Interface. Bei I2C belegt er die Adressen 0x76 oder 0x77. Die Antwortzeit des Sensors auf eine Messanfrage dauert etwa 1 Sekunde, es sind also maximal 60 Messungen je Minute möglich.

Der Baustein selbst ist nur 2,5 mm mal 2,5 mm groß und weniger als einen Millimeter hoch. Die acht Anschlüsse auf der der Unterseite sind für den Lötkolben unerreichbar. Glücklicherweise gibt es den BME280 fertig montiert zusammen mit einigen notwendigen Bauteilen auf einem Breakout-Board fertig zu kaufen. Auf dem von mir vrwendeten Mini-Breakout-Board von Watterott befinden sich ein Spannungsregler und ein Pegelwandler für die I2C/SPI Schnittstelle, daher kann der Sensor mit 3 V bis 5,5 V betrieben werden. Die Adresse ist per Default auf 0x77 eingestellt. Ähnliche Boards gibt es auch von Adfruit oder Sparkfun.


Breakoutboard von watterott

Features:

Betrieb des BMP280 am Raspberry Pi

Für die Verbindungen von BMP280-Breakout-Board zum Raspberry Pi werden nur vier Leitungen benötigt:

BMP280-BoardRasPi
Vin5V, Pin 2
3Vo -
GNDGND, Pin 6
SCKSCL, Pin 5
SDO -
SDISDA, Pin 3
CS -

Der BMP280 liefert zunächst unkompensierte Rohwerte für Temperatur und Luftdruck. Für die Berechnung der kompensierten Werte notwendigen Kalibrierungsinformationen sind vom Hersteller bereits in einen 176-Bit-EEPROM gespeichert. Das Auswerte-Programm muss diese Werte auslesen und die Berechnung durchführen. Daher ist die Software etwas komplexer; das Datenblatt liefert detaillierte Informationen dazu. Wer sich diese Arbeit sparen möchte, kann das unten beschriebene Python- oder C-Programm verwenden.

Das Beispielprogramm berechnet zunächst die Temperatur und den lokal gemessenen absoluten Luftdruck. Bei einer Wetterstation ist die Höhe der Station über NN ist bekannt und man will aus dem gemessenen absoluten Luftdruck den auf Meereshöhe bezogenen Luftdruck bestimmen. Die Druckangabe in der Thermodynamik, also auch bei Wetterstationen, bezieht sich immer auf Meereshöhe, um mit anderen Stationen vergleichbar zu sein. Die Berechnung des Luftdruck auf Meereshöhe erfolgt mittels einer vereinfachten barometrischen Höhenformel. Dazu muss der lokale Luftdruck (local_pressure) in Pascal und die Höhe über dem Meeresspiegel (local_altitude) in Metern angegeben werden:

absolute_pressure = local_pressure/pow(1 - local_altitude/44330, 5.255)

Software

Die folgenden Beispielprogramme in C und in Python sind geradeaus nach den Angaben des Datenblatts programmiert. Jeder Chip enthält einen Speicherbereich mit seinen individuellen Kalibrierungsdaten ("trimming parameters"). Diese parameter werden während der Produktion Im nichtflüchtigen Speichers (NVM) des Chips programmiert. Jedes Kompensationswort ist ein 16-Bit-Wert (unsigned int oder signed int (Zweierkomplement). Da der Speicher in Bytes organisiert ist, müssen immer zwei Bytes zu einen 16-Bit-Wert kombiniert werden, um das Kompensationswort darzustellen. Die Werte sind an den Speicheradressen 0x88 bis 0xA1 gespeichert. In der folgenden Tabelle heißen die entsprechenden Kompensationswörter für die Temperatur "dig_Txx" und für die Druckkompensation "dig_Pxx":

Mit diesen Werten, die im Programm in Arrays (T[] bzw. P[]) gespeichert werden, wird dann die Temperatur- bzw. Druckkompensation berechnet.

Die gesamte Kommunikation mit dem Device erfolgt über den I2C-Bus durch Lesen und Schreiben von Registern, die alle eine Breite von acht Bit haben. Es gibt einige Register, die reserviert sind; diese sollten nicht beschrieben werden. Für das Lesen der Temperatur- und Luftdruck-Rohwerte sind die in der folgenden Grafik gelb unterlegten Register zuständig. Wie man sieht, sind für jeden Wert drei Byte, also 24 Bit vorgesehen. Dabei stehen die niederwertigsten vier Bit ("xlsb") im ersten Register, dann folgen die nächsten acht Bit ("lsb") im folgenden Register und schließlich die höchsten acht Bit ("msb") im dritten Register. Die niederwertigen vier Bit des "xlsb"-Registers sind immer 0 und müssen ignoriert werden.

Somit ergibt sich ein Wert von 20 Bit Auflösung. Daraus ergibt sich die Berechnung der ausgelesenen Werte zu:

Druck = (Reg[0xF7] << 12) + (Reg[0xF8] << 4) + (Reg[0xF9] >> 4)
Temp. = (Reg[0xFA] << 12) + (Reg[0xFB] << 4) + (Reg[0xFC] >> 4)
Wenn man nich die volle Genauigkeit benötigt, reicht es sogar, nur die Register für "lsb" und "msb" auszulesen.

Das "id"-Register enthält die Chip-Identifikationsnummer, die immer 0x58 lautet. Diese Nummer kann gelesen werden, sobald der CHip den Power-On-Reset beendet hat. Das "Reset"-Register erlaubt einen Soft-Reset des Chips. Wird der Wert 0xB6 in das Register geschrieben, führt er einen kompletten Power-On-Reset aus. Andere Werte als 0xB6 haben keine Wirkung. Der Auslesewert ist immer 0x00. Wichtig sind noch die beiden Steuerregister (0xF4 und 0xF5), mit denen der Arbeitsmodus eingestellt wird. In den Beispielprogrammen wird das Register 0xF4 mit dem Wert 0x27 beschrieben, was den Standardmodus setzt und die Oversamplingrate auf 1 einstellt. Das Register 0xF5 wird mit 0xA0 gefüttert, womit die Standby-Zeit auf 1000 ms gesetzt wird, der IIR-Filter ist abgeschaltet und der Baustein auf I2C-Kommunikation eingestellt. Für die weiteren Register und andere Feinheiten sei an dieser Stelle auf das Datenblatt verwiesen.

Nach dem Lesen der Rohwerte erfolgt die Konpensation mit den Kalibrierungsdaten, die zuvor eingelesen wurden. Die Berechnung folgt den Vorschlägen des Datenblatts, wobei auch die Datenblätter der Vorgänger BMP085 und BMP180 zu Rate gezogen wurden. Es ist halt eine ziemliche Rechnerei.Anschließend wird dann noch der Luftdruck bezogen auf Meereshöhe berechnet. Dazu muss die Konstante ALTITUDE auf die aktuelle Höhe des Messortes angepasst werden. Beim Übersetzen an das Einbinden der Mathe-Bibliothek denken ( gcc -Wall -o bmp280 -lm BMP280.c).

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <math.h>

// altitude above sea level
#define ALTITUDE 500

// address of BMP280 (0x76 or 0x77)
#define I2CADDR 0x77

// I2C bus 1
char *BUS = "/dev/i2c-1";

// raw calibration data
char data[24] = {0};
// temperature calibration coeff.
int T[3] = {0};
// pressure calibration coeff.
int P[9] = {0};

int main(void)
  {
  int device;                       // devicehandle
  double temperature;             // final temperature
  double pressure;                // final pressure
  double pressure_nn;             // final pressure at sea level
  int i;                          // loop counter
  double temp1, temp2, temp3;     // calculating temperature
  double press1, press2, press3;  // calculating pressure
  char reg[1] = {0};              // reg[], config[] for I2C I/O
  char config[2] = {0};

  if((device = open(BUS, O_RDWR)) < 0)
    {
    printf("Failed to open the i2c bus. \n");
    exit(1);
    }
  // get I2C device
  ioctl(device, I2C_SLAVE, I2CADDR);

  // read 24 bytes of calibration data from address(0x88)
  reg[0] = 0x88;
  write(device, reg, 1);
  if(read(device, data, 24) != 24)
    {
    printf("Unable to read data from i2c bus\n");
    exit(1);
    }

  // temp coefficents
  T[0] = data[1] * 256 + data[0];
  T[1] = data[3] * 256 + data[2];
  if(T[1] > 32767) { T[1] -= 65536; }
  T[2] = data[5] * 256 + data[4];
  if(T[2] > 32767) { T[2] -= 65536; }

  // pressure coefficents
  P[0] = data[7] * 256 + data[6];
  for (i = 0; i < 8; i++)
    {
    P[i+1] = data[2*i+9]*256 + data[2*i+8];
    if(P[i+1] > 32767) { P[i+1] -= 65536; }
    }

  // Select control measurement register(0xF4)
  // normal mode, temp and pressure oversampling rate = 1(0x27)
  config[0] = 0xF4;
  config[1] = 0x27;
  write(device, config, 2);

  // select config register(0xF5)
  // stand_by time = 1000 ms(0xA0)
  config[0] = 0xF5;
  config[1] = 0xA0;
  write(device, config, 2);
  sleep(1);

  // Read 6 bytes of data from register(0xF7)
  reg[0] = 0xF7;
  write(device, reg, 1);
  if(read(device, data, 6) != 6)
    {
    printf("Unable to read data from i2c bus\n");
    exit(1);
    }

  // Convert pressure and temperature data to 19-bits
  long adc_p = (((long)data[0] << 12) + ((long)data[1] << 4) + (long)(data[2] >> 4));
  long adc_t = (((long)data[3] << 12) + ((long)data[4] << 4) + (long)(data[5] >> 4));

  // temperature offset calculations
  temp1 = (((double)adc_t)/16384.0 - ((double)T[0])/1024.0)*((double)T[1]);
  temp3 = ((double)adc_t)/131072.0 - ((double)T[0])/8192.0;
  temp2 = temp3*temp3*((double)T[2]);
  temperature = (temp1 + temp2)/5120.0;

  // pressure offset calculations
  press1 = ((temp1 + temp2)/2.0) - 64000.0;
  press2 = press1*press1*((double)P[5])/32768.0;
  press2 = press2 + press1*((double)P[4])*2.0;
  press2 = (press2/4.0) + (((double)P[3])*65536.0);
  press1 = (((double) P[2])*press1*press1/524288.0 + ((double) P[1])*press1)/524288.0;
  press1 = (1.0 + press1/32768.0)*((double)P[0]);
  press3 = 1048576.0 - (double)adc_p;
  if (press1 != 0.0)                                 // avoid error: division by 0
    {
    press3 = (press3 - press2/4096.0)*6250.0/press1;
    press1 = ((double) P[8])*press3*press3/2147483648.0;
    press2 = press3 * ((double) P[7])/32768.0;
    pressure = (press3 + (press1 + press2 + ((double)P[6]))/16.0)/100;
    }
  else
    { pressure = 0.0; }
  pressure_nn = pressure/pow(1 - ALTITUDE/44330.0, 5.255);

  // Output data to screen
  printf("Temperature: %.2f C \n", temperature);
  printf("Pressure:    %.2f hPa \n", pressure);
  printf("Pressure NN: %.2f hPa \n", pressure_nn);
  return 0;
  }

Das Python-Programm ist eine Adaption des C-Programms, der Ablauf ist hier identisch. Auch hier sind alle konstanten Parameter am Programmanfang eingestellt. Beide Programme liefern drei Zeilen Output:

Temperature: 26.29 C
Pressure:    960.14 hPa
Pressure NN: 1019.11 hPa

Links


Copyright © Hochschule München, FK 04, Prof. Jürgen Plate
Letzte Aktualisierung: