Dieses Blog durchsuchen

HYT939 und NTC an Matlab über Arduino


In den letzten Blogeinträgen habe ich mit dem Arduino einen NTC-Widerstand  über einen Spannungsteiler an den Analogeingang des Arduino-UNO angeschlossen und ihn als eigenständiges Programmchen am Arduino als Temperatursensor laufen lassen. Die aktuellen Messwerte wurden auf einem LC-Display angezeigt. Dann habe ich die selbe Hardware über die Matlab Software und das "Arduino for Matlab"-Package betrieben und mittels Matlabcode direkt den Temperaturverlauf geloggt. Im vorhergehenden Blog war dann ein kombinierter Temperatur und Luftfeuchtigkeitssensor (Type HYT939) an der Reihe, der über den I²C Bus am Arduino seine Daten lieferte und wieder am LCD ausgegeben hat.

In diesem Bericht kommt nun wieder Matlab ins Spiel. Hier habe ich versucht, beide Sensoren, den NTC am Analogeingang und den HYT am I²C Bus, gleichzeitig auszulesen. Das sollte über einen mehrere Minuten andauernden Zeitraum passieren, wobei die Messwerte gleich mitgeloggt werden, um sie danach in einem Vergleichsdiagramm zu plotten. Der Hardwareaufbau ist wieder ganz einfach. Der NTC ist in Serie mit einem 2k2 Widerstand geschaltet. Die Enden des Spannungsteilers gehen an die +5V Versorgung und GND und der Teilerpunkt wird an den A0 - Eingang des Arduino Uno angeschlossen. Der HYT bekommt ebenfalls seine 5V vom Arduino selbst und an A4 und A5 ist der I²C anzuschliessen (genaue Pinbelegung s. vorgehenden Bericht). Jetzt fehlt noch das Matlab-Script. Es ist hier einzusehen:

 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
 % Beispielscript um mit ArduinoUno einen Temperaturverlauf aufzuzeichnen  
 % Sensoren an A0 (Spannungsteiler mit NTC) und HYT939 an I2C  
 % 03/2016 by I.Bihlo  
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
 a = arduino('com4','Uno','libraries','I2C')  
 analogpin=0; %Anschlusspin analog des UNO  
 analog=0; %Variable für den Analogwert festlegen  
 nn=600; %anzahl der messpunkte  
 addr='0x28'; %addresse für digitalsensor  
 bus=i2cdev(a, addr) %i2c object erzeugen  
 %ein paar konstanten für die weiteren berechnungen  
 r=2200; %Spannungsteilerwiderstand  
 rt=0; %das wird der errechnete widerstand des NTC  
 urt=0; %das wird der errechnete Spannungsabfall am NTC  
 % konstanten für berechnung der Temperatur aus NTC Widerstand  
 % B25=3977K  
 a1=3.354016E-03;  
 b1=3.2569850E-04;  
 c1=2.61013E-06;  
 d1=6.38309e-08;  
 rref=2200;  
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
 % Lesen des I2C Bus  
 % Lesen eines Temperaturabhängigen Widerstandes am Analog Eingang A0  
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
 for x=1:nn  
 %%%% Analog   
 analog(x)=readVoltage(a, analogpin); %Liest den AnalogIn von A0 und gibt in Volt aus  
 urt(x)=5-analog(x); %spannungsabfall am NTC   
 rt(x)=(r/analog(x))*urt(x); %widerstand des NTC  
 pause(0.5);  
 %%%%Digital  
 data = read(bus, 4); %4 byte von i2c auslsesen  
 pause(0.5);  
 %Rohdaten aus Puffer lesen und zusammenbauen  
 humrawh=dec2bin(data(1),8); %byte 1 auf 8bit festlegen in binär wandeln  
 humrawl=dec2bin(data(2),8); %byte 2 auf 8bit festlegen in binär wandeln  
 humrawall=strcat(humrawh,humrawl); % beide bins concentenaten  
 humraw=bin2dec(humrawall); % die ganze kette wieder in dec wandeln  
 %tempraw=uint16(data(3))*256+uint16(data(4));  
 temprawh=dec2bin(data(4),8);  
 temprawl=dec2bin(data(3),8);  
 temprawall=strcat(temprawl,temprawh);  
 temprawall=temprawall(1:14); %% die letzten beiden bits abschneiden  
 tempraw=bin2dec(temprawall);  
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
 % Humidity berechnen lt. Datenblatt  
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
 hum(x)=double(100/(16384-1))*double(humraw);  
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
 % Temperatur berechnen lt. Datenblatt  
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
 temp(x)=double(165/(16384-1))*double(tempraw)-40.0;  
 %berechung der analogtemperatur  
 rvsrref(x)=rt(x)/rref;   
 tempa(x)=1/(a1+(b1*log(rvsrref(x)))+(c1*(log(rvsrref(x)^2)))+(d1*(log(rvsrref(x)^3))));  
 tempc(x)=tempa(x)-273.15 %Kelin in Celsius umrechnen  
 pause(1);  
 end  
 clear a;  
 time=1:nn;  
 %plotten der daten  
 figure(1);  
 subplot(2,1,1);  
 plot(time,tempc,'m');  
 grid on; hold on;  
 %plot(time,analog,'b');  
 %plot(time,rt/1000,'r');  
 %plot(time,urt,'g');   
 plot(time,temp,'g');  
 legend('Temperatur NTC[°C]','Temperatur HYT939 [°C]');  
 %legend('Analogspannung des ADC','Widerstand des NTC in kOhm','Spannung am NTC','Temperatur [°C]');  
 subplot(2,1,2);  
 plot(time,hum,'m');  
 grid on; hold on;  
 legend('Rel Luftfeuchtigkeit HYT939 [%RH]');  
 %ende  

