
LM35 & Arduino, noch ein Temperatursensor Beispiel
Monday, der 22. June 2015
Ich plane in nächster Zeit ein kleines Projekt für welches ein Arduino UNO Temperaturen messen soll. Der Standartsensor für sowas ist der LM35 , der unter anderen von Texas Instruments zu bekommen ist. Das Auslesen eines LM35 wurde schon rech häufig im Netz behandelt und im Grunde ist es nicht sehr schwierig. Machen wir es hier einfach nochmal, aus Spaß an der Freude.
Ich hatte noch eine vage Erinnerung von früher daran, wie der LM35 funktioniert. Deshalb habe ich mir nicht die Mühe gemacht, zuerst die Implementierungen von anderen Leuten anzusehen. Stattdessen entschied ich mich dafür ein paar Minuten zu investieren und zu kucken wie weit ich in ner halben Stunde komme. Der Sensor verfügt über 3 Pins , einen für die Versorgungsspannung , eines für die Masse und eine für das Sensorensignal . Das Signal ist eine analoge Spannung, die proportional zur Temperatur ist. Eine schneller Blick ins Datenblatt verriet mir das Pinout und ne Testschaltung. Wichtig ist ein Stützelko beim AREF Pin des Arduinos. Sonst schwankt der Messwert zu stark.
Das Sensorsignal wird am A0 ‘Analog In’ Pin gemessen. Mein erster Schritt war es, das AnalogReadSerial Beispiel zu verwenden und es ein wenig abzuändern. Das einzige, was wir tun müssen, ist den ADC -Wert in einen Temperatur umzurechnen.
/* AnalogReadSerial - modefied for use with an LM35 This example code is in the public domain. */ #define ref_voltage 5.00 #define volt2temp 100 // the setup routine runs once when you press reset: void setup() { Serial.begin(9600); // initialize serial communication at 9600 bits per second } // the loop routine runs over and over again forever: void loop() { int sensorValue = analogRead(A0); // read the input on analog pin 0: Serial.println(sensorValue * ref_voltage * volt2temp / 1024 ); // print out the value you read delay(1); // delay in between reads for stability }
Die rohen Sensordaten liegen im Bereich zwischen 0 und 1023. 0 bedeutet 0 Volt und 1023 die volle Referenzspannung. Also müssen wir SensorValue zu einem echten Spannung und diese Spannung in die gesuchte Temperatur umrechnen. Dafür habe ich den Messwert mit 5.0 multiplizieren und dann durch 1024 geteilt, der gute alte Dreisatz. Der Grund warum ich mit 5.0 multipliziere und nicht mit 5, liegt darin implizit (nebenbei) das Ergebnis in einen Float-Wert umzuwandeln. Schließlich wird das Zwischenergebnis mit einem Proportionalitätsfaktor multipliziert, um die Temperatur zu bekommen. Laut Datenblatt entsprechen 10mV gleich 1 ° C oder in anderen Worten, 1 Volt entspricht 100 ° C ,
All dies wird in einer Zeile durchgeführt:
Serial.println(sensorValue * ref_voltage* volt2temp / 1024 );
Der Code funktioniert, aber das Ergebnis ist ein wenig seltsam, um nicht zu sagen enttäuschend was die Genauigkeit angeht. Mit einer Raumtemperatur von 23,7 ° C, gibt der Arduino 29.3 ° C aus.
Wenn man darüber nachdenkt, ist die Referenzspannung des Arduino UNO standardmäßig 5V. Da der ADC uns 1024 Werte dazwischen ausgibt, gibt dies uns eine Genauigkeit von etwa 0.00488V pro Schritt. So liegt die Auflösung des ADCs bei 0.48 ° C, was etwas besser ist als die minimum Genauigkeit des Sensors.
Wie sich herausstellt, liegt die große Diskrepanz an der Referenzspannung . In meinem Fall war sie etwa 4.17 (Spannungsversorgung über einen USB Hub). Sobald ich die Referenzspannung korrigierte hatte, bekam ich Werte von 23,62 ° C. Sieht gut aus so weit!
Offensichtlich ist die externe Referenzspannung nicht gut genug. Aber im Grunde funktioniert es ja. Zeit, um sich um zusehen. Die meisten anderen Implementierungen die ich gesehen habe, sind ähnlich.
gunnarherrmann.de beispielsweise kodiert zusätzlich den Pin mit welchen gemessen wird mit einem eigenen Schlüsselwort, dies ist schlau für den Fall, dass mehrere Sensoren verwendet werden. Er mittelt auch seine Werte, um statistische Ausreißer herauszufiltern. Sein Code ist allerdings auch irgendwie seltsam. Zunächst einmal sollten Konstanten immer mit #define und nie als eine Variable deklariert werden. Dies spart einfach RAM. Auch verwendet er ein Array, um die aufeinanderfolgenden Messwerte zu speichern, das ist auch eine Verschwendung von RAM. Die Messungen über die gemittelt werden, liegen 1 Sekunde auseinander, so dass die zeitliche Auflösung nicht mehr wirklich toll ist. Mir gefällt die Code-Wiederholungen auch nicht wirklich.
Andere Seiten wie playground.arduino.cc oder adafruit.com ergeben ähnliche Ansätze. Ich sah ein paar Beispiele, die Verzögerungen zwischen den Messungen verwenden, die meiner Meinung nach nicht notwendig sind. Am interessantesten ist die Verwendung der internen Referenzspannung, die etwa bei 1.1V liegt. Da der ADC die Referensspannung in 1024 Schritte aufteilt, ergibt sich hiermit eine Spannungsauflösung von fast 0.001V. Da der LM35 ohnehin nur für Temperaturen unter 100°C sinnvoll ist und sich damit nur Spannung von maximal 1V ergeben, bleiben wir unter der Referenzspannung. Eine höhere Spannung kann unter Umständen den ADC beschädigen.
Letztendlich hab ich das ganze so gelöst:
/* AnalogReadSerial - modefied for use with an LM35 This example code is in the public domain. */ #define LM35 A0 //Sensor Pin #define ref_voltage 1.08 //actually measured AREF Voltage #define volt2temp 100 #define average_count 50 #define prop_constant ref_voltage* volt2temp / 1024 /average_count // the setup routine runs once when you press reset: void setup() { Serial.begin(9600); // initialize serial communication at 9600 bits per second: analogReference(INTERNAL); } // the loop routine runs over and over again forever void loop() { int sensorValue = 0; // read the sensor multiple times and sum up the readings for (int i = 0; i < average_count; i++) { sensorValue += analogRead(LM35); } Serial.println(sensorValue * prop_constant); //print out the value you read delay(100); // delay in between reads for stability }