Die Temperatur messen mit dem LM75

Diesmal widme ich mich dem kleinen Temperatursensor auf dem GREETBoard-ATMega128 Extension, welches in zweierlei Weise etwas besonderes darstellt. Zum einen ist es das einzige SMD-Bauteil, das ich in einem der GREETBoard Module verwende. Aber dafür ist es auch eins, dass sich sehr einfach löten lässt, da der Pinabstand recht groß ist. Zum Anderen ist es ein Baustein, der per I²C ausgelesen wird und digitale Daten liefert, die im Mikrocontroller ausgewertet werden müssen.

Ich hatte extrem viel Respekt vor dem Löten und der I²C-Ansteuerung, aber im Nachhinein betrachtet war beides mit ein bisschen Fingerspitzengefühl und Konzentration gut machbar…

Der LM75

Allgemeine Angaben

Dieser Baustein stammt aus dem Hause Maxim und kann Temperaturen von -55°C bis +125°C messen. Die aktuelle Temperatur wird über den I²C-Bus ausgelesen (SDA & SDL). Hierfür kann die Adresse mit den Pins 6-8 (A0, A1, A2) eingestellt werden. Damit wäre es theoretisch möglich bis zu acht LM75 an einem Bus zu betreiben. Die Versorgungsspannung beträgt bei diesem Modell 5V. Der Pin OS gibt ein Signal aus, wenn das frei programmierbare Temperaturlimit erreicht wird. Auf dem GREETBoard – ATMega128 Extension habe ich diese Funktion jedoch nicht verwendet. Beim Gehäuse handelt es sich um ein SO-Gehäuse.

LM75 - Pin-Beschreibung

LM75 – Pin-Beschreibung

Schaltplan

Auf diesem Ausschnitt ist zu erkennen, wie der LM75 angeschlossen ist. Unter anderen sticht hervor, dass der OS-Ausgang nicht verwendet wird. Er könnte als Interrupt genutzt werden oder auf GND schalten (je nach Einstellung), wenn das o.g. Temperaturlimit erreicht wird. Die Adress-Pins habe ich alle auf GND gelegt, da ich sowieso nur einen LM75 verwende. Sollte es mal dazu kommen einen Zweiten zu benötigen, dann kann ich bei diesem A0 immer noch auf 5V legen. Zusätzlich habe ich dem kleinen Kerl noch einen 100nF Kondensator spendiert.

LM75 - Der Schaltplanausschnitt

LM75 – Der Schaltplanausschnitt

Das Löten

OK, bei der ersten Version habe ich die Lötstoppmaske auf die Lötseite gesetzt und hab es nicht bemerkt. Daher war ich sehr erstaunt, dass die Pads alle mit grüner Farbe bedeckt waren. Als ich dann die freien Stellen auf der Rückseite sah, hab ich mir mit der flachen Hand auf die Stirn geschlagen. Das war schon ziemlich dämlich. Aber Lötstopplack lässt sich hervorragend mit einem Uhrenmacher-Schlitzschraubendreher wegkratzen, so dass ich den LM75 auflöten konnte. Verzeiht mir also bitte die ausgefransten, lötstoppfreien Stellen an den Pads. 😉

Außerdem habe ich zuerst die großen Bauteile rings um das SMD-IC aufgebaut (da wusste ich noch nicht, dass das mit dem Wegkratzen geht). Dadurch war es ein bisschen schwierig den LM75 zu löten. Aber mit ein wenig Flussmittel war es trotzdem kein Problem. Mit der nächsten Version kommt nicht nur ein zusätzlicher Summer dazu, sondern auch korrekter Lötstopplack.

LM75 - Das aufgelötetet Bauteil

LM75 – Das aufgelötetet Bauteil

Die Bus-Adresse

Die Adressierung ist genau wie bei den PCF8574-Bausteinen des GREETBoard-I2CLCD und des GREETBoard-I²C Portexpander. Der PCF8574 unterscheidet sich jedoch in den Bits 4-7, so dass dieser einen Adressbereich von 0x40 bis 0x4F aufweist. Die Bus-Adresse des LM75 hingegen beginnt bei 0x90 und endet bei 0x9F. Damit kommen sich diese Busteilnehmer nicht in die Quere. Auf dem GREETBorad-ATMega128 Extension habe ich die Pins A0, A1, A2 auf 0 gelegt, so dass dies eine Leseadresse von 0x40 (1001 0000) ergibt.

LM75 - I2C-Adresse

LM75 – I2C-Adresse

In diesem Beispiel werde ich den LM75 nicht beschreiben, was bei der Einstellung des Temperaturlimits (bei dem OS schaltet) nötig wäre. Die Schreibadresse ist immer um eins höher, als die Leseadresse, die zum Schreiben das Bit 0 auf 1 gesetzt werden muss, also 0x91 (1001 0001)

Das Ausgabeformat

Oberes Byte

Der LM75 ist ein Temperatursensor, der digitale Werte ausspuckt. Er kann also nicht an den Analog-Digital-Konverter des Mikrocontrollers angeschlossen werden um die Temperatur aus einem analogen Wert zu ermitteln. Darüber hinaus gibt er auch noch einen 16-Bit-Wert zurück, der es im ersten Moment in sich hat. Aber ich nähere mich den Problemen Schritt für Schritt.

LM75 - Aufschlüsselung der Temperatur-Bits

LM75 – Aufschlüsselung der Temperatur-Bits

Die Aufschlüsselung der einzelnen Temperatur-Bits zeigt erstmal, dass im „unteren“ Byte nur die „,5“-Kommastelle dargestellt wird. Die eigentliche Temperatur befindet sich im „oberen“ Byte. Was dort jedoch stört ist das Bit D15, das für das Vorzeichen zuständig ist.

Die im Datenblatt dargestellte Erklärung hat mich zu Beginn echt sehr verwirrt, sodass ich es mit einer etwas abgewandelten Darstellung zu erklären versuche, wie das mit dem Vorzeichen zu verstehen ist.

Hierbei ist wichtige, dass der LM75 Temperaturen bis 125°C messen kann. Das passt ganz hervorragend in eine 128-stellige Binär-Tabelle. 0000 0000 ist dabei 0°C, 0000 0001 = 1°C und 0100 0000 = 64°C. Das deckt sich mit der vorherigen Aufschlüsselung. Solange das MSB (Most significant bit, also D15) 0 ist, entspricht der Dezimalwert des oberen Byte der gemessenen Temperatur. In dem Moment, an dem dieses auf 1 springt gilt folgende Formel (Beispiel-Messwert: 1001 1101 = 157):

LM75 - Temperaturberechnung für Werte ab 128

Die folgende Tabelle zeigt, wie der Wert von steigend positiv und fallend negative umspringt. Ich habe die Nullen gelb markiert, um sie besser zu unterscheiden. Interessanterweise gibt es die Werte 126 und 127 laut Datenblatt nicht und daher habe ich sie grau eingefärbt.

LM75 - Temperaturwerte-Tabelle

LM75 – Temperaturwerte-Tabelle

Die Lösung dieses Vorzeichen-Problems lässt sich also damit lösen, das erst einmal kontrolliert wird, ob der Wert über 127 ist, so dass ab diesem Wert die Formel angewendet werden kann. Aber der ATMega128 stellt uns da eine große Hilfe zur Seite – das sogenannte SIGNED char. „Signed“ bedeutet soviel wie Variable mit Vorzeichen. Wenn ich nun das obere Byte in ein signed char schreibe, wird die Vorzeichenerkennung automatisch durchgeführt und ich muss mich um nichts mehr kümmern. Das ist doch mal sehr praktisch, oder nicht! 🙂

Unteres Byte

Wer sich nun wundert, dass es noch eine neunte Spalte gibt, die ständig auf 0 steht hat ganz recht. Dieses Bit gehört aber bereits zum unteren Byte und es ist für die Nachkommastelle zuständig, da der LM75 in der Lage ist auf ein halbes Grad genau die Temperatur anzuzeigen.

Durch entsprechende Bitmanipulation ist es möglich, eine 1 an diesem Bit zu erkennen und auf dem Display einfach eine „,5“ an die entsprechende Stelle zu schreiben. Der Wert des oberen Bytes wird also um 0,5 erhöht. Liegt dieser Wert jedoch im negativen Bereich, dann würde z.B. aus einer (-24) + 0,5 ein –23,5. Der Wert, der zuvor in das Signed Char geschrieben wurde muss um eins erhöht werden.

Das Programm in kleinen Schritten

Soviel zur Theorie, jetzt zeige ich, wie der LM75 ausgelesen werden kann. Dabei benutze ich das GREETBoard-I²CLCD um die Temperatur als Text anzuzeigen..

Wie alle Programme startet auch dieses mit der Taktdefinition und der Einbindungen von diversen Header-Dateien.

#ifndef F_CPU            //Wenn CPU-Takt nicht bereits definiert wurde...
#define F_CPU 16000000   //...dann definiere ihn auf 16MHz
#endif

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "i2clcd.h"
#include "i2cmaster.h"

Gleich darauf folgt die Definition der Variablen.

#define lm75_r 0x90      //Leseadresse des LM75
uint8_t msb_temp;        //Oberes Temperatur-Byte
uint8_t lsb_temp;        //Unteres Temperatur-Byte
uint16_t temp_wrd;       //Ganzes Temperatur-Wort
uint8_t ret;             //Kontrollvariable für I2C Kommunik.
uint8_t x;               //X-Position der Kommastelle
signed char temperatur;  //Variable m. Vorzeichen für die Temp.berechnung
char Buffer[20];         //Umwandlungs-Variable für LCD Anzeige

Die Funktion „temperfassung“ startet erst einmal die I²C-Kommunikation, in dem die Leseadresse des LM75 an den Bus gesendet wird. Dieser hört ständig am Bus mit und sollte seine Adresse erkennen. Daraufhin wird er eine 0 zurücksenden, wenn die Kommunikation starten kann

void temperfassung(void) {
  ret = i2c_start(lm75_r);      //Start Lesen des LM75

  if (ret == 0) {               //Wenn LM75 ein OK sendet...

Der erste Lesebefehl liest immer das obere Byte aus, welches direkt in der Variable msb_temp abgelegt wird. Der zweite Lesebefehl hingegen zeigt nicht nur an (i2c_readNak), dass die Kommunikation nach ihm beendet ist, sondern er ließt auch das untere Byte aus. Auch dieses wird gespeichert.

    msb_temp = i2c_readAck();   //...speichere oberes Bit
    lsb_temp = i2c_readNak();   //...speichere unteres Bit
  }

Gibt der LM75 eine 1 zurück, dann konnte keine erfolgreiche Kommunikation aufgebaut werden. Dies wird mit einer Textausgabe am LCD-Display angezeigt.

  else {                        //Wenn LM75 kein OK sendet
    lcd_command(LCD_CLEAR);     // Leere Display
    lcd_printlc(1,13,"READ");   // "Lesevorgang"
    lcd_printlc(2,13,"NOK");    // "Nicht OK (NOK)"
  }
}

Das Hauptprogramm startet mit der Initialisierung der I²C-Kommunikation und des LCD-Displays.

