PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Temperatur mit BMP180 und DS18B20 entspricht nicht der Real-Temperatur



RoboTrader
03.01.2018, 11:25
Hallo, ich bin's mal wieder.
Ja, mit dem lustigen Explorer700 für den Pi taste ich mich so von Problem zu Problem. Ich habe nun die Temperatursensoren (BMP180 on board und DS18B20 aufgesteckt in 1-WIRE-Schnittstelle) ausgiebig getestet und komme auf seltsame Werte.

Beispiele zum gleichen Zeitpunkt:
a) BMP180 = 27.8°C
b) DS18B20 = 32.0°C
c) Heim-Anzeige am Barometer = 23.0°C

Und nein, ich habe da nicht selbst meine ersten Programme mit 1-WIRE & Co gebastelt, sondern nutze die reinen Beispielcodes.

Für (a) gibt es den Beispielcode:

#!/usr/bin/python

import time
from BMP180 import BMP180

# ================================================== =========================
# Example Code
# ================================================== =========================

# Initialise the BMP085 and use STANDARD mode (default value)
# bmp = BMP085(0x77, debug=True)
bmp = BMP180()

# To specify a different operating mode, uncomment one of the following:
# bmp = BMP085(0x77, 0) # ULTRALOWPOWER Mode
# bmp = BMP085(0x77, 1) # STANDARD Mode
# bmp = BMP085(0x77, 2) # HIRES Mode
# bmp = BMP085(0x77, 3) # ULTRAHIRES Mode
while True:
temp = bmp.read_temperature()

# Read the current barometric pressure level
pressure = bmp.read_pressure()

# To calculate altitude based on an estimated mean sea level pressure
# (1013.25 hPa) call the function as follows, but this won't be very accurate
altitude = bmp.read_altitude()

# To specify a more accurate altitude, enter the correct mean sea level
# pressure level. For example, if the current pressure level is 1023.50 hPa
# enter 102350 since we include two decimal places in the integer value
# altitude = bmp.readAltitude(102350)

print "Temperature: %.2f C" % temp
print "Pressure: %.2f hPa" % (pressure / 100.0)
print "Altitude: %.2f\n" % altitude
time.sleep(1)
... und die Library dazu:

import time
import smbus

# BMP085 default address.
BMP180_I2CADDR = 0x77

# Operating Modes
BMP180_ULTRALOWPOWER = 0
BMP180_STANDARD = 1
BMP180_HIGHRES = 2
BMP180_ULTRAHIGHRES = 3

# BMP085 Registers
BMP180_CAL_AC1 = 0xAA # R Calibration data (16 bits)
BMP180_CAL_AC2 = 0xAC # R Calibration data (16 bits)
BMP180_CAL_AC3 = 0xAE # R Calibration data (16 bits)
BMP180_CAL_AC4 = 0xB0 # R Calibration data (16 bits)
BMP180_CAL_AC5 = 0xB2 # R Calibration data (16 bits)
BMP180_CAL_AC6 = 0xB4 # R Calibration data (16 bits)
BMP180_CAL_B1 = 0xB6 # R Calibration data (16 bits)
BMP180_CAL_B2 = 0xB8 # R Calibration data (16 bits)
BMP180_CAL_MB = 0xBA # R Calibration data (16 bits)
BMP180_CAL_MC = 0xBC # R Calibration data (16 bits)
BMP180_CAL_MD = 0xBE # R Calibration data (16 bits)
BMP180_CONTROL = 0xF4
BMP180_TEMPDATA = 0xF6
BMP180_PRESSUREDATA = 0xF6

# Commands
BMP180_READTEMPCMD = 0x2E
BMP180_READPRESSURECMD = 0x34


class BMP180(object):
def __init__(self, address=BMP180_I2CADDR, mode=BMP180_STANDARD):
self._mode = mode
self._address = address
self._bus = smbus.SMBus(1)
# Load calibration values.
self._load_calibration()
def _read_byte(self,cmd):
return self._bus.read_byte_data(self._address,cmd)

def _read_u16(self,cmd):
MSB = self._bus.read_byte_data(self._address,cmd)
LSB = self._bus.read_byte_data(self._address,cmd+1)
return (MSB << 8) + LSB

