Kampis Elektroecke

I2C Luftdrucksensor

Raspberry Pi

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:

  1. Ultra low Power
  2. Standard
  3. High resolution
  4. 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.

→ Zurück zum I2C

14 Kommentare

    1. 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

      1. 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

        1. 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

          1. Du hast es geschafft, das ich gleich schaue… :)

            sudo apt-get install python-smbus <–war die Lösung

            nun geht's!

            Grüße
            AMB

  1. 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

    1. 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

        1. 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

          1. Vielen Dank. Sobald der bestellte Sensor eingetroffen ist, werde ich das versuchen.
            Nochmals Danke
            und Gruß
            Rolf

          2. 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

  2. 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

    1. 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

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert