I2C Temperatur- und Feuchtigkeitssensor HDC1008

Hardware

Beschreibung

Das HDC1008 Modul ist ein Temperatur- und Feuchtigkeitssensor, den man via I2C auslesen kann.

Die Steckbrücke wird separat beigelegt und muss bei Bedarf selbst aufgelötet werden.

Die Preise liegen bei ca. 6-7 Euro zuzüglich Versand. Leider vertreiben ihn nur wenige Firmen, d.h. entweder den Preis akzeptieren oder lassen ;-)

Aus meiner Sicht lohnt sich das Modul allemal, Schon dadurch, dass man 4 Module an einem Bus hängen, d.h. man an 4 Stellen im Bus Temperatur, sowie Feuchtigkeit messen und damit auch den Taupunkt berechnen kann, ermöglicht komplexere Steuerungen zur cleveren Belüftung von Räumen.

Adressierung

Jumper Binär Hex
0 010000000x40
0 110000010x41
1 010000100x42
1 110000110x43

Pogrammierung

Aus der Doku (Datenblatt) geklaut

Die ganze Kommunikation ist recht simple. Der Sensor ist erst mal im Ruhezustand und tut nix. Man setzt also zuerst erst den Pointer auf die Konfiguration (Adresse 0x02) und schreibt danach ein Word mit der gewünschten Konfiguration

BitWertBedeutung
100Temperatur mit 14 Bit Genauigkeit
101Temperatur mit 11 Bit Genauigkeit
9:80:0Feuchtigkeit mit 14 Bit Genauigkeit
9:80:1Feuchtigkeit mit 11 Bit Genauigkeit
9:81:0Feuchtigkeit mit 8 Bit Genauigkeit
131Einschalten der Heizung im Sensor zur Vermeidung von Vermeidung von Kondenswasser

Danach setzt man den Pointer auf 0x00 um die Temperatur zu lesen. Entsprechend des Datenblatts sollte man bei 14 Bit Genauigkeit 6.35 ms, bei 11 Bit 3.65 ms warten, bis die Messung fertig ist und der Wert bereit steht. Danach kann vom I2C den 2 Byte(=1 Word) großen Wert auslesen.

Temperatur (in C°) = (Wert[ BIT 15:00 ] / 2^16) *165 - 40;

Weiter geht es mit der Feuchtigkeit, Pointer diesmal auf 0x01 setzen , wieder warten (6.50 ms bei 14 Bit, 3.85 ms bei 11 und 2.50 ms bei 8 Bit) bis die Messung fertig ist und der Wert bereit steht. Danach kann vom I2C den 2 Byte(=1 Word) großen Wert auslesen.

Relative Luftfeuchte (in %) = (Wert[ BIT 15:00 ] / 2^16) * 100

Das wars eigentlich schon.

Umsetzung in Perl

Offen gestanden mit der Programmierung des Sensors tat ich mich etwas schwer. Das Datenblatt war verständlich, jedoch die Umsetzung nicht ohne. Das SMBus Protokoll funktioniert eben doch etwas anders als das I2C.

Die erste Umsetzung ging schnell. Pointer auf Konfiguration gesetzt, meine Wunscheinstellung geschrieben, Pointer auf "Temperatur lesen" gesetzt... doch halt.. wie kann ich ein simple Word via SMBus lesen... nachgelesen (Stichwort multiple bytes), der angegebene Workaround klappte nicht.

Gut dann eben via I2C... ah Google zeigt viele Treffer zu HiPi::Device::I2C. Installation scheint einfach, aber klappt nicht. Das Modul wurde für Perl 3.5 und nicht für 5.2 geschrieben. Viele Libs (automake, libtools,... ) muss man nachinstallieren, ok getan, es gibt neue Fehler. So veränderte ich stundenlang in dem Modul mal da - mal dort was, kaum war der eine Fehler raus sprang mich der nächste an. Gut unter der Banane will er nicht, auch der Versuch unter dem Raspi scheiterte.

Also nun hier meine Lösung SMBus mit eigenem ReadWord per direkten Zugriff.

#!/usr/local/bin/perl -w

package main;

use strict;
use warnings;
use Time::HiRes qw(usleep);

use IO::File;
use Fcntl;

use Device::SMBus;

my $dev = Device::SMBus->new(
  I2CBusDevicePath => '/dev/i2c-2',
  I2CDeviceAddress => 0x40,
);

# gibs leider nicht per SMBus, daher eigenes nachgerüstet
sub I2CReadWord
{	
	my ($dev) = @_;

    my $fh = IO::File->new( $dev->I2CBusDevicePath, O_RDWR );
    if ( !$fh ) {
        croak "Unable to open I2C Device File";
        return -1;
    }
    $fh->ioctl( Device::SMBus::I2C_SLAVE,  $dev->I2CDeviceAddress );

	my $temp1='';
	sysread ( $fh, $temp1, 2);
	my @x = split(//, $temp1);
	
	my $msb = ord($x[0]);
	my $lsb = ord($x[1]);

	close($fh);

	return $msb*256 + $lsb;
}

# schreibe Konfiguration 
# Temperatur sowohl auch Feuchtigkeit bitte in 14 Bit ausgeben
$dev->writeWordData(0x02,0x1000);
Time::HiRes::sleep(0.2);


my $i = 0;
while($i < 100000000) 
{

	# lese Temperatur
	$dev->writeByte(0x00);
	Time::HiRes::sleep(0.07); 
	my $tempWord = I2CReadWord($dev);
	printf ( "Temp: %f\n", (($tempWord /65536.0)*165.0)-40.0 );

	# lese Feuchtigkeit
	$dev->writeByte(0x01);
	Time::HiRes::sleep(0.07); 
	my $humWord = I2CReadWord($dev);
	printf ( "Hum: %f\n", ($humWord /65536.0)*100.0) ;

	print "durchlauf $i\n\n";

	$i += 2;


}
Artikel von Karsten Grüttner, letzte Änderung 8.10.2015