def _read_s16(self,cmd):
result = self._read_u16(cmd)
if result > 32767:result -= 65536
return result

def _write_byte(self,cmd,val):
self._bus.write_byte_data(self._address,cmd,val)

def _load_calibration(self):
"load calibration"
self.cal_AC1 = self._read_s16(BMP180_CAL_AC1) # INT16
self.cal_AC2 = self._read_s16(BMP180_CAL_AC2) # INT16
self.cal_AC3 = self._read_s16(BMP180_CAL_AC3) # INT16
self.cal_AC4 = self._read_u16(BMP180_CAL_AC4) # UINT16
self.cal_AC5 = self._read_u16(BMP180_CAL_AC5) # UINT16
self.cal_AC6 = self._read_u16(BMP180_CAL_AC6) # UINT16
self.cal_B1 = self._read_s16(BMP180_CAL_B1) # INT16
self.cal_B2 = self._read_s16(BMP180_CAL_B2) # INT16
self.cal_MB = self._read_s16(BMP180_CAL_MB) # INT16
self.cal_MC = self._read_s16(BMP180_CAL_MC) # INT16
self.cal_MD = self._read_s16(BMP180_CAL_MD) # INT16

def read_raw_temp(self):
"""Reads the raw (uncompensated) temperature from the sensor."""
self._write_byte(BMP180_CONTROL, BMP180_READTEMPCMD)
time.sleep(0.005) # Wait 5ms
MSB = self._read_byte(BMP180_TEMPDATA)
LSB = self._read_byte(BMP180_TEMPDATA+1)
raw = (MSB << 8) + LSB
return raw

def read_raw_pressure(self):
"""Reads the raw (uncompensated) pressure level from the sensor."""
self._write_byte(BMP180_CONTROL, BMP180_READPRESSURECMD + (self._mode << 6))
if self._mode == BMP180_ULTRALOWPOWER:
time.sleep(0.005)
elif self._mode == BMP180_HIGHRES:
time.sleep(0.014)
elif self._mode == BMP180_ULTRAHIGHRES:
time.sleep(0.026)
else:
time.sleep(0.008)
MSB = self._read_byte(BMP180_PRESSUREDATA)
LSB = self._read_byte(BMP180_PRESSUREDATA+1)
XLSB = self._read_byte(BMP180_PRESSUREDATA+2)
raw = ((MSB << 16) + (LSB << 8) + XLSB) >> (8 - self._mode)
return raw

def read_temperature(self):
"""Gets the compensated temperature in degrees celsius."""
UT = self.read_raw_temp()
# Datasheet value for debugging:
# UT = 27898
# Calculations below are taken straight from section 3.5 of the datasheet.
X1 = ((UT - self.cal_AC6) * self.cal_AC5) >> 15
X2 = (self.cal_MC << 11) / (X1 + self.cal_MD)
B5 = X1 + X2
temp = ((B5 + 8) >> 4) / 10.0
return temp

def read_pressure(self):
"""Gets the compensated pressure in Pascals."""
UT = self.read_raw_temp()
UP = self.read_raw_pressure()
# Datasheet values for debugging:
#UT = 27898
#UP = 23843

X1 = ((UT - self.cal_AC6) * self.cal_AC5) >> 15
X2 = (self.cal_MC << 11) / (X1 + self.cal_MD)
B5 = X1 + X2

# Pressure Calculations
B6 = B5 - 4000
X1 = (self.cal_B2 * (B6 * B6) >> 12) >> 11
X2 = (self.cal_AC2 * B6) >> 11
X3 = X1 + X2
B3 = (((self.cal_AC1 * 4 + X3) << self._mode) + 2) / 4

X1 = (self.cal_AC3 * B6) >> 13
X2 = (self.cal_B1 * ((B6 * B6) >> 12)) >> 16
X3 = ((X1 + X2) + 2) >> 2
B4 = (self.cal_AC4 * (X3 + 32768)) >> 15
B7 = (UP - B3) * (50000 >> self._mode)

if B7 < 0x80000000:
p = (B7 * 2) / B4
else:
p = (B7 / B4) * 2
X1 = (p >> 8) * (p >> 8)
X1 = (X1 * 3038) >> 16
X2 = (-7357 * p) >> 16

