MLX90614 IR Thermometer

Hallo Leute,

ich bin gerade iwie am verzweifeln : (
Ich habe mir den oben genannten Sensor gekauft und auch zum Laufen gebracht. Hier der Quelltext:

#include <i2cmaster.h>

const int analogpin = 0;  // Analog input pin
void setup(){
Serial.begin(9600); 
Serial.println("Herzlich willkommen. Zeig mir einen Gegenstand") ;
Serial.println("und ich zeig dir wie warm er ist : )");
i2c_init(); //Initialise the i2c bus

PORTC = (1 << PORTC4) | (1 << PORTC5);//enable pullups
}

void loop(){
int dev = 0x5A<<1;
int data_low = 0;
int data_high = 0;
int pec = 0;


i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x07);
i2c_rep_start(dev+I2C_READ);


data_low = i2c_readAck(); //Read 1 byte and then send ack
//read one byte from the I2C device, request more data from device
data_high = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak();
//read one byte from the I2C device, read is followed by a stop condition
i2c_stop();
//set stop conditon = release bus


//This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
float tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
float tempData = 0x0000; // zero out the data
int frac; // data past the decimal point

// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData = (double)(((data_high & 0x007F) << 8) + data_low);
tempData = (tempData * tempFactor)-0.01;

float celcius = tempData - 273.15;


Serial.print("Celcius: ");
Serial.println(celcius);

delay(1000); // wait a second before printing again

}

Das Programm läuft soweit ganz toll. Aber ich verstehe einige Befehle nciht und finde im Internet keine gute Hilfe dafür, deshalb wende ich mich an euch.

Folgende Programmzeile verwirrt mich:

i2c_start_wait(dev+I2C_WRITE); // Dieser Teil sendet eine Adresse an das Arduino Board???
i2c_write(0x07);
i2c_rep_start(dev+I2C_READ);

Könnt ihr mir bitte helfen?

Vielen Dank schon mal im Voraus

Hast Du nicht in der Beschreibung der Bibiothek oder in TXT file nachgeschaut? Grüße Uwe

Doch aber ich kann mit der englischen Beschreibung ncihts anfangen, deshalb hoffe ich ja das mir hier jemand weiterhelfen kann :)

Vor allem dieser Befehl verwirrt mich. Kannst du mir das erklären?

tempData = (double)(((data_high & 0x007F) << 8) + data_low);

tempData wurde im Quelltext als Variabel deklariert.
Double ist das gleiche wie float.

Was bedeutet denn 0x007F???
und was soll die Verknüpfung:
data_high & 0x007F

Ich finde im internet nirgends ne Seite die das wirklich gut erklärt und sitz gerade nur davor und hab überhaupt keine ahnung

tempData = (double)(((data_high & 0x007F) << 8 )+ data_low);

Es wird hochwertiges Byte und niederwertiges Byte der Temperatur zusammengefügt und das höchste Bit gelöscht.

0x007F … ist eine Zahl in Hexadezimaldarstellung.
& … bitweise AND-verknüpfung ( in diesem Fall werden die oberen Bits null gesetzt und es bleiben nur die unteren (niederwertigen) 7 Bit).
<< … Dann wird alles 8 Stelle nach links verschoben (gleichbedeutend wie mit 256 multipliziert) und data_low dazugezählt.
Im ganzen wird hochwertiges Byte und niederwertiges Byte der Temperatur zusammengefügt und das höchste Bit gelöscht.

http://arduino.cc/en/Reference/HomePage links unten “Bitwise Operators”

Grüße Uwe

Klasse danke,

ich verstehe ja das 007F eine Hexadezimalzahl ist, aber was bewirkt das 0x davor?

Ist das eine Multiplikation um die letzten 4 bits null zu setzen?

Das ist einfach die C Konvention um dem Compiler zu sagen dass es sich um eine Hexzahl handelt. Eine Zahl nur mit einer führenden Null wäre übrigens eine Oktalzahl.