Nachdem der Code nun nach einigen Anpassungen läuft, habe ich beide Sensoren (wie am Titelbild zu sehen) nebeneinander angeordnet und vor Beginn der Messung mit Kältespray (Kälte75 von KontaktChemie) heruntergekühlt. Dann startete das Script und begann aufzuzeichnen. Im Ergebnis sollte der Verlauf der Erwärmung auf die Raumtemperatur zu sehen sein. Da die Kälte am Metallgehäuse des HYT sofort eine Schicht aus geforenem Kondensat bildet die langsam taut, erwartete ich mir einen Luftfeuchtigkeitswert im Bereich der Sättigung. (was dann auch deutlich im Plot zu sehen ist).




Feuchtesensor am Arduino

In den letzten Blog-Einträgen habe ich mit Hilfe des Arduino Uno - Experimentierboards auf unterschiedliche Weise einen NTC-Widerstand zur Messung der Temperatur eingesetzt. Aus einem anderen Projekt habe ich auch noch einen Feuchte/Temperatursensor der Firma IST (Innovative Sensor Technologie) zur Verfügung, der mit einem Raspberry und in Python ausgelesen wurde. Es handelt sich um den digitalen Sensor HYT939, der über den I²C Bus ausgelesen wird. Er zeichnet sich laut Datenblatt mit folgenden Merkmalen aus:

  • chemisch sehr resistent
  • sehr weiter Temperatur- und Feuchtigkeitsmessbereich (-40°C .. +125°C, 0% ..100% RH)
  • mechanisch robuste Bauform
  • kalibriert und temperaturkompensiert
  • sehr geringer Drift
  • einsetzbar bis zu einem Umgebungsdruck von 16bar
  • Versorgungsspannung von 2.7 bis 5.5V
  • Auflösung von +/- 0.02% RH und 0.015°C
  • Genauigkeit von +/- 1.8% RH bei +23°C und +/-0.2K
Also wollte ich diesen Sensor auch mit dem Arduino betreiben und vielleicht in weiterer Folge auch den NTC parallel auslesen und die Ergebnisse vergleichen. Aber zurerst einmal wird der HYT an den Arduino angeschlossen.
Das Bild zeigt das Pinout des HYT in der Ansicht von unten. Die Belegung der Pins lautet:
  • 1...SCL
  • 2...VCC
  • 3...GND
  • 4...SDA