p = p + ((X1 + X2 + 3791) >> 4)
return p

def read_altitude(self, sealevel_pa=101325.0):
"""Calculates the altitude in meters."""
# Calculation taken straight from section 3.6 of the datasheet.
pressure = float(self.read_pressure())
altitude = 44330.0 * (1.0 - pow(pressure / sealevel_pa, (1.0/5.255)))
return altitude

def read_sealevel_pressure(self, altitude_m=0.0):
"""Calculates the pressure at sealevel when given a known altitude in
meters. Returns a value in Pascals."""
pressure = float(self.read_pressure())
p0 = pressure / pow(1.0 - altitude_m/44330.0, 5.255)
return p0

Hier der Code zu (b):

#!/usr/bin/python
# -*- coding:utf-8 -*-
import os
import glob
import time

os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')

base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'
def read_rom():
name_file=device_folder+'/name'
f = open(name_file,'r')
return f.readline()

def read_temp_raw():
f = open(device_file, 'r')
lines = f.readlines()
f.close()
return lines

def read_temp():
lines = read_temp_raw()
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
temp_c = float(temp_string) / 1000.0
temp_f = temp_c * 9.0 / 5.0 + 32.0
return temp_c, temp_f

print(' rom: '+ read_rom())
while True:
print(' C=%3.3f F=%3.3f'% read_temp())
time.sleep(1)

Ich teste später auch zum Vergleich noch den DHT22. Bin sehr gespannt. Aber gerade der BMP180 wäre eben praktisch mit seinen Werten, da "on board" und somit für schnelle Messungen klasse.

Vielleicht sieht jemand sofort, woran es mangelt oder was ich beachten muss!?
Ich habe auch bei meiner Zusammenstellung beider Codes und Anzeige auf dem OLED die gleichen Unterschiede ...

Danke und einen tollen Mittwoch!

- - - Aktualisiert - - -

Also, der DHT22 mit dem Adafruit-Code fast wie in diesem Tutorial (https://tutorials-raspberrypi.de/raspberry-pi-luftfeuchtigkeit-temperatur-messen-dht11-dht22/) (nur 3 Pins am DHT22, daher direkt 3.3V, GND und Daten-Pin und mit python3 aufgerufen), erhalte ich:

T = 25.5

Hier nochmal zu einem Zeitpunkt alle Daten:

Tdht = 25.3
Thumidity = 40.0%
Tds = 28.437
Tbmp = 32.1
Tbmp_press = 984.16
Tbmp_alt = 244.797

Und das alte Zeigermodell: T=23 Press=996 Humidity=48.5%

Hm, sind hier am Arbeitsplatz nun 23, 25, 28 oder 32°C? :D

- - - Aktualisiert - - -

Ja, nun habe ich das OLED aussen vor gelassen und nur eine reine Ausgabe aller Sensoren programmiert. Gleiches Ergebnis, irgendetwas stimmt nicht in den Quell-Libraries oder es sind doch die Sensoren fehlerhaft - wie ich hier im Forum nachlesen konnte:


T[DS18B20] = 28.062 C
T[BMP180] = 32.0 C
Pressure = 985.11 hPa
Altitude = 237.2131959795308 m
T[DHT22] = 25.5 C
Humidity = 39.0%

Rabenauge
03.01.2018, 23:14
Mein BMP gibt auch ein bisschen mehr aus- liegt bei mir an der Einbausituation: da ich den für nix vernünftiges mehr nutze (ich nehm inzwischen lieber die BME, weil die die Luftfeuchte auch können), hab ich ihn zusammen mit allem möglichen anderen Kram auf ein Proto-Shield für Arduino gelötet.
Nun sitzt der praktisch fast genau über dem Hauptprozessor- mit nem Zentimeter Abstand.
Schalt ich das Ding ein, haut es ne Weile hin, danach steigt die Temperatur durchaus um einige Grad...irgendwann hört das dann aber auf, weil die Temperatur der Bauteile wohl nur nen gewissen Wert erreicht. Im Dauerbetrieb könnte man das einfach mit nem Offset erschlagen.

An der Wetterstation den BME hab ich deshalb so angeordnet, dass er am tiefsten (und quasi frei hängend) auf der Platine sitzt (warme Luft steigt rauf...), und da die Platine senkrecht steht, bekommt er von unten immer frische Luft.
So funktioniert es dann.

Der DHT22 (hab ich neben dem BMP hocken, eben weil der die Feuchte nich kann) hat übrigens genau das selbe Problem- aber die Dinger sind weit weniger genau als die Bosch-Sensoren.
Wenn du Spass haben willst, besorg dir mal nen DHT 11- während die 22er immerhin noch halbwegs schätzen können, wird im 11er scheinbar intern gewürfelt. :)