int main(void) {
	cli();                     // Interrupts deaktiviert
	i2c_init();                // Starte I2C Bus
	lcd_init();                // Starte I2CLCD
	lcd_command(LCD_CLEAR);    // Leere Display
	lcd_wait_ms(20);           // Warte 20ms wegen Display-Löschung

Die Temperatur wird zu Beginn der Hauptschleife durch den Funktionsaufruf temperfassung(); ausgelesen. Das obere und untere Byte wird anschließend zu einem 16-Bit-Wort zusammengesetzt. Da die eigentliche Temperatur im oberen Byte steht, schreibe ich nur dieses in das signed char temperatur, so dass es ein Vorzeichen „erhält“.

  while(1) {
    temperfassung();                            //Start der Temp.auslesung
    temp_wrd = (msb_temp << 8 | lsb_temp);      //Zusammensetzung von o. & u. Byte
    temperatur = msb_temp;                      // Umwandlung in ein Signed Char

So umgewandelt kann ich die Variable dazu nutzen die Anzahl der Zeichen zu erkennen. Das ist wichtig, um herauszufinden, an welcher Position die Kommastellenangabe platziert werden muss. Bei =< -100°C werden bereits die ersten vier Zeichen besetzt und ein z.B. „,0“ darf erst ab Stelle 5 beginnen. Steigt die Temperatur auf 5°C würden sich drei Leerstellen zwischen 5 und „,0“ befinden. Das sieht nicht schön aus! Daher wird temperatur ausgelesen und die X-Position der folgenden Kommastelle entsprechend in der Variable x abgelegt.

    // Nachkommastelle erkennen
    if      (temperatur <= -100){x = 5;} //X-Pos. bei <= -100°C)
    else if (temperatur <= -10) {x = 4;} //X-Pos. bei <=  -10°C)
    else if (temperatur <= 9)   {x = 3;} //X-Pos. bei <=    9°C)
    else if (temperatur <= 99)  {x = 4;} //X-Pos. bei <=   99°C)
    else                        {x = 5;} //X-Pos. bei  >   99°C

Die folgende Abfrage schaut auf Bit 7 um zu erkennen, ob dort eine 1 steht. Ist dies der Fall, dann wird an die zuvor ermittelte X-Position „,5“ geschrieben. Ansonsten „,0“.

    if (temp_wrd & (1<<7)) {             //Nachkommastelle erkennen
      lcd_printlc(2,x,",5");             //,5 an Pos x schreiben
    }
    else {
      lcd_printlc(2,x,",0");             //,0 an Pos x schreiben
    }

Wieder wird ein Bit der temp_wrd Variable abgefragt um zu erkennen, ob es sich um einen negativen Wert handelt. Bei einer 1 ist dies der Fall und die Variable temperatur wird für die Anzeige auf dem LCD-Display umgewandelt und dann angezeigt. Vorher jedoch wird die Temparatur, wie weiter oben beschrieben, um eins erhöht!

    if (temp_wrd & (1<<15)) {            //Wenn Minus-Grade angezeigt werden
      if (temp_wrd & (1<<7)) {           //Nachkommastelle erkennen
        temperatur = temperatur +1;
      }
      itoa(temperatur,Buffer, 10 );      //Variable umwandeln...
      lcd_printlc(2,1,Buffer);           //...und anzeigen
    }

Handelt es sich um eine positive Zahle sind ein paar mehr Schritte notwendig. Leider beginnt die positive Zahl nicht mit einem „+“ (Negative haben das „-“ automatisch davor stehen), sodass es manuell gesetzt wird. Anschließend wird auch hier die Temperatur umgewandelt und am LCD-Display ausgegeben. Der Unterschied zur vorherigen „Anzeigeroutine“ ist, dass die X-Position bei positiven Werten nicht bei 1, sondern bei 2 liegt. Denn bei positiven Zahlen wird ja das Vorzeichen nicht ausgegeben, sodass diese hinter dem zuvor gesetzten „+“ beginnen müssen.

    else {
      lcd_printlc(2,1,"+");
      itoa(temperatur, Buffer, 10 );
      lcd_printlc(2,2,Buffer);
    }

Die Temperaturwerte habe ich in die zweite Zeile geschrieben, sodass in der Ersten Platz für eine kleine „Überschrift“ bleibt. Abschließend wird eine halbe Sekunde gewartet um dann von vorne zu beginnen.

    lcd_printlc(1,1,"Temperatur");
    _delay_ms(500);
  }
}

Abschluss

Die I²C-Kommunikation läuft einwandfrei und der LM75 arbeitet zufriedenstellend. Damit läuft eine weitere Funktion des GREETBoard-ATMega128 Extension genau so wie ich es mir vorgestellt habe. Das freut mich echt tierisch!! Dabei hat mir das Datenblatt des LM75 sehr geholfen und ich generell nur empfehlen Datenblätter nicht zu vernachlässigen. Aber für erste Versuche, ist das oben beschriebene Programm wunderbar.

