HH10D mit Atmega8 auslesen

Erstellt am 13.05.2012

Wandeln und Lesen

Für mein aktuelles Projekt, eine Lüfter- und Lüftungssteuerung im Keller, sollte die Luftfeuchtigkeit und Temperatur gemessen werden, damit der Keller nur dann gelüftet wird, wenn er dadurch nicht noch feuchter wird. Die Temperatur auszulesen stellt ja kein Problem dar - entweder NTC oder gleich einen 1-wire-Sensor.
Für die Luftfeuchtigkeit gibt es im Internet den HH10D-Sensor zu kaufen. Dieser besteht eigentlich aus zwei Komponenten. Einmal dem eigentlichen Sensor für die Luftfeuchtigkeit und einmal einem EEPROM, in dem die Daten von der Kalibrierung im Werk gespeichert sind. Dieser EEPROM kann per i2c-Bus ausgelesen werden und enthält zwei Werte, die zusammen mit der Ausgabe des Feuchtigkeitssensors verrechnet werden. Der Feuchtigkeitssensor gibt den relative Luftfeuchtigkeit als Frequenz im Bereich von ca. 5 bis 10 kHz aus.

Interessant wird es nun deshalb, weil der Sensor und der EEPROM mit 3 V (bzw. 3,3 V sind auch möglich) betrieben werden müssen, ich aber für die übrige Mikrocontroller-Logik mit 5 V Pegeln arbeite. Da der i2c-Bus bidirektional arbeitet, gibt es recht aufwändige Pegelwandler-Chips, die aber dank einer App-Note von Jim Hagerman aus EDN durch zwei einfache NPN-Transistoren (je einer für SCL und SDA) und und ein paar Widerstände ersetzt werden können. Die Transistoren werden dabei im Sättigungsbereich betrieben. Ich habe den Schaltplan im EAGLE-Format mal hochgeladen.

i2c-Pegelwandler mit Transistoren i2c-Pegelwandler Platine

Der Frequenzausgang des Luftfeuchtigkeitssensors kann direkt an den Mikrocontroller geführt werden, da dieser die 3 bzw. 3,3 V Pegel bereits als High erkennt. Für meine Schaltung verwende ich einen Atmega8 - entsprechend führe ich den Frequenzausgang an den 16-Bit-Counter T1. Die i2c-Leitungen werden ebenfalls an die vom Atmega8 vorgesehenen Pins vom TWI (Two Wire Interface) PC4/5 angeschlossen.

Umrechnung

Der nächste Schritt ist jetzt, zunächst den EEPROM auszulesen und anschließend die Frequenz. Aus dem EEPROM erhält man zwei Werte: Sensitivity und Offset. Diese sind jeweils 2 Byte lang und liegen auf den folgenden Adressen:

KoeffizientAdresse
Sensitivity (MSB:LSB)0x0A:0x0B
Offset (MSB:LSB)0x0C:0x0D

Ließt man also den Wert von 0x0A aus, muss man diesen um 8 Bit nach links schieben und den Wert von 0x0B aufaddieren. Im Code sieht das dann so aus:

	float sens = 0.0;			
	float senslsb = 0.0;
	float offset = 0.0;			
	float offlsb = 0.0;			

	i2c_init();			// I²C initialisieren
	i2c_start( 0xA2 );		// I²C Übertragung starten mit 0xA2
	i2c_write( 0x0A );		// Adresse die als erstes Ausgelesen werden soll
	i2c_start( 0xA3 );		// Daten anfordern
	sens = i2c_readAck();		// 0x0A MSB von sens
	senslsb = i2c_readAck();	// 0x0B LSB von sens
	offset = i2c_readAck();		// 0x0C MSB von offset
	offlsb = i2c_readNak();		// 0x0D LSB von offset, es werden keine weiter Daten mehr angefordert
	i2c_stop();			// I²C Übertragung beenden

	offset = offset * ( 1<<8 );	// Stellenwert von offset-MSB berücksichten
	offset = offset + offlsb;	// MSB und LSB von Offset zusammenfügen
	sens = sens * ( 1<<8 )		// Stellenwert von sens-MSB berücksichten
	sens = sens + senslsb;		// MSB und LSB von sens zusammenfügen

Als nächstes benötigen wir noch die Frequenz. Dazu könnte man entweder die Zeit zwischen zwei Impulsen messen, oder die Impulse innerhalb einer gewissen Zeitspanne. Ich habe mich für letzteres entschieden, da sich das mit dem Counter sehr einfach und ohne großartiges Interrupthandling bewerkstelligen lässt. Der 16-Bit Counter wird also so konfiguriert, dass er den T1-Pin als Trigger für den Counter verwendet. Anschließend wird der Counter auf 0 gesetzt, eine Pause von 100 ms eingelegt und anschließend der Counterwert ausgelesen. Nimmt man ihn mal 10, erhält man die Frequenz in Hz. Im Code sieht das dann so aus:

	DDRD &= ~( 1 << DDD5 );		// PD5(T1) pin zurücksetzen
					// PD5(T1) ist jetzt als input konfiguriert

	// Counter einschalten, Clock bei steigender Flanke
	TCCR1B |= ( 1 << CS12 ) | ( 1 << CS11 ) | ( 1 << CS10 );

	float freq = 0.0;
	TCNT1 = 0;
	pause( 100 );			// 100 ms messen
	freq = TCNT1;
	freq = freq * 10;		// Ergebnis * 10 nehmen

Bei einer minimalen Frequenz von 5 kHz ergibt das bei 100 ms Messzeit einen Counterstand von 500 bzw. bei 10 kHz einen Counterstand von 1000, was noch gut in den 16 Bit des Counters liegt, aber für die 8 Bit des kleineren Counters schon viel zu groß wäre.
Im Datenblatt findet sich nun die folgende Formel zur Berechnung der relativen Luftfeuchtigkeit:

RH = (offset - freq ) * sens / 2^12

Da hier ein Wert mit einer Kommastelle heraus kommt, habe ich bereits für die Initialisierung der an der Rechnung beteiligten Variablen den Typ float deklariert. Dies benötigt zwar mehr RAM im Mikrocontroller, ich habe dann aber keinen Ärger mit Typecasts. Im Code ist das dann einfach diese Zeile:

	float rh = 0.0;			// Relative Luftfeuchtigkeit
	rh = ( offset - freq ) * sens / ( 1<<12 );

Den Code für ein fertiges Programm habe ich in einem zip zusammengestellt: hh10d_atmega8.zip
Das Programm nutzt die TWI-Implementierung i2cmaster von Peter Fleury und gibt das Ergebnis auf der seriellen Schnittstelle mit 9600-8n1 aus.
Schaut auch gern noch bei meiner Kellerlüftung vorbei - dort gehe ich ebenfalls nochmal auf den Sensor ein.

Seitenanfang