RP6conrad
06.01.2018, 13:03
Mit den DS18B20 habe ich sehr gute Erfahrungen.Sowohl mit auslesen mit eine Python lib auf den Pi, wie mit Arduino (ESP, Wemos D1). Die Temperaturen sind immer +/- 0,5°C gleich an andere Messmethoden.

RoboTrader
06.01.2018, 13:16
Danke euch für die Erfahrungen!

Heisst also, dass der Code des Herstellers in Ordnung ist, aber ich versuchen sollte, die Sensoren weiter entfernt oder eben unter der Wärmeentwicklung zu platzieren?
Und dann wirklich ein DS18B20 besser misst als ein BMP180 und dieser wiederum besser als der DHT22?

Dennoch wären mir die 28°C des DS18B20 zu warm ... ;)
Ich versuche die Entfernungsvariante.

Rabenauge
06.01.2018, 17:23
Nö- der DS ist keineswegs besser.
Er hat andere Vorteile 1-Wire-Bus)- aber genauerwird der auch nicht sein. Dafür ist die Handhabung etwas kniffeliger.
Leg mal _irgendein_ Thermometer auf die Heizung, und versuch dann, die wirkliche Raumtemperatur zu ermitteln- das wird mit _keinem_ klappen.
Insofern ist es egal, welchen du benutzt.
Jeder misst nur seine Umgebung, und wenn da ne kleine Wärmequelle in der Nähe ist, misst er eben Mist.
Die Bosch-Sensoren sind hervorragend (meiner Meinung nach im Bastelsegment das Beste, was man derzeit kriegen kann), da sie eben noch mehr als nur Thermometer sind.
Und die messen schon genau....da kann ich absolut nix gegen sagen

Ob der Maxim theoretisch noch genauer kann, da musst du dich mal durch die Datenblätter wühlen, ich hab hier drei Bosch (2xBME und einmal den BMP, den aber mit dem Offset, wegen der blöden Einbausituation), die geben nen Unterschied von maximal 0.1 Grad aus....das wird dann wohl hin hauen.

Im Grunde isses bei jedem Thermometer so: willst du die wirkliche Aussentemperatur messen, muss das Ding nen Meter von der Hauswand weg.
Und: wen juckt denn ein halbes Grad- viel interessanter finde ich, zu sehen, ob die Temperatur steigt oder fällt (zeigt mein Thermometer auch an), das halbe Grad Unterschied hat man gewöhnlich schon zwischen Fussboden-und Tischhöhe.

HaWe
06.01.2018, 17:33
ich habe jetzt ein paar Tage lang die Bosch BMP280 gegen DHT22 gemessen, 50cm vom Board entfernt (nodeMCU), direkt nebeneinander, und hatte höchstens 0,7°C Unterschied.

RoboTrader
06.01.2018, 17:58
Danke. Insbesondere für eure immer ausführlichen Antworten. So verstehe ich das Handling und Thema viel besser!

Wenn ich das richtig verstehe, dann könnte man mit einem Offset die "zu heiße Situation" ausgleichen und die Temperaturunterschiede messen (insbesondere für den "onboard"-Sensor, der exakt den gleichen Abstand zur Wärmequelle behält). In meinem Fall wäre das:


T[Analoges Messgerät] = 23°C

T[DS18B20] = 28.062°C -5°C =23°C
T[BMP180] = 32.0°C -9°C =23°C
T[DHT22] = 25.5 C -2.5°C =23°C