Ich hoffe dieser Artikel war hilfreich und vielleicht finden sich noch ein oder zwei weitere interessante Artikel in meinem Blog. Und wem der Artikel gefallen hat, kann mir ja einen Kommentar hinterlassen. Das würde mich sehr freuen 😉

Alles Gute, Timo

Anhang: Das Programm

#ifndef F_CPU            //Wenn CPU-Takt nicht bereits definiert wurde...
#define F_CPU 16000000   //...dann definiere ihn auf 16MHz
#endif

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "i2clcd.h"
#include "i2cmaster.h"

#define lm75_r 0x90      //Leseadresse des LM75
uint8_t msb_temp;        //Oberes Temperatur-Byte
uint8_t lsb_temp;        //Unteres Temperatur-Byte
uint16_t temp_wrd;       //Ganzes Temperatur-Wort
uint8_t ret;             //Kontrollvariable für I2C Kommunik.
uint8_t x;               //X-Position der Kommastelle
signed char temperatur;  //Variable m. Vorzeichen für die Temp.berechnung
char Buffer[20];         //Umwandlungs-Variable für LCD Anzeige

void temperfassung(void) {
  ret = i2c_start(lm75_r);      //Start Lesen des LM75

  if (ret == 0) {               //Wenn LM75 ein OK sendet...
    msb_temp = i2c_readAck();   //...speichere oberes Bit
    lsb_temp = i2c_readNak();   //...speichere unteres Bit
  }
  else {                        //Wenn LM75 kein OK sendet
    lcd_command(LCD_CLEAR);     // Leere Display
    lcd_printlc(1,13,"READ");   // "Lesevorgang"
    lcd_printlc(2,13,"NOK");    // "Nicht OK (NOK)"
  }
}

int main(void) {
	cli();                     // Interrupts deaktiviert
	i2c_init();                // Starte I2C Bus
	lcd_init();                // Starte I2CLCD
	lcd_command(LCD_CLEAR);    // Leere Display
	lcd_wait_ms(20);           // Warte 20ms wegen Display-Löschung

  while(1) {
    temperfassung();                        //Start der Temp.auslesung
    temp_wrd = (msb_temp << 8 | lsb_temp);  //Zusammensetzung von o. & u. Byte
    temperatur = msb_temp;                  // Umwandlung in ein Signed Char

    // Nachkommastelle erkennen
    if      (temperatur <= -100){x = 5;} //X-Pos. bei <= -100°C)
    else if (temperatur <= -10) {x = 4;} //X-Pos. bei <=  -10°C)
    else if (temperatur <= 9)   {x = 3;} //X-Pos. bei <=    9°C)
    else if (temperatur <= 99)  {x = 4;} //X-Pos. bei <=   99°C)
    else                        {x = 5;} //X-Pos. bei  >   99°C

    if (temp_wrd & (1<<7)) {             //Nachkommastelle erkennen
      lcd_printlc(2,x,",5");             //,5 an Pos x schreiben
    }
    else {
      lcd_printlc(2,x,",0");             //,0 an Pos x schreiben
    }

    if (temp_wrd & (1<<15)) {            //Wenn Minus-Grade angezeigt werden
      if (temp_wrd & (1<<7)) {           //Nachkommastelle erkennen
        temperatur = temperatur +1;
      }
      itoa(temperatur,Buffer, 10 );      //Variable umwandeln...
      lcd_printlc(2,1,Buffer);           //...und anzeigen
    }

    else {
      lcd_printlc(2,1,"+");
      itoa(temperatur, Buffer, 10 );
      lcd_printlc(2,2,Buffer);
    }

    lcd_printlc(1,1,"Temperatur");
    _delay_ms(500);
  }
}

2 Gedanken zu „Die Temperatur messen mit dem LM75

  1. Hi, ich finde deine Seite sehr gut! Top! Ich experimentiere gerade mit dem RaspberryPi und dem LM75. Ich musste mir selber ein neues C Programm schreiben und habe erst jetzt deine Seite entdeckt! xD

    Soweit funktioniert das Ganze bei mir.

    Liebe Grüße.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.