Temperatur- und Drucksensoren BMP280 und BME280 an Microcontrollern per SPI oder I2C betreiben
https://bildung.social/deck/@oerinformatik/114120517692659575
https://oer-informatik.de/esp_bme280
tl/dr; (ca. 5 min Lesezeit): Breakoutsboards mit den günstige Temperatur- und Drucksensoren BMP280 und BME280 sind weit verbreitet und lassen sich mithilfe vieler Bibliotheken an Microcontrollern anbinden. Es werden in diesem Artikel die Unterschiede der Sensoren, deren Anschluss per SPI und I2C und deren Anbindung per C++ Code gezeigt. Dazu gibt es Beispielcodes, Hinweise auf mögliche Fehlerquellen alternativen zur Vorgegebenen Pin-/Adress-Belegung. (Zuletzt geändert am 11.11.2025)
Teilabschnitte dieses Artikels sind:
Welcher Sensor liegt vor?
Generelle Überlegungen zu Installation und Inbetriebnahme von Devices am Microcontrollerboard
Aufbau und Beispielcode mit der I2C-Schnittstelle
Individuelle Konfiguration per I2C-Schnittstelle
Aufbau und Beispielcode mit der SPI-Schnittstelle
Individuelle Konfiguration per SPI-Schnittstelle
Welcher Sensor liegt vor Dir? BME280 oder BMP280?
Es gibt unzählige Breakout-Boards für zwei sehr ähnlichen Temperatur/Druck Sensoren von Bosch: der BME280 und der BMP280 sind sich in Aussehen und Funktion zum Verwechseln ähnlich. Zunächst müssen wir erst einmal herausfinden, welcher Sensor auf dem jeweiligen Board verbaut wurde:

Auf den Breakout-Boards findet sich der eigentliche Sensor in einem kleinen Metallgehäuse - an diesem können die beiden Varianten voneinander abgegrenzt werden:
Den etwas funktionsreicheren BME280-Sensor (im Bild oben links) erkennt man bei genauem Hinsehen am eher quadratischeren Metallgehäuse, das eine winzige Öffnung fast mittig zu linken Seitenkante hat (gut zu erkennen auf den Datenblattseiten des Herstellers Bosch). Der BME280 kann neben Temperatur und Luftdruck auch noch die Luftfeuchtigkeit messen.
Demgegenüber hat der BMP280-Sensor (im Bild oben rechts) einen rechteckigen Sensor mit unterschiedlichen langen Kanten. Er ist etwas günstiger und kann nicht die Luftfeuchtigkeit messen. Das kleine Metallgehäuse hat eine Öffnung, die eher in der Ecke liegt (gut zu erkennen z.B. auch auf den Datenblattseiten des Herstellers Bosch).
Generelle Überlegungen zu Installation und Inbetriebnahme von Devices am Microcontrollerboard
Das Vorgehen ist eigentlich bei allen Geräten im Arduino-Kosmos identisch, unabhängig davon, ob es ein Sensor, ein Aktor, ein Display oder etwas völlig anderes ist:
Typenbezeichnung suchen: Zuerst muss die Art und Typ des neuen Geräts herausgefunden werden. Manchmal steht dies auf der Platine, manchmal muss man im Netz nach Fotos/Pinouts suchen (siehe unten).
Bibliothek wählen und installieren: Wird mit der Arduino-IDE entwickelt, so muss im Menü
Werkzeuge/Bibliotheken verwalteneine passende Bibliothek für das Gerät gesucht werden. Häufig sind die Bibliotheken von Adafruit relativ gut. Wer eine andere IDE nutzt, ist hoffentlich fortgeschritten genug, die Bibliotheken selbständig einzubinden. Falls nicht, wäre der Wechsel zur Arduino-IDE eine Option.Pins des Geräts recherchieren und Logiklevel prüfen: Zum Anschließen des Geräts benötigen wir die Pinbezeichnungen der jeweils genutzten Platine. Nicht immer ist der Aufdruck auf den Platinen komplett, häufig wirkt ein zusätzliches Pinout (Bildersuche nach “Pinout Gerätebezeichnung”) Wunder. Dabei sollte im Datenblatt auch geprüft werden, ob das Logiklevel der Platine mit dem des Microcontrollers kompatibel ist (Arduino Uno: 5V, ESPs, Arduino Mega: 3,3V).
Freie Pins des Microcontrollers wählen: Bevor wir verdrahten können, sollten wir uns noch entscheiden, welche Schnittstelle wir verwenden wollen (wenn das Gerät mehrere anbietet - z.B. SPI oder I2C). Dazu benötigen wir eine Liste der freien Pins unseres Microcontrollers, der für diese Schnittstelle geeignet ist (für einige ESPs beispielsweise in diesem Artikel). Ggf. hilft auch ein Blick in die Beispielquelltexte mit Hinweisen (s.u.).
Verdrahten und mit Beispielcode erkunden: Dann kann das Gerät verdrahtet werden und über Beispiel-Quelltexte (
Datei/Beispielehäufig ganz unten: “Beispiele angepasster Bibliotheken”) erkundet werden.
In unserem konkreten Fall:
Zu (1) Typenbezeichnung suchen: BME280 - siehe oben
Zu (2) Bibliothek wählen und installieren: Werkzeuge / Bibliotheken verwalten
Die Suche nach “BME280” liefert u.a. die Bibliothek “Adafruit BME280 Library”, die ich in dem Beispiel nutze - andere Bibliotheken können aber ebenso eingesetzt werden:

Die Bibliothek benötigt eine Reihe von weiteren Abhängigkeiten, die direkt mit installiert werden können:

Aufbau und Beispielcode mit der I2C-Schnittstelle
Zu (3) Pins des Geräts recherchieren
Ich schließe den BME280/BMP280 zunächst per I2C-Schnittstelle an - hierfür sind neben der Spannungsversorgung (3V3, GND) noch die Signale Clock (SCL) und Data (SDA) nötig. Die beiden übrigen Pins (CSB, SDO) sind nur für den Anschluss per SPI-Schnittstelle nötig (oder zur Änderung der I2C-Adresse), können daher unbeschaltet bleiben.
Zu (4) Freie Pins des Microcontrollers wählen
Da wir den BME280/BMP280 per I2C-Schnittstelle anschließen wollen, nutzen wir einfach die vorgesehenen Pins:
bei ESP32 ist dies:
GPIO21fürSDAundGPIO22fürSCL.bei ESP8266 ist dies:
D2fürSDAundD1fürSCL.bei Arduino Uno ist dies:
A4fürSDAundA5fürSCL.
Wenn bereits andere I2C Geräte an diesen Leitungen angeschlossen sind, dann kann der Sensor zusätzlich parallel angeschlossen werden - schließlich handelt es sich hierbei um ein Bus-System, dass genau für den Anschluss mehrere Geräte gedacht ist.
Es wären auch andere Pins möglich (siehe unten), aber so sparen wir uns etwas Konfigurationsarbeit.
Zu (5) Verdrahten und mit Beispielcode erkunden:
Der Aufbau sieht bei mir mit einem ESP32 Dev V1 so aus (vorsicht: ggf. ist die Pinleiste andersherum aufgelötet und alle Pins des Sensors gespiegelt):

Natürlich müssen bei einem anderen Microcontroller auch andere Pins verwendet werden, da die Adafruit_BMx280-Bibliothek die I2C-Standardpins der jeweiligen Boards verwendet. (Wie man von den Standardports abweichen kann erkläre ich weiter unten).
Wichtig ist zu beachten, dass die Pinanordnung des Sensors auch spiegelverkehrt sein kann, wenn die Pin-Leiste auf der anderen Seite angelötet wurde. Außerdem sind die Spannungsversorgungs-Schienen (rote und blaue Pinleisten außen) am Breadboard manchmal umgekehrt - also bitte immer alle Kontakte des eigenen Aufbaus prüfen und nicht einfach nach optischer Ähnlichkeit zusammenstecken!
Die I2C-Schnittstelle identifiziert Geräte am Bus über eine eindeutige Adresse. Jedes Gerät erkennt anhand dieser Adresse, wer Empfänger der Nachrichten am Bus sein soll. Die Adresse umfasst sieben Bit, es gibt also 2^7 = 128 verschiedene Adressen ( also 0 und 127 dezimal, 0x00-0x7F hexadezimal, 0b0000000 - 0b1111111 binär). Damit mehrere Geräte des gleichen Typs angeschlossen werden können, wird häufig nur ein Teil dieser Adresse durch den Hersteller fest vorgegeben, einige Bit können manuell konfiguriert werden. Bei den BMx280-Sensoren wird das letzte Bit angepasst - es können die I2C-Adressen 0x76 (binär: 0b1110110) oder 0x77 (binär: 0b1110111) konfiguriert werden. Im Fall der oben abgebildeten BMx280-Breakout-Boards wird das letzte Bit über den Pin SDO bestimmt: liegt hier ein HIGH an, reagiert der Sensor auf die Adresse 0x77, ist der Pin nicht verdrahtet oder LOW, dann regiert der Sensor auf 0x76.
Die genutzte Bibliothek spricht standardmäßig die Adresse 0x77 an. Wir müssen also entweder ein HIGH an SDO anlegen - oder aber die Software an die neue Adresse (0x76) anpassen (wie unten geschehen). Wir verlassen uns in dem Beispielcode nicht darauf, dass die IDE die Standardports der I2C-Schnittstelle erkennt und geben diese sicherheitshalber explizit an.Dadurch können wir die Pins auch individuell konfigurieren.
Intern nutzt der Adafruit_BMx280-Treiber eine Arduino-Bibliothek namens Wire, um die I2C-Kommunikation abzuwickeln. Mit Hilfe dieser Bibliothek können wir die I2C-Verbindung auch auf andere Pins legen, indem wir zu Beginn unseres Programms die Pin-Bezeichnungen über den Aufruf Wire.begin(MCU_SDA, MCU_SCL); übergeben. Natürlich müssen die beiden Variablen, die ich hier mal MCU_SDA und MCU_SCL genannt habe, vorher deklariert und initialisiert werden. Alternativ können auch direkt die Pinbezeichnungen übergeben werden (Wire.begin(18, 19);), was aber den Quelltext schlecht wartbar machen würde.
Ein minimales Programm, das den BMx280-Sensor mit der Adafruit-Bibliothek abfragt, könnte also so aussehen:
#include <Adafruit_BME280.h>
//-------------------------------------------------------------------------------------
// List of Input- and Output-devices and Pins
//-------------------------------------------------------------------------------------
// Datatype | Name of Variable | Pin No. connected | Name, Behaviour*/
const int MCU_SDA = 21; // GPIO of MCU connected to SDA-Pin of Sensor
const int MCU_SCL = 22; // GPIO of MCU connected to SDCL-Pin of Sensor
const int I2C_ADDR = 0x76; // if SD0 is floating or LOW 0x76, else 0x77
//-------------------------------------------------------------------------------------
// App-Settings
//-------------------------------------------------------------------------------------
#define SEALEVELPRESSURE_HPA (1013.25)
unsigned long delayTime = 1000;
unsigned long serialMonitorBaudrate = 115200;
Adafruit_BME280 bme;
void setup(){
Serial.begin(serialMonitorBaudrate); // Activate debugging via serial monitor
Wire.begin(MCU_SDA, MCU_SCL); // connection with individual I2C-Pins
int status = bme.begin(I2C_ADDR, &Wire); //status = bme.begin();
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring, i2c address");
while (1) delay(10);
}
Serial.println("|Temperature | Pressure | Altitude | Humidity |");
}
void loop() {
serialPrintMeasurement();
delay(delayTime);
}
void serialPrintMeasurement() {
char prBuffer[51]; // Print buffer
float temp = bme.readTemperature();
float pressure = bme.readPressure() / 100.0F;
float altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);
float humidity = bme.readHumidity();
sprintf(prBuffer, "| %2.1f °C | %4.1f hPa | %3.1f m | %2.1f %% |",temp, pressure, altitude, humidity);
Serial.println(prBuffer);
}Der seriellen Monitor (Strg+ Shift+M) sollte bei 115200 Baud eingestellt jetzt folgendes ausgeben (beim BME zusätzlich noch die Spalte “Humidity”):
Temperature | Pressure | Altitude |
24.0 °C | 1004.1 hPa | 76.7 m |
23.9 °C | 1004.1 hPa | 76.8 m |
23.9 °C | 1004.1 hPa | 76.7 m |
23.8 °C | 1004.1 hPa | 76.2 m |
23.7 °C | 1004.1 hPa | 76.5 m |
Wenn dieser Programmcode oder die vom Treiber mitgelieferten Beispielsketche (Datei/ Beispiele / ganz unten: BME280 bzw. BMP280 ) nicht gehen, dann hat das häufig die folgenden Ursachen:
Could not find a valid BME280 sensor, check wiring, i2c address: Die I2C-Adresse ist falsch konfiguriert oder wird nicht erkannt. Welche Adresse hat der Sensor überhaupt und ist alles richtig verdrahtet? Hier hilft ein Scan des I2C-Bus’ über das Beispielprogramm:Datei/Beispiele/Wire/WireScan. Im Normalfall reicht es, sowohl die0x76als auch die0x77als Adresse zu versuchen.Ausgabe der Werte ist unrealistisch, z.B.
0.0 °C | 0.0 hPa | 44330.0 m |: Es handelt sich um den falschen Treiber für den Sensor - bitte nochmals prüfen, ob es ein BME280 oder BMP280 ist (siehe oben).Die Pins wurden vertauscht - das passiert insbesondere, wenn die Beschriftung auf der Unterseite ist und man sich alles “auf dem Kopf” vorstellen muss.
Aufbau und Beispielcode mit der SPI-Schnittstelle
Wenn wir anstelle der I2C-Schnittstelle die SPI-Schnittstelle nutzen wollen, können wir die Überlegungen (1) Sensorart bestimmen und (2) Treiber wählen und installieren von oben übernehmen. Bei der Pin-Belegung gibt es aber Unterschiede:
Zu (3) Pins des Geräts recherchieren
SPI nutzt neben der Spannungsversorgung (3V3, GND) vier weitere Pins: die Clock (SCL), Datenausgang des Microcontrollers (MOSI, SDA), Dateneingang des Microcontrollers (MISO, SDO) und einen Pin zur Sensorauswahl (Chip Select, CSB). Wesentliche Unterschiede zu I2C sind also, dass wir über unterschiedliche Leitungen lesen und schreiben (“Multiplex”) und anstelle einer Adressierung dem Sensor über eine eigene digitale Leitung mitgeteilt wird, dass die Nachricht am Bus für ihn bestimmt wird (CSB).
Zu (4) Freie Pins des Microcontrollers wählen
Auch die SPI-Kommunikation mit dem BME280/BMP280 wollen wir zunächst über die vorgesehenen Pins lösen:
bei ESP32 ist dies:
GPIO18fürSCL,GPIO19fürMISO/SDO,GPIO23fürMOSI/SDAundGPIO5fürCSBbei ESP8266 ist dies:
GPIO15/D5fürSCL,GPIO12/D6fürMISO/SDO,GPIO13/D7fürMOSI/SDAundGPIO15/D8fürCSBbei Arduino Uno ist dies:
D13fürSCL,D12fürMISO/SDO,D11fürMOSI/SDAundD10fürCSB
Es wären auch andere Pins möglich (siehe unten), aber so sparen wir uns etwas Konfigurationsarbeit.
Zu (5) Verdrahten und mit Beispielcode erkunden:
Der Aufbau sieht bei mir mit einem ESP32 Dev V1 so aus (vorsicht: ggf. ist die Pinleiste andersherum aufgelötet und alle Pins gespiegelt):