Somit lässt sich der Sensorchip ganz einfach an den Arduino anschliessen, wobei die Pins SDA auf den Arduino Pin A4 und SCL auf den Pin A5 gelegt sind. Die Ausgabe der ausgelesenen Werte soll wieder wie beim NTC auf dem LC-Display stattfinden. Nachstehend ist der Code gelistet:

 /*  
  HYT939 bei Arduino UNO an:  
  SDA pin A4  
  SCL pin A5  
  HYT939 bei MEGA2560 an:  
  SDA pin 20  
  SCL pin 21  
  LCDisplay  
  Pinzuordnungen allgemein für LCD  
  RS to digital 12  
  EN to digital 11  
  D4 to digital 5  
  D5 to digital 4  
  D6 to digital 3  
  D7 to digital 2  
  R/W to ground  
  VSS to ground  
 */  
 //I2C Addresse festlegen  
 #define ADDR 0x28  
 //Variablen und Datentypen festlegen  
 double temp;  
 double hum;  
 unsigned int tempraw;  
 unsigned int humraw;  
 int x;  
 unsigned char buffer[4];  
 //Libraries laden  
 #include <Wire.h>  
 #include <LiquidCrystal.h>  
 // interfacepins initialisieren  
 LiquidCrystal lcd(12, 11, 5, 4, 3, 2);  
  void setup()  
  {  
  //I2C und LCD Interface initialisieren,  
  Wire.begin();  
  lcd.begin(20, 4);  
  Serial.begin(9600);  
  lcd.println("HYT939-Sensor");  
  }  
 void loop()  
  {  
  //I2C auselesen  
  Wire.beginTransmission(ADDR);   
  Wire.endTransmission();  
  delay(200);  
  //4 Bytes auslesen  
  Wire.requestFrom(ADDR, 4,true);  
  x=0;  
  while(Wire.available())   
  { char c = Wire.read(); buffer[x]=c; x++; }  
 //Rohdaten aus Puffer lesen  
 tempraw=buffer[2]*256+buffer[3];  
 humraw=buffer[0]*256+buffer[1];  
 //Daten laut Datenblatt maskieren  
 tempraw&=0xfffc;  
 humraw&=0x3fff;  
 tempraw=tempraw/4;  
 //Rohdaten in Ausgabeformat umrechnen  
 temp=(double)tempraw/99.2909; //skalieren laut datasheet  
 temp=temp-40.0;  
 hum=(double)humraw/163.83;  
 //Daten auf LCD schreiben  
  lcd.setCursor(0, 2);   
  lcd.print("Temperatur =");  
  lcd.setCursor(11, 2);  
  lcd.print(temp);  
  lcd.setCursor(0, 3);   
  lcd.print("Humidity =");  
  lcd.setCursor(14, 3);  
  lcd.print(hum);  
 //lcd.setCursor(0, 2);  
 //lcd.print('Buffer0 =');  
 //lcd.setCursor(11, 2);  
 //lcd.print(buffer[2]);  
 //lcd.setCursor(0, 3);  
 //lcd.print('Buffer1 =');  
 //lcd.setCursor(11, 3);  
 //lcd.print(buffer[3]);  
 }  

Ortsradioaktivität mit Homematic

Mein Interesse an Strahlungsmessung im allgemeinen und das Interesse am Eingenbau von Messgeräten lässt mich oft, vorallem bei langweiligem Fernsehprogramm, im Web recherchieren. Auf der Suche nach dem Begriff Geigerzähler findet man ja unheimlich viele Ergebnisse. Nach einer Unterhaltung mit einem Kollegen, wie es zu Zeiten von Tschernobyl hier mit der Strahlungsbelastung aussah, suchte ich auch nach einer Karte mit der aktuellen Strahlungsverteilung in Österreich und wurde auch fündig. Es gibt ein ganzes Netzwerk an Messgeräten in ganz Östrreich verteilt, das stündlich die Radioaktivität misst und aufzeichnet. Über diese Website kann man sich anhand einer Karte mit unterschiedlich (entspechend der Intensität der Strahlung) eingefärbten Punkten informieren. Klickt man einen Messpunkt an, so erhält man die Detailwerte der Messungen angegeben in nSievert/h dargestellt als Diagramm oder auch in Tabellenform. Die Website nennt sich: http://sfws.lfrz.at.

Toll dachte ich beim Betrachten der Messdaten. Noch toller wäre es, selber so eine Meßstation aufzubauen und in mein bestehendes Homematic-System mit aufzunehmen. Oder für´s erste könnte man ja versuchen, die Daten der Website in die Homematic zu integrieren. ... und dann beispielsweise bei bei Überschreitung eines Messwertes eine Nachricht oder einen Alarm zu generieren.
Also habe ich mir die Website genauer angesehen und die java- und php-scripten analystiert, die hier aufgerufen werden. Schlussendlich lässt sich über die Seite http://sfws.lfrz.at/json.php ein gutes Interface erreichen, dass mit den entsprechenden Commandos bedienen kann. Für meinen Fall hole ich mit http://sfws.lfrz.at/json.php?command=getstationdata&stationcode=AT0408&a=&b= die Messdaten für eine nahe Meßstation ab.