Somit wäre der Offset für den DS18B20 -5, für den BMP180 -9 und für den DHT22 -2.5.
Damit würdet ihr arbeiten?
Oder sollte ich mir die Referenz an anderer Stelle suchen?

Und was meint ihr zu Pressure, Altitude und Humidity? Alle 3 sind auch ziemlich unterschiedlich zu meinem analogen Messgerät.


Pressure = 985.11 hPa
Altitude = 237.2131959795308 m
Humidity = 39.0%

Da dürfte doch die Wärme keine Rolle spielen, oder?

Grüße in einen schönen Samstagabend!

- - - Aktualisiert - - -

Habe gerade nochmal über die Offsetwerte nachgedacht.
Die machen vielleicht wirklich Sinn:

BMP180 - onboard > -9
DS18B20 - aufgesteckt als 1-Wire, somit etwa 0.5cm vom Board entfernt > -5
DHT22 - mit diesen typischen Kabeln an den GPIOs, somit etwa 4cm entfernt > -2.5

HaWe
06.01.2018, 18:34
offset nur, wenn du die Sensor-Temperaturen mit einem direkt benachbarten und geeichten Thermometer über weitere Temperaturbreiche abgeglichen hast. Aber mit einem Onboard-Sensor wirst du immer nur die Onboard-Temperatur messen, niemals die exakte Umgebungstemperatur, das muss dir klar sein, denn sie wird bei -20° bis +80° bei unterschiedlichen Luftströmungen in unkalkulierbarer Weise verfälscht, und es würden im besten Falle höchstens Eichkurven etwas verbessern, samt Ventilator, keinesfalls konstante Offsets.

RoboTrader
06.01.2018, 18:40
Danke, so etwas dachte ich zunächst auch. Das kann kaum eine lineare Abhängigkeit sein.
Vielleicht nehme ich mir einige Referenzwerte und wandere mit den 3 Sensoren auf einen schneebedeckten Berg, in eine Sauna und so 5 Werte dazwischen. Dann dürft sich etwas ergeben.

Wollte schon lange die Polynom-Funktion der numpy-Bibliothek testen! :)

RoboHolIC
06.01.2018, 19:15
@HaWe:
Danke! Du hast das was ich auch schon zu formulieren versuchte und wieder verworfen habe, treffend auf den Punkt gebracht.

@RoboTrader:
Nein :nö:. Mit der Polynom-Funktion kannst du einen nichtlinearen Sensor bestimmt trefflich auswerten.
Aber du kannst aber eine methodisch falsche Messung mit unbekannten Einflussfaktoren damit nicht ausbügeln. Optimiere deine Messanordnung und du kommst in den Genuss der guten, herstellerseitigen Kalibrierung der Sensoren.
OK, beim Onboard-BMP180 ist dahingehend natürlich nichts mehr zu machen.

Die Schneewanderung solltest du trotzdem machen \\:D/

