Drucksensoren BMP280 und BME280
Mit dem BMP280 Sensor lässt sich der Absolutdruck und die Umgebungstemperatur messen. Mit dem etwas größeren BME280 Sensor zusätzlich noch die Luftfeuchtigkeit. Das Auslesen der Messwerte funktioniert bei beiden Sensoren sehr ähnlich so dass sie in diesem Artikel zusammengefasst werden können.
Der Sensor misst in einstellbaren Abständen nacheinander die Temperatur den Luftdruck und beim BME280 zusätzlich die Luftfeuchtigkeit. Es kann dabei eingestellt werden wie häufig (und damit auch wie lange) in einem Messzyklus die 3 Messwerte ermittelt werden. Je höher dieses 'oversampling' gewählt wird (bis zu 16x) desto genauer wird die Messung.
Um kurzzeitige Störungen der Messwerte zu reduzieren (Windstoß etc.) kann für die Druck- und Temperaturmessung ein Low Pass Filter zugeschaltet werden.
Die Messwerte des Sensors sind zunächst nur Rohdaten. Diese Rohdaten müssen mit in den im Datenblatt angegebenen Berechnungsformeln mit sensor-spezifischen Kalibrierungswerten zu den gewünschten Messwerte in °C, hPa oder % Luftfeuchte umgerechnet werden. Die Kalibrierwerte wurden bei der Herstellung für jeden einzelnen Sensor ermittelt und sind in entsprechenden Registern zum Auslesen abgelegt.
Nach dem Einschalten befindet sich der Sensor zunächst im 'Sleep Mode' und nimmt keine Messungen vor. In diesem Modus konfiguriert man die Register. Für die Messungen steht ein 'Forded Mode' für einen einzelnen Messzyklus auf Anforderung oder ein 'Normal Mode' für eine dauerhaft Messung mit einstellbaren Abständen zwischen den Messzyklen zur Verfügung.
Ansteuerung des Sensors
Die BMx280 Sensoren lassen sich mit I2C oder SPI ansteuern. Das gewünschte Protokoll wird über den CSB Pin festgelegt. Liegt dieser dauerhaft auf VCC ist die I2C Verbindung aktiv, ansonsten die SPI Verbindung. Der SDO Pin dient bei der I2C Verbindung zur Auswahl der Sensor-Slave-Adresse. Zwei Adressen stehen zur Auswahl (0x76 und 0x77). Die SPI Schnittstelle funktioniert mit dem SPI Modus 1 und 3 (siehe SPI Schnittstelle).
| Pinbelegung | |
|---|---|
| VCC | +3,3V Spannungsversorgung |
| GND | - Spannungsversorgung |
| SCL | Serial Clock (I2C: Clock Line | SPI: SCK) |
| SDA | Serial Data (I2C: Data Line | SPI: MOSI ) |
| CSB | Chip Select (I2C: dauerhaft VCC | SPI: CS) |
| SDO | Serial Data Output I2C: GND= Slave Adresse 1110110, VCC= Slave Adresse 1110111 SPI: MISO |
Die Komplette Kommunikation mit dem Sensor erfolgt über das Auslesen oder Beschreiben von Registern.
SPI
Read: Nachdem mit CSB LOW die Übertragung eingeleitet wurde wird die Register-Adresse übertragen. Die eigentliche Adresse hat nur 7 Bit. Am MSB = 1 erkennt der Sensor, dass nachfolgend Daten aus dem Register gelesen werden sollen. Die BMx Sensoren haben eine 'Auto-Inkrement' Funktion, so dass nachfolgende Register direkt hintereinander ausgelesen werden können. Nach der letzte Übertragung wird mit CSB HIGH die Übertragung beendet.
Write:Auch hier wird mit CSB LOW die Übertragung eingeleitet. Das MSB ist hier 0. Daran erkennt der Sensor, dass das Register beschrieben werden soll. Das sich an die Registeradresse anschließende Byte wird in dem Register gespeichert. Mit CSB HIGH wird die Übertragung beendet.
I2C
Write: Wie bei I2C üblich besteht die Slave Adresse nur aus 7 Bit. Das LSB=0 bedeutet, dass Daten zum Slave gesendet werden sollen. Als zweites Bit nach der Slave-Adresse wird die Registeradresse übertragen und als letztes das Datenbyte, welches in das Register geschrieben werden soll. (SLAVE-ADRESSE mit LSB=0 | REGISTER-ADRESSE | DATEN)
Read: Das Lesen aus einem bestimmten Register erfolgt mit zwei Befehlen. Zuerst muss das Register, welches gelesen werden soll gesendet werden. Dies erfolgt im Write-Mode (SLAVE-ADRESSE mit LSB=0 | REGISTER-ADRESSE). Als zweiter Befehl wird der der Sensor aufgefordert zum Senden (SLAVE-ADRESSE mit LSB=1). Nacheinander (Auto increment) werden nun die Registerinhalte zum Master übertragen bis der die Übertragung beendet.
Register Beschreibung
Config Register (0x88-0xA1 und beim BME280 zusätzlich 0xE1-0xF0)
In diesen Registern werden die bei der Produktion ermittelten Kalibrierwerte gespeichert. Diese Registereinträge müssen bei der Initialisierung zunächst ausgelesen und gespeichert werden. Die Berechnungsformeln zur Umrechnung der Rohdaten greifen auf diese Werte zurück.
Einstellung Feuchtemessung (Register 0xF2, nur BME280)
Dieses Register speichert das Oversampling, also die Anzahl der Einzelmessungen pro Messzyklus der Feuchtigkeitsmessung. Beim BMP280 Sensor ist diese Register ebenfalls vorhanden, hat aber keine Auswirkung.
D7|D6|D5|D4|D3 | D2|D1|D0
| Feuchtigkeitsmessung | |
|---|---|
| 000 | Keine Messung |
| 001 | 1 Messung pro Messzyklus |
| 010 | Mittelwert aus 2 Messungen |
| 011 | Mittelwert aus 4 Messungen |
| 100 | Mittelwert aus 8 Messungen |
| 101 | Mittelwert aus 16 Messungen |
| D7-D3 haben keine Verwendung |
|---|
Weitere Einstellungen (Register 0xF5)
In diesem Register wird die Zeit zwischen zwei Messzyklen eingestellt (bei Normal Mode), der IIR Filter gesteuert und die SPI Schnittstelle zwischen 3 und 4 Wire Modus umgestellt.
Der Low Pass Filter rechnet intern nach der Formel: neuer Filterwert = (alter Filterwert × (Filterfaktor - 1) + Messwert ) ÷ Filterfaktor
D7|D6|D5 | D4|D3|D2 | D1 | D0
| Standby zwischen zwei Messzyklen | |
|---|---|
| 000 | 0,5ms |
| 001 | 62,5ms |
| 010 | 125ms |
| 011 | 250ms |
| 100 | 500ms |
| 101 | 1s |
| 110 | BMP 2s / BME 10ms |
| 111 | BMP 4s / BME 20ms |
| Filter Faktor | |
|---|---|
| 000 | Filter aus |
| 001 | 2 |
| 010 | 4 |
| 011 | 8 |
| 100 | 16 |
| D1 hat keine Verwendung |
|---|
| SPI Einstellung | |
|---|---|
| 0 | Normaler SPI Modus (4-Wire) |
| 1 | 3-Wire-Interface |
Einstellung Temp.- und Druckmessung und Auswahl Betriebsmodus (Register 0xF4)
In diesem Register wird das Oversampling, also die Anzahl der Einzelmessungen pro Messzyklus sowohl für die Temperatur- als auch für die Druckmessung und der Betriebsmodus des Sensors eingestellt.
D7|D6|D5 | D4|D3|D2 | D1|D0
| Temperaturmessung | |
|---|---|
| 000 | Keine Messung |
| 001 | 1 Messung pro Messzyklus |
| 010 | Mittelwert aus 2 Messungen |
| 011 | Mittelwert aus 4 Messungen |
| 100 | Mittelwert aus 8 Messungen |
| 101 | Mittelwert aus 16 Messungen |
| Druckmessung | |
|---|---|
| 000 | Keine Messung |
| 001 | 1 Messung pro Messzyklus |
| 010 | Mittelwert aus 2 Messungen |
| 011 | Mittelwert aus 4 Messungen |
| 100 | Mittelwert aus 8 Messungen |
| 101 | Mittelwert aus 16 Messungen |
| Betriebsmodus | |
|---|---|
| 00 | Sleep Mode |
| 01/10 | Forced Mode |
| 11 | Normal Mode |
Ergebnisse Druckmessung (Register 0xF7, 0xF8, 0xF9)
Aus diesen Registern kann der Druckmesswert als Rohdaten ausgelesen werden, die noch 1. zu einem 20 Bit Wert zusammengesetzt und 2. mit der im Datenblatt angegebenen Formel und den zuvor ausgelesenen Kalibrierungswerten umgerechnet werden muss.
Ergebnisse Temperaturmessung (Register 0xFA, 0xFB, 0xFC)
Aus diesen Registern kann der Temperaturmesswert als Rohdaten ausgelesen werden, die noch 1. zu einem 20 Bit Wert zusammengesetzt und 2. mit der im Datenblatt angegebenen Formel und den zuvor ausgelesenen Kalibrierungswerten umgerechnet werden muss.
Ergebnisse Feuchtigkeitsmessung (Register 0xFC, 0xFD, nur BME280)
Aus diesen Registern kann der Feuchtigkeitsmesswert als Rohdaten ausgelesen werden, die noch 1. zu einem 16 Bit Wert zusammengesetzt und 2. mit der im Datenblatt angegebenen Formel und den zuvor ausgelesenen Kalibrierungswerten umgerechnet werden muss. BEIm BMP280 können diese Register ebenfalls ausgelesen werden. Diesen haben jedoch immer den Wert 0.
Programmcode
Zur besseren Übersichtlichkeit ist das Programm mit Hilfe einer Klasse BMx280 erstellt worden. Die Formeln zur Berechnung der Messwerte wurden ohne diese verstehen zu wollen aus dem Datenblatt übernommen.
/* Anschlusspins:
* Arduino Mega: MISO(=SDO) = 50 | MOSI(=SDA) = 51 | SCK(=SCL) = 52 | CS(=CSB) = 8
* Arduino Uno: MISO(=SDO) = 12 | MOSI(=SDA) = 11 | SCK(=SCL) = 13 | CS(=CSB) = 8
* VCC = 3,3V | GND = GND */
#include "BMx280.h" // Einbinden der erstellen Klasse
BMx280 Sensor; // Beim Erstellen des Objekts 'Sensor' wird die SPI Schnittstelle konfiguriert...
// ...und die sensorspezifischen Kaibrierungswerte ausgelesen.
void setup() {
Serial.begin(115200);
// Gibt die ausgelesenen Kaibrierungswerte zur Info aus
Sensor.printCalibrationRegisters();
// 'ctrl_hum' Register einstellen (= Feuchtigkeit Messwert aus 8 Einzelmessungen)
Sensor.registerWrite(0xF2, B00000100);
// 'ctrl_meas' Register einstellen (= Messwert T und P aus 8 Einzelmessungen, Dauermessung)
Sensor.registerWrite(0xF4, B10010011);
}
void loop() {
// Das nachfolgende Programm gibt jede Sekunde die ausgelesenen und berechneten Messwerte aus
Serial.print("Temperatur: " + String(Sensor.getTemperature()) + " *C");
Serial.print(" Luftdruck: " + String(Sensor.getPressure()) + " mBar");
Serial.println(" Luftfeuchte: " + String(Sensor.getHumidity()) + " %");
delay(1000);
}
Programmcode der Klasse BMx280.h
Der nachfolgende Programmcode der Klasse BMx280.h muss im selben Ordner gespeichert sein. Bei der geöffneten Arduino IDE erscheint er dann als zweiter Tab neben dem oberen Code.
Programmcode Bmx280.h
#include "SPI.h"
#define CS 8
class BMx280 {
private:
// Variablen enthalten die ausgelesenen Kalibrierwerte des Sensors (s. Datenblatt)
unsigned int dig_T1, dig_P1;
int dig_T2, dig_T3, dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9, dig_H2, dig_H4, dig_H5;
byte dig_H1, dig_H3, dig_H6;
// Variable der Temperaturberechnung zur Weiterverwendung bei der Druckberechnung (Temperaturkompensation)
long t_fine;
void readoutCalibrationRegisters(); // Liest die Kalibrierungswerte aus und speichert diese
public:
// Konstruktor (Initialisierungsfunktion)
BMx280() {
SPI.begin();
SPI.setDataMode(SPI_MODE0); // oder SPI_MODE3
SPI.setClockDivider(SPI_CLOCK_DIV64); // max. 10 Mhz
SPI.setBitOrder(MSBFIRST);
pinMode(CS, OUTPUT); // Chip Slect Pin für die SPI Schnittstelle definieren
readoutCalibrationRegisters();
}
// öffentliche Funktionen (Innerhalb der Klasse reicht nur Ankündigung)
void registerWrite(byte, byte); // Beschreibt ein Register (1 Byte)
byte registerRead(byte); // Liest ein Registerinhalt (1 Byte)
void printCalibrationRegisters(); // Gibt alle Sensoreigenen Kalibrierdaten auf dem seriellen Monitor aus
float getTemperature(); // Liest die T-Rohwert-Register aus und berechnet die Temperatur
float getPressure(); // Liest die P-Rohwetregister aus berechnet den Druck
float getHumidity(); // Liest die F-Rohwetregister aus berechnet die Luftfeuchtigkeit
};
byte BMx280::registerRead(byte registerAdresse) {
// Die Registeradressen sind nur 7 Bit lang. Das MSB dient als Befehl zum Lesen (=1) oder Schreiben (=0)
digitalWrite(CS, LOW); // CS (=SS) auf LOW ziehen um den Slave auszuwählen
SPI.transfer(registerAdresse); // Übernahme der Adresse des auszulesenden Registers da MSB bereits 1
byte empfangen = SPI.transfer(0xff); // Währen dem Shiften eine willkürlichen Bittfolge wird paralell über MISO ein Datenbyte empfangen
digitalWrite(CS, HIGH); // CS wieder freigeben
return empfangen;
}
void BMx280::registerWrite(byte registerAdresse, byte daten) {
/* Die Registeradressen sind nur 7 Bit lang. Das MSB dient als Befehl zum Lesen (=1) oder Schreiben (=0)
*/
digitalWrite(CS, LOW); // CS (=SS) auf LOW ziehen um den Slave auszuwählen
registerAdresse = registerAdresse - 128;
SPI.transfer(registerAdresse);
SPI.transfer(daten); // Daten die in das Register geschriebene werden sollen
digitalWrite(CS, HIGH); // CS wieder freigeben
delay(10); // Pause, damit Daten vor dem weiteren Programmablauf vollständig gespeichert sind
}
void BMx280::readoutCalibrationRegisters() {
/* Die Registeradresse wird automatisch inkrementiert (auto incremented) so dass auch die nachfolgenden Register
* ohne erneute Adressierung ausgelesen werden können. */
digitalWrite(CS, LOW); // CS (=SS) auf LOW ziehen um den Slave auszuwählen
SPI.transfer(0x88); // Adressponter auf die erste Adresse der Kalibrierungs-Register setzen
byte reg88 = SPI.transfer(0xFF); // 0x88 (dig_T1 LSB)
byte reg89 = SPI.transfer(0xFF); // 0x89 (dig_T1 MSB)
byte reg8A = SPI.transfer(0xFF); // 0x8A (dig_T2 LSB)
byte reg8B = SPI.transfer(0xFF); // 0x8B (dig_T2 MSB)
byte reg8C = SPI.transfer(0xFF); // 0x8C (dig_T3 LSB)
byte reg8D = SPI.transfer(0xFF); // 0x8D (dig_T3 MSB)
byte reg8E = SPI.transfer(0xFF); // 0x8E (dig_P1 LSB)
byte reg8F = SPI.transfer(0xFF); // 0x8F (dig_P1 MSB
byte reg90 = SPI.transfer(0xFF); // 0x90 (dig_P2 LSB)
byte reg91 = SPI.transfer(0xFF); // 0x91 (dig_P2 MSB)
byte reg92 = SPI.transfer(0xFF); // 0x92 (dig_P3 LSB)
byte reg93 = SPI.transfer(0xFF); // 0x93 (dig_P3 MSB)
byte reg94 = SPI.transfer(0xFF); // 0x94 (dig_P4 LSB)
byte reg95 = SPI.transfer(0xFF); // 0x95 (dig_P4 MSB)
byte reg96 = SPI.transfer(0xFF); // 0x96 (dig_P5 LSB)
byte reg97 = SPI.transfer(0xFF); // 0x97 (dig_P5 MSB)
byte reg98 = SPI.transfer(0xFF); // 0x98 (dig_P6 LSB)
byte reg99 = SPI.transfer(0xFF); // 0x99 (dig_P6 MSB)
byte reg9A = SPI.transfer(0xFF); // 0x9A (dig_P7 LSB)
byte reg9B = SPI.transfer(0xFF); // 0x9B (dig_P7 MSB)
byte reg9C = SPI.transfer(0xFF); // 0x9C (dig_P8 LSB)
byte reg9D = SPI.transfer(0xFF); // 0x9D (dig_P8 MSB)
byte reg9E = SPI.transfer(0xFF); // 0x9E (dig_P9 LSB)
byte reg9F = SPI.transfer(0xFF); // 0x9F (dig_P9 MSB)
digitalWrite(CS, HIGH); // CS wieder auf HIGH stellen und damit Kommunikation beenden
digitalWrite(CS, LOW);
SPI.transfer(0xA1); // Adressponter auf die Adresse der Kalibrierungs-Register setzen
byte regA1 = SPI.transfer(0xFF); // 0xA1 (dig_H1)
digitalWrite(CS, HIGH);
digitalWrite(CS, LOW);
SPI.transfer(0xE1); // Adressponter auf die erste Adresse der Kalibrierungs-Register setzen
byte regE1 = SPI.transfer(0xFF); // 0xE1 (dig_T2 LSB)
byte regE2 = SPI.transfer(0xFF); // 0xE2 (dig_T2 MSB)
byte regE3 = SPI.transfer(0xFF); // 0xE3 (dig_H3)
byte regE4 = SPI.transfer(0xFF); // 0xE4 (dig_H4[11:4])
byte regE5 = SPI.transfer(0xFF); // 0xE5 (dig_H4[3:0] = 0xE5[3:0] und dig_H5[3:0] = 0xE5[7:4]
byte regE6 = SPI.transfer(0xFF); // 0xE6 (dig_H5[11:4])
byte regE7 = SPI.transfer(0xFF); // 0xE7 (dig_H6)
digitalWrite(CS, HIGH);
// die Bytes werden an die richtige Stelle geschoben
dig_T1 = reg89 << 8 | reg88;
dig_T2 = reg8B << 8 | reg8A;
dig_T3 = reg8D << 8 | reg8C;
dig_P1 = reg8F << 8 | reg8E;
dig_P2 = reg91 << 8 | reg90;
dig_P3 = reg93 << 8 | reg92;
dig_P4 = reg95 << 8 | reg94;
dig_P5 = reg97 << 8 | reg96;
dig_P6 = reg99 << 8 | reg98;
dig_P7 = reg9B << 8 | reg9A;
dig_P8 = reg9D << 8 | reg9C;
dig_P9 = reg9F << 8 | reg9E;
dig_H1 = regA1;
dig_H2 = regE2 << 8 | regE1;
dig_H3 = regE3;
dig_H4 = regE4 << 4 | (regE5 & B00001111);
dig_H5 = regE6 << 4 | (regE5 & B11110000) >> 4;
dig_H6 = regE7;
}
void BMx280::printCalibrationRegisters() {
Serial.println("-----------------------------------");
Serial.println("Calibration Register");
Serial.println("-----------------------------------");
Serial.println("dig_T1: " + String(dig_T1));
Serial.println("dig_T2: " + String(dig_T2));
Serial.println("dig_T3: " + String(dig_T3));
Serial.println("dig_P1: " + String(dig_P1));
Serial.println("dig_P2: " + String(dig_P2));
Serial.println("dig_P3: " + String(dig_P3));
Serial.println("dig_P4: " + String(dig_P4));
Serial.println("dig_P5: " + String(dig_P5));
Serial.println("dig_P6: " + String(dig_P6));
Serial.println("dig_P7: " + String(dig_P7));
Serial.println("dig_P8: " + String(dig_P8));
Serial.println("dig_P9: " + String(dig_P9));
Serial.println("dig_H1: " + String(dig_H1));
Serial.println("dig_H2: " + String(dig_H2));
Serial.println("dig_H3: " + String(dig_H3));
Serial.println("dig_H4: " + String(dig_H4));
Serial.println("dig_H5: " + String(dig_H5));
Serial.println("dig_H6: " + String(dig_H6));
Serial.println("-----------------------------------");
}
float BMx280::getTemperature() {
// Register mit den gemessenen Rohwerten auslesen
digitalWrite(CS, LOW); // CS (=SS) auf LOW ziehen um den Slave auszuwählen
SPI.transfer(0xFA); // Adresspointer auf die erste Adresse der Temp.werte stellen
byte rohTempMSB = SPI.transfer(0xff); // Temperatur MSB (0xFA)
byte rohTempLSB = SPI.transfer(0xff); // Temperatur LSB (0xFB)
byte rohTempXLSB = SPI.transfer(0xff); // Temperatur xLSB (OxFC)
digitalWrite(CS, HIGH); // CS wieder auf HIGH stellen und damit Kommunikation beenden
// Die drei ausgelesenen Bytes werden zu einem 20 Bit Wert zusammengesetzt
long adc_T = (long)rohTempMSB << 12 | (long)rohTempLSB << 4 | (long)rohTempXLSB >> 4;
// Die komplette nachfolgende Fomrel berechnet aus dem Messwert und den zuvor ausgelesenen Kalibrierwerten...
// ...die Temperatur (s. Datenblatt)
int32_t var1, var2, T;
var1 = ((((adc_T >> 3) - ((int32_t)dig_T1 << 1))) * ((int32_t)dig_T2)) >> 11;
var2 = (((((adc_T >> 4) - ((int32_t)dig_T1)) * ((adc_T >> 4) - ((int32_t)dig_T1))) >> 12)
* ((int32_t)dig_T3)) >> 14;
t_fine = var1 + var2;
T = (t_fine * 5 + 128) >> 8;
return (float)T / 100.0f; // Umrechnung und Rückgabe in °C
}
float BMx280::getPressure() {
// Register mit den gemessenen Rohwerten auslesen
digitalWrite(CS, LOW); // CS (=SS) auf LOW ziehen um den Slave auszuwählen
SPI.transfer(0xF7); // Adresspointer auf die erste Adresse der Temp.werte stellen
byte rohDruckMSB = SPI.transfer(0xff); // Temperatur MSB (0xF7)
byte rohDruckLSB = SPI.transfer(0xff); // Temperatur LSB (0xF8)
byte rohDruckXLSB = SPI.transfer(0xff); // Temperatur xLSB (OxF9)
digitalWrite(CS, HIGH); // CS wieder auf HIGH stellen und damit Kommunikation beenden
// Die drei ausgelesenen Bytes werden zu einem 20 Bit Wert zusammengesetzt
long adc_P = (long)rohDruckMSB << 12 | (long)rohDruckLSB << 4 | (long)rohDruckXLSB >> 4;
// Die komplette nachfolgende Formrel berechnet aus dem Messwert und den zuvor ausgelesenen Kalibrierwerten...
// ...den Druck (s. Datenblatt)
int64_t var1, var2, p;
var1 = ((int64_t)t_fine) - 128000;
var2 = var1 * var1 * (int64_t)dig_P6;
var2 = var2 + ((var1 * (int64_t)dig_P5) << 17);
var2 = var2 + (((int64_t)dig_P4) << 35);
var1 = ((var1 * var1 * (int64_t)dig_P3) >> 8) + ((var1 * (int64_t)dig_P2) << 12);
var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)dig_P1) >> 33;
if (var1 == 0){
return 0; // avoid exception caused by division by zero
}
p = 1048576 - adc_P;
p = (((p << 31) - var2) * 3125) / var1;
var1 = (((int64_t)dig_P9) * (p >> 13) * (p>>13)) >> 25;
var2 = (((int64_t)dig_P8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((int64_t)dig_P7) << 4);
return (float)p / 256.0f / 100.0f; // Umrechnung und Rückgabe in mBar
}
float BMx280::getHumidity() {
// Register mit den gemessenen Rohwerten auslesen
digitalWrite(CS, LOW); // CS (=SS) auf LOW ziehen um den Slave auszuwählen
SPI.transfer(0xFD); // Adresspointer auf die erste Adresse der Feuchtewerte stellen
byte rohFeuchteMSB = SPI.transfer(0xff); // Feuchtigkeit MSB (0xFD)
byte rohFeuchteLSB = SPI.transfer(0xff); // Feuchtigkeit LSB (0xFE)
digitalWrite(CS, HIGH); // CS wieder auf HIGH stellen und damit Kommunikation beenden
// Die zwei ausgelesenen Bytes werden zu einem 16 Bit Wert zusammengesetzt
long adc_H = (long)rohFeuchteMSB << 8 | (long)rohFeuchteLSB;
// Die komplette nachfolgende Fomrel berechnet aus dem Messwert und den zuvor ausgelesenen Kalibrierwerten..
// ...die Luftfeuchtigkeit (s. Datenblatt)
int32_t v_x1_u32r, H;
v_x1_u32r = (t_fine - ((int32_t)76800));
v_x1_u32r = (((((adc_H << 14) - (((int32_t)dig_H4) << 20) - (((int32_t)dig_H5) * v_x1_u32r)) +
((int32_t)16384)) >> 15) * (((((((v_x1_u32r * ((int32_t)dig_H6)) >> 10) * (((v_x1_u32r *
((int32_t)dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + ((int32_t)2097152)) *
((int32_t)dig_H2) + 8192) >> 14));
v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) *
((int32_t)dig_H1)) >> 4));
v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
H = v_x1_u32r>>12;
return (float)H / 1024.0f; // Umrechnung und Rückgabe in %RH
}