Der webresponse sieht dann inetwa so aus:
{"v":[{"d":1457276400,"v":90.1,"c":32768}, {"d":1457272800,"v":88.9,"c":32771}, {"d":1457269200,"v":85.8,"c":32781}, {"d":1457265600,"v":83.1,"c":32790}, {"d":1457262000,"v":83.7,"c":32788}, {"d":1457258400,"v":86.6,"c":32778}, {"d":1457254800,"v":88.2,"c":32773}, {"d":1457251200,"v":83.1,"c":32790}, {"d":1457247600,"v":84.2,"c":32786}, {"d":1457244000,"v":85.1,"c":32783}, {"d":1457240400,"v":89.7,"c":32768}, {"d":1457236800,"v":99.1,"c":38656}, {"d":1457233200,"v":101,"c":39680}, {"d":1457229600,"v":90.8,"c":33280}, {"d":1457226000,"v":92,"c":34048}, {"d":1457222400,"v":112,"c":46848}, {"d":1457218800,"v":115,"c":48896}, {"d":1457215200,"v":109,"c":45056}, {"d":1457211600,"v":104,"c":41728}, {"d":1457208000,"v":91.5,"c":33536}, {"d":1457204400,"v":89.7,"c":32768}, {"d":1457200800,"v":84.9,"c":32784}, {"d":1457197200,"v":84.4,"c":32785}, {"d":1457193600,"v":83.5,"c":32788}], "a":"1457190947","b":"1457277347"}

Also perfekte Rohdaten um damit was anfangen zu können :) Im Datensatz ist der Zeitstempel (im Unix-Zeitcode Format), der Messwert in nS/h, sowie ein RGB Farbcode für die Darstellung der Farbe in der Webkarte angegeben. Also beginnen wir, die Messdaten über die Homematic CCU2 Zentrale abzurufen und nach der Datenaufbereitung in Systemvariablen zu speichern.

Als erstes legen wir zwei neue Systemvariablen an:
Die erste Variable soll "Strahlungswert" heissen und vom Datentyp "Zahl" sein. Als Maßeinheit gebe ich nS/h (nanoSivert pro Stunde) an.
Die zweite Variable benennen wir "Messzeitpunkt" mit dem Datentyp "Zeichenkette". Wenn alles mit OK bestätigt ist, dann legen wir unter Programme und Verknüpfungen ein neues Programm an:
Das Programm habe ich "strahlungwerte über web" genannt und als Trigger ein periodisches Zeitevent definiert. Das Programm soll alle 60 Minuten ausgeführt werden um die Daten vom Web abzuholen und in die Systemvariablen zu schreiben.
Nachdem der Auslöser definiert ist, muß eine Aktivität bestimmt werden. Wir wählen hier keinen Aktor, sondern die Option Skript:
Danach klicken wir auf die Script-Zeile und öffnen den Scripteditor:
Die nachfolgenden Zeilen sind am besten per copy und paste in den Scripteditor einzufügen und per OK zu bestätigen.

 !script zum importieren der webdaten von der landeswarnzentrale radioaktivität  
 !by ingmar b.03/2016  
 string stderr;  
 string stdout;  
 string answer;  
 !Website angeben - die Antwort kommt als string  
   string url="http://sfws.lfrz.at/json.php?command=getstationdata&stationcode=AT0408&a=&b=";  
 !mit wget den Inhalt der Antwort in stdout schreiben    
 system.Exec("wget -q -O - "#url, &stdout, &stderr);  
 !stdout in die variable answer schreiben  
 answer = stdout;  
 !stringlänge des Inhalts von answer ermitteln  
 integer length = answer.Length();   
 !foreach(summand, summanden.Split(","))  
 !answer=answer.Split("},{"));  
 var rad;  
 var zeitst;  
 var radiation;  
 var zeitstempel;  
 !Antwort Radiation in index 1,4,7,10,13...70  
 !Antwort Zeitcode in index 0,3,6,9,12...69  
 rad=(answer.StrValueByIndex(",", 1));   
 zeitst=(answer.StrValueByIndex(",",0));  
 !WriteLine(rad); nur zum debuggen  
 !WriteLine(zeitst); nur zum debuggen  
 radiation=rad.Substr(4,4);       !String an pos4 substituiern und 4 Stellen ausgeben  
 zeitstempel=zeitst.Substr(11,10);  !String an pos11 substituiern und 10 Stellen ausgeben  
 zeitst=zeitstempel.ToInteger();  
 zeitst=zeitst.ToTime();  
 rad=radiation.ToFloat();  
 dom.GetObject("Messzeitpunkt").State(zeitst); !Systemvariable muss definiert sein  
 dom.GetObject("Strahlungswert").State(rad); !Auch die Systemvariable 'Strahlungswert' vorher anlegen  