Der Adafruit-Treiber ist so generisch aufgebaut, dass sich nur wenige Codezeilen ändern, wenn statt der I2C-Schnittstelle die SPI-Schnittstelle verwendet wird.
Beim Aufruf des Treibers wird der Chip-Select-Pin übergeben - damit erkennt der Treiber automatisch, dass SPI verwendet werden soll:
Adafruit_BMP280 bmp(BMP_CS);Beim Starten der Messung wird keine I2C-Adresse übergeben:
bmp.begin()
Sicherheitshalber verlassen wir uns nicht darauf, dass die Standard-SPI-Ports des Microcontrollers korrekt gefunden werden und nutzen die Möglichkeit, alle SPI-Pins (MISO, MOSI) explizit zu konfigurieren. Damit sollte das Auslesen per SPI in jedem Fall klappen. Mit unterschiedlichen CS-Pins können so auch einfach mehrere Sensoren/Aktoren an den SPI-Bus angeschlossen werden. Ein minimales Codebeispiel sieht so aus:
#include <Adafruit_BME280.h>
//-------------------------------------------------------------------------------------
// List of Input- and Output-devices and Pins
//-------------------------------------------------------------------------------------
// Datatype | Name of Variable | Pin No. connected | Name, Behaviour*/
const int BMP_CS = 5; // GPIO of MCU connected to SPI-Chip-Select-(CSB)-Pin
const int BMP_MOSI = 23; // GPIO of MCU connected to SDA/SPI-MOSI-Pin
const int BMP_MISO = 19; // GPIO of MCU connected to SDO/SPI-MISO-Pin
const int BMP_CLK = 18; // GPIO of MCU connected to SCL/SPI-Clock-Pin
//-------------------------------------------------------------------------------------
// App-Settings
//-------------------------------------------------------------------------------------
#define SEALEVELPRESSURE_HPA (1013.25)
unsigned long delayTime = 1000;
unsigned long serialMonitorBaudrate = 115200;
Adafruit_BME280 bme(BMP_CS, BMP_MOSI, BMP_MISO, BMP_CLK); // indivudual SPI-Pins
void setup(){
Serial.begin(serialMonitorBaudrate); // Activate debugging via serial monitor
int status = bme.begin();
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring");
while (1) delay(10);
}
Serial.println("|Temperature | Pressure | Altitude | Humidity |");
}
void loop() {
serialPrintMeasurement();
delay(delayTime);
}
void serialPrintMeasurement() {
char prBuffer[51]; // Print buffer
float temp = bme.readTemperature();
float pressure = bme.readPressure() / 100.0F;
float altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);
float humidity = bme.readHumidity();
sprintf(prBuffer, "| %2.1f °C | %4.1f hPa | %3.1f m | %2.1f %% |",temp, pressure, altitude, humidity);
Serial.println(prBuffer);
}Quellen und weitere Informationen
Der Verdrahtungsplan wurde erstellt mit Fritzing, als BMx280-Part nutze ich das von vanepp/MWS erstellte aus dem Fritzing-Forum. Weitere Informationen dazu, welche Parts ich von Fritzing nutze in diesem Artikel.
Hinweis zur Nachnutzung als Open Educational Resource (OER)
Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: “Temperatur- und Drucksensoren BMP280 und BME280 an Microcontrollern per SPI oder I2C betreiben” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/esp_bme280 veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/mcu/arduino-esp. Stand: 11.11.2025.
[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]


