Hallo,
neben der Heizungssteuerung ist die Wetterstation ja eines der beliebtesten Bastelprojekte
An anderer Stelle hier im Forum wurde der HP03S und der HH10D angesprochen, die durch den i2c Bus ideale Sensoren für den Pi sind.
Ich habe mich auch mit dem HP03S beschäftigt und möchte das Ergebnis hier vorstellen.
Hardware:
Beim HP03S gibt es zwei Besonderheiten zu beachten, damit man ihn am i2c Bus betreiben kann.
1) über einen GPIO Pin muss dem Sensor mitgeteilt werden, ob der ADC aktiv ist oder das EEPROM mit den Kalibrierungsdaten.
Der Pin muss auf LOW liegen, um die EEPROM Daten auszulesen und auf HIGH, um den ADC zu aktivieren. Das erledigt man am
sinnvollsten über einen GPIO
2) Der Sensor benötigt für den ADC ein Taktsignal von 32kHz. Der genaue Takt soll eher unkritisch sein (zw. 30 und 35 kHz) aber der
Stromverbrauch wird geringer, je steiler die Flanken des Taktsignals sind. Ich habe hierfür eine Anregung von Orb aus einem anderen Thema
übernommen (Off-Topic/selber löten/Betrag 22 - hab noch nicht herausgefunden, wie man das direkt verlinken kann :-)) und den Takt mit einem
4001 4 fach NOR und einem Uhrenquarz erzeugt. Der 4001 kostet knappe 10ct, der Uhrenquarz ca 25ct.
Software:
EEPROM lässt sich mit i2cget und i2cdump von der Kommandozeile auslesen, Den ADC bedient man am besten per Programm, zumal man ja
auch noch rumrechnen muss, um die gewünschten Werte zu erhalten.
Hier der Code:
Es ist da möglicherweise noch ein Fehler drin. Der Luftdruck ist zwar in einem plausiblen Bereich, kommt mir aber viel zu niedrig vor. (995 hPa, während
die nahe Wetterstation 1022 hPa meldet)
Temperatur hingegen scheint 100% korrekt rüberzukommen.
# -*- coding: iso-8859-1 -*-
import smbus
import RPi.GPIO as GPIO
from time import sleep
class hp03s:
# Initialisierung:
# Übergabe von Bus (0 oder 1, 0 default)
# und Port für XCLR Leitung (Default 25: Dritter Pin von rechts oben)
def __init__(self,busno=0,xclrpin=25):
self.bus=smbus.SMBus(busno)
self.control=0x50
self.data=0x77
GPIO.setmode(GPIO.BCM)
self.xclr=xclrpin
GPIO.setup(self.xclr,GPIO.OUT)
self.C1=self.getParam(0x10,0x11)
self.C2=self.getParam(0x12,0x13)
self.C3=self.getParam(0x14,0x15)
self.C4=self.getParam(0x16,0x17)
self.C5=self.getParam(0x18,0x19)
self.C6=self.getParam(0x1a,0x1b)
self.C7=self.getParam(0x1c,0x1d)
self.A=self.getParam(0x1e)
self.B=self.getParam(0x1f)
self.C=self.getParam(0x20)
self.D=self.getParam(0x21)
# Destructor:
# Freigabe des Portpins
def __del__(self):
GPIO.cleanup()
# Kann raus, diente zum Prüfen, ob der richtige GPIO Pin
# angeschlossen ist.
def testXCLR(self):
for i in range(10000):
GPIO.output(self.xclr,GPIO.HIGH)
GPIO.output(self.xclr,GPIO.LOW)
def xclrLOW(self):
GPIO.output(self.xclr,GPIO.LOW)
def xclrHIGH(self):
GPIO.output(self.xclr,GPIO.HIGH)
# Lesen eines ROM Parameters:
# Bei Angabe von 2 Adressen werden beide ausgelesen und Inhalt als Integer
# zurückgegeben. Wird nur ein Parameter angegeben erfolgt Rückgabe als Byte
# Verwendung siehe __init__
def getParam(self,p1,p2=0):
self.xclrLOW()
pa=self.bus.read_byte_data(self.control,p1)
if p2!=0:
pb=self.bus.read_byte_data(self.control,p2)
return(pa*256+pb)
else:
return(pa)
# Liesst den Sensorwert für Druck aus dem ADC aus dem der tatsächliche Druck berechnet
# werden kann
def getRawPressure(self):
self.xclrHIGH()
#sleep(0.5)
self.bus.write_byte_data(self.data,0xff,0xf0)
sleep(0.05)
self.bus.write_byte(self.data,0xfd)
a=self.bus.read_byte(self.data)
b=self.bus.read_byte(self.data)
self.xclrLOW()
return(a<<8|b)
# Liesst den Sensorwert für Temperatur aus dem ADC, aus dem die tatsächliche Temperatur
# berechnet werden kann
def getRawTemperature(self):
self.xclrHIGH()
#sleep(0.5)
self.bus.write_byte_data(self.data,0xff,0xe8)
sleep(0.05)
self.bus.write_byte(self.data,0xfd)
a=self.bus.read_byte(self.data)
b=self.bus.read_byte(self.data)
self.xclrLOW()
return(a*256+b)
# Liesst die Sensorwerte und berechnet die Temperatur
# Rückgabe als Float
def getTemperature(self):
D2=self.getRawTemperature()
D1=self.getRawPressure()
if (D2>=self.C5):
dUT=D2-self.C5-((D2-self.C5)/128)*((D2-self.C5)/128)*self.A/2**self.C
else:
dUT=D2-self.C5-((D2-self.C5)/128)*((D2-self.C5)/128)*self.B/2**self.C
OFF=(self.C2+(self.C4-1024)*dUT/2**14)*4
SENS=self.C1+self.C3*dUT/2**10
X=SENS*(D1-7168)/2**14-OFF
P=X*10/2**5+self.C7
T=250+dUT*self.C6/2**16-dUT/2**self.D
return(T/10.0)
# Liesst die Sensorwerte und berechnet den Druck
# Rückgabe als Float
def getPressure(self):
D2=self.getRawTemperature()
D1=self.getRawPressure()
if (D2>=self.C5):
dUT=D2-self.C5-((D2-self.C5)/128)*((D2-self.C5)/128)*self.A/2**self.C
else:
dUT=D2-self.C5-((D2-self.C5)/128)*((D2-self.C5)/128)*self.B/2**self.C
OFF=(self.C2+(self.C4-1024)*dUT/2**14)*4
SENS=self.C1+self.C3*dUT/2**10
X=SENS*(D1-7168)/2**14-OFF
P=X*10/2**5+self.C7
T=250+dUT*self.C6/2**16-dUT/2**self.D
return(P/10.0)
Alles anzeigen
Und hier ein kleines Testprogramm:
import hp03s
# Neues hp03s Objekt i2c Bus 0 und XCLR Pin=25
hp=hp03s.hp03s(0,25)
p=hp.getPressure()
t=hp.getTemperature()
print "Pressure="+str(p)
print "Temp="+str(t)
Alles anzeigen
So, das wars erst mal. Vielleicht hat ja jemand eine Ahnung, woran das mit dem zu geringen Luftdruck liegen könnte
Gruß
Odin