Rabenauge
06.01.2018, 22:42
Die Luftdruck-Angabe meines BME ist sehr genau.
Ich hab ein Garmin GPS mit barometrischen Höhenmesser hier (keine Ahnung, was das genau für einer ist), der stimmt mit dem BME sehr genau überein.
Zumindest, wenn ich den gemessenen Luftdruck ausgebe (mach ich normal nicht, da auch die Wetterfrösche den auf Meeresniveau angeben), passt das.
Auch beim BMP. Du sagst "analoges Gerät"- hast du ein "altes" mit Dose oder sowas? Die Dinger müssen auch justiert werden, auf die genaue Höhe (und zeigen trotzdem nicht ganz exakt, weil der Luftdruck _nicht nur_ von der Höhe abhängt.

Die Temperatur und der Offset: bei meinem (dem, der geheizt wird) läuft es so, dass der ganz zu Anfang stimmt. Aber dann steigt er binnen einiger Stunden (um runde 3 Grad), bleibt dann aber wiederum so.
Betrifft aber den Luftdruck nicht, der stimmt!

Man könnte, mit ner Referenz, einige Werte zwischendrin aufnehmen, und daraus ne Art Graphen erstellen, so dass man ne ganze Reihe Korrekturwerte über die Zeit hat. Oder einfach den Sensor erstmal ignorieren (so mache ich das, da es ne reine Bastelplatine mit allem möglichen Kram drauf ist), bis alles warmgelaufen ist, und dann halt die 3 Grad einfach abziehen.
Alternative: viele Chips (z.B. die DS3231, aber auch die Arduino-Prozessoren selber) haben einen Temperatursensor eingebaut.
Eventuell kann man auch damit ne Korrektur stricken...wobei ich bei der 3231 _weiss_ dass auch die sich erwärmt- und der Temperatursensor das natürlich mit misst.
Wäre mir alles zu wackelig, ehrlich gesagt.
Daher ist es am sinnvollsten, so einen Sensor entsprechend anzuordnen: Wärme steigt nach oben. Wenn ich also das Layout so baue, dass er "ganz unten" angeordnet ist (am besten der reine Sensor, denn auf dem Breakout sind auch Widerstände oder gar Spannungsregler, die auch warm werden könnten), und von unten auch ausreichend frische Luft nachströmen kann, dürfte man der Wirklichkeit ziemlich nahe kommen.

Und zum Schluss "vermittele" ich das Ergebnis sowieso noch, weil es nervt, wenn die Anzeige sich nahezu pausenlos ändert, ungefähr so:

temp=(tempGemessen*0.7)+(tempVorherGemessen*0.3).

Dann ändert sich nicht alle Sekunden was- und das Ergebnis bleibt immernoch ausreichend genau.
Ich zeichne den Temperaturverlauf auch auf, über 24 Stunden, da kann man später an den Graphen trotzdem noch ablesen, wann ich mal die Tür kurz offen hatte. :cool:
Beim Luftdruck ist es übrigens ganz ähnlich: wenn man nicht gerade nen präzisen Höhenmesser braucht (den man allerdings auch vor jeder Messung kalibrieren muss), ist der tatsächliche Wert nicht sehr nützlich- der Verlauf ist interessant!
Damit kann man schon bisschen Prognosen stricken, der reine Wert dagegen sagt so gut wie nichts.

Das mit dem Höhenmesser hab ich allerdings auch noch vor- ich will mal so einen BMx in ne Modellrakete stecken...dauert aber noch.

Da ich aber nun von ausgehe, dass, wenn der BME Temperatur und Luftdruck sehr genau ausgibt, auch die Luftfeuchte stimmen wird, und man eben alles zusammen in einem Kästchen hat (und das auch noch super bequem per I2C auslesen kann) ist das Ding einfach meine beste Wahl.
Für alle Fälle kann man den BME (den BMP bestimmt auch, nur vom BME hatte ich neulich erst das Datenblatt vor der Nase) auch wieder "justieren"- z.B. wenn er mal abgesoffen ist.
Geht übrigens bei den DHT-Sensoren auch...

wkrug
07.01.2018, 08:40
Wenn ich mich da auch nur Dunkel daran erinnere...
Gab's da nicht mal ein Problem das es DS18B20 gelabelte Sensoren, die aber eigentlich DS18S20 waren?
Das Temperaturregister hat dabei unterschiedliche Auflösungen, was deine Temperaturabweichung auch erklären würde.

Ist zwar schon ein paar Jahre her, hatte da aber auch mal ein Problem.

HaWe
07.01.2018, 09:37
@Rabenauge:

temp=((tempGemessen*0.7)+(tempVorherGemessen*0.3)/2).
der Lowpassfilter (gleitender Durchschnitt) in der Art

tempd=(tempGemessen*0.7)+(tempd*0.3) // Aktualisierung des gleitenden Durchschnitts tempd
macht Sinn, das stimmt, aber ohne die /2

@Robotrader:
wenn du eine genaue Raumtemp. willst, dann miss sie nicht auf dem Shield mit ominösen Schätzfaktoren, sondern spendiere ein paar EUR für einen externen Sensor (BME280 z.B.) und miss dann genau dort, wo es maßgeblich ist und wo es darauf ankommt !

Rabenauge
07.01.2018, 10:50
Ups- hast recht. Das kommt davon, wenn man einfach ausm Kopf tippt. :D
Danke für den Hinweis-ich habs korrigiert.