Zum Schluß noch per Fehlerprüfung nachsehen ob der code ein Problem hat und dann OK und mit OK speichern. Hat alles geklappt sollte man jetzt die Systemvariablen ansehen können und es sollten auch gültige Werte zu sehen sein:








NTC am Arduino

Nach dem kleinen Projektchen "Arduino mit Matlab" möchte ich der Vollständigkeit halber den selben Aufbau auch noch ohne Matlab laufen lassen. Dabei soll der Code mit der mitgelieferten Arduino Entwicklungsumgebung "Arduino Software 1.6.7" erstellt und in den Atmega 328 geladen werden. Damit man in dieser Stand-Alone-Variante auch was sehen kann, soll ein altes vierzeiliges LC-Display angeschlossen werden. Idealerweise gibt es hier eine schöne library namens LiquidCrystal.h, mit der das LCD im 4Bit Betrieb ganz einfach angesteuert werden kann.

Also schnell die benötigten Pins des LCD (übrigens ein JM204A) aus dem Datenblatt herausgesucht und mit Flachbandkabel und Pinheadern versorgt und an den Arduino angeschlossen. (die Belegung des Arduino habe ich im Script angegeben)

Der NTC-Spannungsteiler bleibt, wie er ist. Und schon kanns losgehen. Da wir die vier schönen Zeilen mit 20 Zeichen pro Zeile am LCD zur Verfügung haben, kann auch viel Information angezeigt werden. Ich habe mich entschieden, den Integer Wert des 10Bit ADC anzuzeigen (0-1023), den errechneten Widerstandswert des NTC´s und natürlich die daraus errechnete Temperatur.


Und das hier ist der simple Code ;) ...



 /* ingmarsretro 2016  
  * Pinzuordnungen fürs LCDisplay  
  * RS to digital 12  
  * EN to digital 11  
  * D4 to digital 5  
  * D5 to digital 4  
  * D6 to digital 3  
  * D7 to digital 2  
  * R/W to ground  
  * VSS to ground  
 */  
 // include libraries  
 #include <LiquidCrystal.h>  
 #include <math.h>  
 int analogpin = 0;  
 int analogvalue = 0;  
 double a1=3.354016E-03;  
 double b1=3.2569850E-04;  
 double c1=2.61013E-06;  
 double d1=6.38309e-08;  
 double urt=0;  
 double rt=0;  
 double rvsrref=0;  
 double temp=0;  
 double tempc=0;  
 double r=2200;  
 double rref=2200;  
 double analog=0;  
 // interfacepins initialisieren  
 LiquidCrystal lcd(12, 11, 5, 4, 3, 2);  
 void setup() {  
  // setup LCD spalten und reihen  
  lcd.begin(20, 4);  
  lcd.print("Testprogramm NTC");  
  Serial.begin(9600);  
 }  
 void loop() {  
  analogvalue=analogRead(analogpin);  
  analog=(0.004882812*analogvalue);  
  urt=5-analog;  
  rt=((r/analog)*urt);  
  rvsrref=rt/rref;  
  temp=(1/(a1+(b1*log(rvsrref))+(c1*(log(rvsrref*rvsrref)))+(d1*(log(rvsrref*rvsrref*rvsrref)))));  
  tempc=temp-273.15;  
  // column 0, line 1  
  // (note: line 1 is the second row, since counting begins with 0):  
  lcd.setCursor(0, 1);  
  // print the number of seconds since reset:  
  lcd.print("ADC-Wert =");  
  lcd.setCursor(11,1);  
  lcd.print(analogvalue);  
  lcd.setCursor(0, 2);   
  lcd.print("Widerstd =");  
  lcd.setCursor(11, 2);  
  lcd.print(rt);  
  lcd.setCursor(0, 3);   
  lcd.print("Temp Cels=");  
  lcd.setCursor(11, 3);  
  lcd.print(tempc);  
 }