Somit: 13 = Dezimal 13 / Hex 0D / Oktal 15 013 = Oktal 13 / Dezimal 11 / Hex 0B 0x13 = Hex 13 / Dezimal 19 / Oktal 23

und B10010100 ist eine Zahl in binärBasis. Statt 0x007F hätte man auch B01111111 schreiben können Grüße Uwe

Super danke das habe ich verstanden :smiley:

jetzt muss ich nur noch verstehen was die folgenden Befehle machen^^
i2c_start_wait(dev+I2C_WRITE);
dev wurde als Hexadezimalzahl definiert gleichbedeutend mit 101 im binär System (int dev = 0x5A<<1;)
gleichzeitig wurde diese Hexadezimalzahl um eine Stelle nach links verschoben quasi 1010
I2C_write ist aber keine Anweisung oder? Wird das als Variabel behandelt?

i2c_write(0x07); → 0x07 steht für die Hexadezimalzahl 07 = 111

i2c_rep_start(dev+I2C_READ);
Ähnlich wie der oben stehende Befehl nur mit der Anweisung read?

data_low = i2c_readAck();
data_high = i2c_readAck();
Hierbei werden beide Variablen mit 1Byte aus dem Arduino beschrieben, aber sind diese dann nicht identisch?

Ironman1201:
Super danke das habe ich verstanden :smiley:
jetzt muss ich nur noch verstehen was die folgenden Befehle machen^^
i2c_start_wait(dev+I2C_WRITE);
dev wurde als Hexadezimalzahl definiert gleichbedeutend mit 101 im binär System (int dev = 0x5A<<1;)
gleichzeitig wurde diese Hexadezimalzahl um eine Stelle nach links verschoben quasi 1010
I2C_write ist aber keine Anweisung oder? Wird das als Variabel behandelt?

Die Adresse des I2C Bauteils besteht aus 7 Bit und als niederwertigstes Bit ein Bit um Lesen/schreiben anzuzeigen.
dev ist die I2C-Adresse und
I2C_WRITE bzw I2C_READ ist ein Bit das anzeigt ob geschrieben oder gelesen wird.

Die Adresse liegt als 8-Bit Zahl vor wobei das Höherwertige Bit keine Funktion hat. Die Adresse wird um eine stelle nach links geschoben und das Schreibe/Lese-Bit hinzugefügt.

Ironman1201:
data_low = i2c_readAck();
data_high = i2c_readAck();
Hierbei werden beide Variablen mit 1Byte aus dem Arduino beschrieben, aber sind diese dann nicht identisch?

Nein, die Daten werden hintereinander gelesen / geschrieben und das I2C Bauteil stellt automatisch eine neue Speicherstelle bereit (sequenzielles Schreiben/Lesen)

Grüße Uwe

Klasse also kann man erstmal soweit zusammenfassen:

int dev=0x05A<<1 bedeutet
5A=1011010
5A<<1=10110100

i2c_start_wait(dev+i2c_write)=i2c_start_wait(1011 0100+0000 0001)=i2c_start_wait(1011 0101)

Dieser Befehl zeigt zum einen das jetzt geschreiben wird zum anderen definiert er die Adresse des Slaves.

i2c_write(0x07)
Dieser Befehl sendet ein Byte nämlich 0000 0111
Aber wiso gerade 0x07 und nciht zum Beispiel 0x06, ist das willkürlich?

Ironman1201: i2c_write(0x07) Dieser Befehl sendet ein Byte nämlich 0000 0111 Aber wiso gerade 0x07 und nicht zum Beispiel 0x06, ist das willkürlich?

Das hängt vom Befehlssatz des I2C Gerätes ab und was Du machen willst. Grüße Uwe

Achso also ist das fest definiert. Stehen die Befehle für den Sensor im Datenblatt oder kann ich die iwo finden?

Entschuldige, das sind keine Befehle sondern Speicherzellen von denen Du Werte lesen kannst bzw EEprom-Register zum setzen gewisser Funktionen.

http://www.watterott.com/de/Infrared-Thermometer-MLX90614

Kapitel 8.3 Seite 11 von http://www.sparkfun.com/datasheets/Sensors/Temperature/SEN-09570-datasheet-3901090614M005.pdf

http://www.sparkfun.com/datasheets/Sensors/Temperature/SEN-09570-MLX90614.pdf

Grüße Uwe

Also ich hab hier die folgende Tabelle gefunden:

Seite 14 Punkt 8.3.4 http://www.sparkfun.com/datasheets/Sensors/Temperature/SEN-09570-datasheet-3901090614M005.pdf

Dort stehen ja Adressen für die jeweiligen Befehle drinne. Mich interessiert ja die Objekttemperatur und die Umgebungstemperatur, also im Prinzip 006h und 007h. Über den Befehl I2C_write(0x07) messe ich also die Objekttemperatur. Ist also 0x07 gleichzusetzen mit 007h ? (0x07 ist ja nur eine Hexadezimalzahl)?

Ja, soweit ich das verstanden habe. Grüße Uwe

Unter dem Punkt 8.5.3 Customizing the temperature range for PWM output kann man ja die Formel finden mit denen zum Bsp die Objekttemperatur bestimmt werden kann.

Gleich die erste Formel gibt ja die Objekttemperatur an

Tpwmobj=(Tmax-Tmin)/1024

Kommt daher die Formel:
tempData1 = (((data_high1 & 0x007F) << 8) + data_low1);
also das data_high+data_low?

Tpwmobj müßte der PWM Ausgangssignal sein das der Baustein alternativ zum I2C usgeben kann.

tempData1 = (((data_high1 & 0x007F) << 8 ) + data_low1);

also das data_high+data_low?

Nein, das kommt davon, daß das Ergebnis 15 Bit lang ist und auf einmal nur 8bit übertragen werden.

Grüße Uwe

Tpwmobj müßte der PWM Ausgangssignal sein das der Baustein alternativ zum I2C usgeben kann.

Achso dadurch, dass meine Kommunikation aber ausschließlich über die I2C Schnittstelle erfolgt, kann ich die dort angegebenen Formeln nicht für die Berechnung heranziehen?

Darüberhinaus wollte ich die Spannung bestimmen, die der jeweiligen Messtemperatur entspricht. Dazu habe ich folgenden Queltext geschrieben: float voltage=analogRead(analogpin); voltage=voltage*3.3/1024; Serial.print(voltage); Serial.println(" volts"); Serial.println(" "); delay(1000);

Aber welchen Wert mess ich damit jetzt überhaupt? Jeder Temperatur wird ja eine Spannung zugeordnet. Entsprechen jetzt z.B. 1,2 gemessene Volt der Temperatur des Objekts der Umgebung oder funktioniert der Quelltext so überhaupt nicht?

PS Vielen Dank für deine Hilfe, Echt Klasse von dir ;) :D

Ein PWM Signal ist kein Gleichstromsignal sondern eine Rechteckspannung mit variablen Impuls-Pausenverhältnis. Darum müßtest Du das PWM erst durch einen Filter schicken um es soweit zu glätten, daß eine Gleichspannung daraus wird. Der Fehler und Störungen beim A/D-Wandeln verschlechtern noch die Auflösung. Eine Bessere Messung des PWM-Signals ist die Messung des Impuls-Pausenverhältnsses da dies auf 2 relative Zeitmessung geschiet, werden viele Fehler ausgemerzt. Dies brigt die volle 10bit Auflösung in der Messung.

Du kannst auch nicht beides Gleichzeitig ( PWM und I2C) haben da ein Pin für beide Ausgänge verwendet wird.

Nimm den digitalen Wert über die I2C Schnittstelle; das ist am einfachsten und ohne Fehlerquellen.

Grüße Uwe