Hier zeige ich, wie ein BMP085 Luftdrucksensor an den I2C Bus des Raspberry Pi angeschlossen und ausgelesen werden kann. Dieser Sensor ist in der Lage die Temperatur und den Druck zu messen und mit Hilfe verschiedener Kalibrationswerte kann daraus dann der Druck berechnet werden. Zudem besitzt der Sensor vier Betriebsmodi:
- Ultra low Power
- Standard
- High resolution
- Ultra high resolution (verwendeter Modus)
Der Betriebsmodi beeinflusst die Messzeit ziemlich stark und kann im späteren Programm durch die Variable oss eingestellt werden.
Beschaltung des Sensors:
Der Sensor stellt zudem noch einen EOC-Pin (End of Conversion) bereit, der auf High gezogen wird, sobald eine Messwerterfassung abgeschlossen ist. Falls ein fertiges Modul verwendet wird (so wie ich es getan habe), sieht die Beschaltung folgendermaßen aus:
Pull-up Widerstände sind nicht notwendig, da sie sich bereits auf dem Board befinden. Der EOC-Pin wird mit dem GPIO 4 des Raspberry Pi verbunden.
Das Python-Skript:
Bevor der Sensor messen kann, müssen 11 16-Bit Kalibrierungswerte aus dem EEPROM geladen werden.
Da diese Werte zum größten Teil Vorzeichenbehaftet sind, habe ich zwei Unterprogramme geschrieben:
- Eins zum Auslesen von Vorzeichenbehafteten Werten
- Eins zum Auslesen von Werten ohne Vorzeichen:
def ReadSInt(Device, Adresse): MSB = Bus.read_byte_data(Device, Adresse) LSB = Bus.read_byte_data(Device, Adresse + 1) if(MSB > 127): MSB = MSB - 256 Data = (MSB << 8) + LSB return Data def ReadUInt(Device, Adresse): MSB = Bus.read_byte_data(Device, Adresse) LSB = Bus.read_byte_data(Device, Adresse + 1) Data = (MSB << 8) + LSB return Data
Diese Unterprogramme lesen, angefangen bei der übergebenen Adresse, zwei Datenbytes aus und fügen diese zu einem 16-Bit Wert zusammen. Das erste Unterprogramm prüft vorher aber noch ob das höchstwertige Bit des höchstwertigen Bytes eine High ist. Ist dies der Fall, dann ist die Zahl negativ und das Byte wird durch eine Subtraktion mit 256 in den negativen Bereich umgerechnet. Die fertigen 16-Bit Werte werden anschließend zurück in das Hauptprogramm übergeben.
Der nächste Schritt ist dann das Auslesen der Kalibrationswerte.
def ReadCal(Device): Data = {} AC1 = ReadSInt(Device, 0xAA) AC2 = ReadSInt(Device, 0xAC) AC3 = ReadSInt(Device, 0xAE) AC4 = ReadUInt(Device, 0xB0) AC5 = ReadUInt(Device, 0xB2) AC6 = ReadUInt(Device, 0xB4) B1 = ReadSInt(Device, 0xB6) B2 = ReadSInt(Device, 0xB8) MB = ReadSInt(Device, 0xBA) MC = ReadSInt(Device, 0xBC) MD = ReadSInt(Device, 0xBE) Data.update({"AC1": AC1}) Data.update({"AC2": AC2}) Data.update({"AC3": AC3}) Data.update({"AC4": AC4}) Data.update({"AC5": AC5}) Data.update({"AC6": AC6}) Data.update({"B1": B1}) Data.update({"B2": B2}) Data.update({"MB": MB}) Data.update({"MC": MC}) Data.update({"MD": MD}) return Data
Es werden alle Registerpaare, die Kalibrationswerte enthalten, ausgelesen und der Wert wird in einer gleichnamigen Variable gespeichert. Hier bei muss unbedingt auf das Vorzeichen geachtet werden, da die Werte sonst falsch sind und nachher die Rechnung nicht stimmt. Anschließend speichere ich die Kalibrationsdaten in einem Dictionary mit dem dazu gehörigen Namen als Schlüssel, welches ich dann an das Hauptprogramm übergebe.
Im nächsten Schritt werden die Rohdaten ausgelesen. Als aller erstes lese ich die Temperaturdaten aus:
def ReadTemp(Device): Temp = 0 Bus.write_byte_data(Device, 0xF4, 0x2E) while GPIO.input(EOC) == 0: pass Temp = ReadUInt(Device, 0xF6) return Temp
Das Unterprogramm schreibt als erstes den Hexwert 0x2E in das Controlregister, welches die Adresse 0xF4 besitzt.
Dadurch wird eine Temperaturmessung ausgelöst und das Programm wartet dann, bedingt durch die While-Schleife, so lange bis der EOC-Pin auf High liegt, sprich die Messung abgeschlossen ist.
Sobald die Messung abgeschlossen ist ließt das Programm den 16-Bit Temperaturwert aus und speichert ihn unter Temp. Dieser Wert wird dann in das Hauptprogramm übergeben und unter der Variable UT gespeichert. Im nächsten Schritt erfolgt die Druckmessung:
def ReadPres(Device, oss): Pressure = 0 Bus.write_byte_data(Device, 0xF4, (0x34 + (oss << 6))) while GPIO.input(EOC) == 0: pass MSB = Bus.read_byte_data(Device, 0xF6) LSB = Bus.read_byte_data(Device, 0xF7) XLSB = Bus.read_byte_data(Device, 0xF8) Pressure = ((MSB << 16) + (LSB << 8) + XLSB) >> (8 - oss) return Pressure
Das Unterprogramm ist nahezu identisch wie das der Temperaturmessung, bis auf die Ausnahme, dass zum Auslösen einer Druckmessung eine 0x34 + den Betriebsmodus in das Controlregister geschrieben werden muss und das der Druckwert aus drei Bytes besteht, die ein bisschen anders zusammen gerechnet werden.
Die Unterprogramme CalTemp(), CalPres() und CalAltitude() berechnen dann aus den Temperatur und Druckwerten zusammen mit den Kalibrationswerten den Luftdruck, die Temperatur und die Höhe über dem Meeresspiegel.
Eine Erklärung spare ich mir an dieser Stelle, da ich einfach nur die Formel aus dem Datenblatt (Seite 13) abgetippt habe. Die berechneten Werte werden dann anschließend in der Konsole ausgegeben:
Das Beispielprogramm ist für mein 256 MB Raspberry Pi geschrieben. Wenn das Programm auf dem 512er Pi genutzt werden soll, muss die I2C-Schnittstelle entsprechend angepasst werden.
Das komplette Python-Skript ist in meinem GitHub-Repository zum Download verfügbar.
Hi Daniel,
Wo schließt Du am Raspberry Pi den EOC Pin des Sensors an?
Hab ich das in Deiner Anleitung überlesen?
Gruß
AMB
Hey,
im Text steht das (glaube) ich nicht. Aber wenn du dir mal meinen Quelltext anschaust, siehst du das ich ihn an GPIO 4 des Raspberry Pi angeschlossen habe.
Gruß
Daniel
Hi Daniel,
Danke für die schnelle Antwort!
So hatte ich es auch interpretiert, und ausprobiert.
Hat aber nicht geklappt.
Scheint wohl noch eine anderes Problem vorzuliegen.
Ich mach mich die Tage mal auf die Suche.
Und – gute Seite die Du da aufgezogen hast.
Ich schau immer mal wieder gerne rein!
Gruß
AMB
Hey,
danke für das Lob :)
Du kannst mal mittels
i2cdetect -y 0/1
schauen ob der Sensor am Bus erkannt wird (wenn du eine 512MB Variante hast, musst du statt 0/1 einfach 1 schreiben).
Bei 0x77 sollte dann der Sensor stehen.
Ansonsten beschreib den Fehler mal genauer. Dann kann ich dir helfen :)
Gruß
Daniel
Du hast es geschafft, das ich gleich schaue… :)
sudo apt-get install python-smbus <–war die Lösung
nun geht's!
Grüße
AMB
Hey,
sehr gut :)
Freut mich das es nun funktioniert.
Viel Spaß mit dem Sensor!
Gruß
Daniel
Hallo Daniel,
wieder eine tolle und gut verständliche Anleitung, vielen Dank.
Eine (Anfänger)-Frage habe ich noch:
Wie erreiche ich es, dass das Ergebnis nicht nur in der Konsole ausgegeben wird , sondern auch in eine text-Datei geschrieben wird?
Vielen Dank
Rolf
Hallo Rolf,
du kannst z.B. ein >> /Pfad/MeineDatei.txt hinter den Aufruf hängen. Dann werden alle Ausgaben in die Datei umgeleitet oder du machst das direkt über Dateioperationen, also open(), write() und close().
Falls du weitere Hilfe brauchst sag einfach Bescheid :)
Gruß
Daniel
Wäre e es so richtig:
print „Luftdruck: “ + str(Pressure) + “ hPa“ /Pfad/MeineDatei.txt ?
Hey,
ne. Entweder so:
$ python /Luftdruck.py >> /tmp/MeinText.txt
Oder direkt im Programm:
Datei = open(„/tmp/MeinText.txt“, „w“)
Datei.write(print „—————————————-„)
Datei.write(„…..“)
Datei.write(„…..“)
Datei.write(„…..“)
Datei.close()
Gruß
Daniel
Vielen Dank. Sobald der bestellte Sensor eingetroffen ist, werde ich das versuchen.
Nochmals Danke
und Gruß
Rolf
Hey,
kannst dich ja schon mal etwas damit vertraut machen :)
Es funktioniert im Grunde wie eine Konsolenausgabe (nachdem du die Datei geöffnet hast).
Gruß
Daniel
Hallo guten Tag Rolf,
bin auch dabei eine Wetterstation einzurichten. Deine Seite hat mir bez. bmp180 sehr geholfen. Wie vorgesehen werden Daten ausgegeben.
– Temperatur: 40.57 C
– Luftdruck: 818.916 hPa
– Altitude: 1760.38
Habe leider bisher nicht erkannt, ob ich in Deinem Programm eine Anpassung auf meinen Wohnort vornehmen kann oder eine Rechnung außerhalb erfolgen muss. Altitude für meinem Wohnort Between 90 and 110 m.
Gruß Bodo
Hallo Bodo,
eine Anpassung an den Wohnort kann man bei dem Programm nicht machen, da die Werte alle aus den Sensorwerten berechnet werden.
Ggf. habe ich bei der Formel einen Fehler gemacht?
Gruß
Daniel