Temperatursensor LM35 stabilisieren

Ich habe gestern meine Lüftersteuerung zusammengelötet.

[Spolier] Realisiert wird das Ganze mit einem billigen CPU-Lüfter und einem BJT, dessen Basis mit dem PWM Ausgang meines Megas verbunden ist und dessen Kollektor und Emitter über einen StepUp Booster/Schaltregler auf 12V verbunden ist. Genauer ist der Emitter mit dem GND des Schaltreglers verbunden und der Kollektor mit dem GND des Lüfters, dessen +12V wiederum mit dem +12V des Schaltreglers verbunden ist. Außerdem ist zwischen +12V und GND des Lüfters eine Schutzdiode, wegen der Induktionsspannung des DC Motors. [/Spolier]

Anfangs gab es größere Probleme mit dem Starten und Stoppen des Lüfters, das ich jetzt aber durch eine art Hysterese etwas in den Griff bekommen habe. Der Lüfter startet also bei meiner festgelegten MindestTemperatur und wenn er gestartet wurde, dann dreht er solange bis (MindestTemperatur - 3) erreicht wurde und geht dann aus.

Anfangs hat der Lüfter wild gedreht und gestoppt - bzw. gepiept nicht gepiept (das mit dem piepen ist schon besser geworden, wird aber noch ausgetestet durch Veränderung der TimerFrequenz).

Jetzt habe ich allerdings ein LM35 Temperatursensor, der anscheinend wirklich ERHEBLICH streut. In meinem Zimmer hier ist es 17,5°C (gemessen mit 3 übereinstimmenden Temperaturmessgeräten).

Die Temperatur wird jede Sekunde einmal eingelesen. Der LM35 gibt Temperaturwerte von 4°C bis 22°C aus. Berechnet wird das so:

int getTemp() 
{  // get the temperature and convert it to celsius
  temp = analogRead(tempPin);
  return temp * 0.48828125;
}

Da das doch wirklich ERHEBLICHE Schwankungen bei einer aktuell stabilen Temperatur sind, habe ich versucht dem etwas entgegen zu wirken, indem ich den Mittelwert berechne:

static int tempMittelWert = 0;
static byte TempWerte[5];

tempMittelWert = 0;
   
   // Werte im TempWerte-Array shiften um Platz für TempWerte[0] zu machen
   for (byte i=4; i>0; i--)   
   {
    TempWerte[i] = TempWerte[i-1];
    tempMittelWert += TempWerte[i];
   }
   
   TempWerte[0] = temp;
   tempMittelWert += TempWerte[0];
   tempMittelWert = tempMittelWert / 5;

Es werden also 5 Messpunkte eingelesen und dann immer der älteste gegen den aktuellen ersetzt. Aus diesen 5 Temperaturwerten ermittele ich ganz plump dem mittelwert indem ich durch 5 teile. Dadurch entstehen dennoch Schwankungen (bei unveränderlicher Temperatur und "eingeschwungen") von 12 bis 19°C. Das ist mir deutlich zu ungenau.

Ist mein Temperatursensor mist oder sind diese Schwankungen üblich und ich muss versuchen, das Ganze durch erhöhen der Messpunkte + Mathematik in den Griff zu bekommen?

Ich hätte eigentlich gerne so etwas wie ein gestuztes oder Winsorisiertes Mittel, weiß allerdings nicht wie man das ordentlich programmiert. Eventuell ginge auch der Meridian, allerdings ist das auch wieder etwas zu "wackelig".

Hat jemand da etwas zur hand oder im Kopf?

Das Datenblatt sagt: Der lm35 ist bis auf 0.5° genau.

Da läuft also irgendwas massiv schief. Aber ka, was. Verkabelung? Stromversorgung?

Wo ist mein post hin? (bin eigentlich hier her gekommen um zu gucken ob jemand schon darauf geantwortet hat. Ok dann eben nochmal..

Hmm also ich verwende ein Mega, dass über USB vom PC gespeist wird. Das Mega selbst bekommt nur den DatenPin vom LM35 an A15 und ein GND von einem 5V Netzteil an dessen GNDPin (bei der POWER leiste). Das LM35 wird über das Netzteil mit +5 und GND versorgt.

Normalerweise sollte das doch klappen oder?

Hast du schonmal das Datenblatt zu Rate gezogen?

Dort steht, dass der LM35 recht empfindlich auf kapazitive Lasten ist. Es wird empfohlen entweder einen längswiderstand in die Messleitung zu setzen, oder einen Lastwiderstand nach GND.

Falls die Zuleitungen zum Sensor länger sind, wird ein Kondensator 10nF zwischen den Versorgungspins empfohlen.

(Quelle: Datenblatt LM35 von TI, Kapitel "TYPICAL APPLICATIONS"

Hallo,

die Referenzspannung für den AD-Wandler ist im Normalfall die Betreibsspannung! Also, wie stabil ist die? Wenn du das Ganze per USB-Kabel versorgst, dann ist das Ganze schon mal Mist. Zum Einen sind die nominellen 5V in den seltensten Fällen genau 5V und zum Anderen bricht diese Spannung bei Last noch ein - also dein Lüfter nebst StepUp Regler. Du hast mehrere Optionen: ein externes Steckernetzteil, damit die Spannungstabil bleibt. Außerdem mit einem Multimeter die Betriebsspannung messen und diesen Messwert in die Formel einsetzen. Variante 2 - verwende eine interne oder externe Referenzspannung. Der nächste von obrigen Maßnahmen unabhängige Punkt ist eine Stabilisierung der analogen Messwerte. Hänge am Analogeingang einen 1µ oder 2,2µF Folienkondensator - keinen Elko - gegen Masse. Außerdem solltest du das Sensorkabel, wenn es länger als 20-30 cm ist schirmen. Also ein geschirmtes Kabel benutzen. Der Schirm wird einseitig, vorzugsweise am Arduino mit Masse verbunden. Ich habe es mit den aufgezählten Maßnahmen und ca. 2m Zuleitung geschafft, auf 1/10° stabile und genaueTemperaturwerte zu bekommen. Mein Projekt war ein Wärmeschrank. Wobei ich das Ganze dann mit einem ATMEGA 328 ohne Arduinoplatine realisiert habe :) Du kannst dir auch den ganzen Stress sparen, indem du einen DS18B20 von Dallas verwendest. Dazu brauchst du nur den Code anpassen. Der Dallas ist komplett abgelichen und liefert ein digitales Datentelegramm, nix Analoges, was erst noch umgerechnet werden muß ;)

Gruß Gerald

Leon333:
Hmm also ich verwende ein Mega, dass über USB vom PC gespeist wird.
Das Mega selbst bekommt nur den DatenPin vom LM35 an A15 und ein GND von einem 5V Netzteil an dessen GNDPin (bei der POWER leiste).
Das LM35 wird über das Netzteil mit +5 und GND versorgt.

Normalerweise sollte das doch klappen oder?

Nur, wenn Arduino GND und LM35 GND mit einander verbunden sind.
Sonst gibts Zufallswerte.

Und ich würde auf die 1,1V Referenz umstellen. Für Raumtemperaturen sollte das reichen und deine Messergebnisse werden erheblich exakter.

Aha!

Also in der zwischenzeit habe ich einen 2. TempSensor verbaut und diesen Direkt mittels Arduino gespeist.
Temperatur komplett stabil!

Dann habe ich den 1. TempSensor über das Arduino Gespeist - Ebenfalls stabil!

@combie:
Meine GNDs sind verbunden gewesen, nur nicht direkt sondern beide gegehen am Netzteil zusammen…
Es muss wohl an den unterschiedlichen ~ +5V liegen.

@nix_mehr_frei:
Warum keinen Elko? Ich habe keine Folienkondensatoren hier :smiley:

Für alle die es interessiert, hier meine nun nicht mehr nötige Funktion zur Berechnung des WinsorMittels.

Ich hab es extra für euch nochmal sauber gecodet, kommentiert und “allgemeingültig” gemacht, weil ich ein paar Besonderheiten habe, bzw. ein paar Sachen (wie zB. einen korrekten Anfangswert) nicht brauche.

static int TempAusleseIntervall = 1000; // Ausleseintervall in ms
byte const anzahlTempMessungen = 7;     // Anzahl der Messpunkte; höher genauer, allerdings mehr Rechenaufwand
static byte tempPin = A0;               // Pin an dem der LM35 TempSensor angeschlossen ist
static int temp;
static boolean initialisiert = false;


int getTemp() 
{   
  temp = analogRead(tempPin); // Temperatur erfassen
  return temp * 0.48828125;   // und in °C Umwandeln
}


int WinsorisiertesMittel() 
{
  static int TempWerte[anzahlTempMessungen];  // MessArray, dass nacheinander bis zu anzahlTempMessungen einliest für eine höhere Stabilität
  static int TempWerteSortieren[anzahlTempMessungen]; // Kopie von MessArray, damit das WinsorMittel errechnet werden kann ohne das eigentliche MessArray zu überschreiben
  
  temp = getTemp();     // Temperatur lesen    
  
  // wenn die Messung gerade begonnen hat, einmal alle Werte mit dem ersten Messwert füllen. Das ist zwar dann ungenau, allerdings genauer, als NULL-Werte zu beginn
  // nach den ersten "anzahlTempMessungen"-Messungen ist der Wert dann gemittelt
  if (initialisiert == false)
  {    
    for (byte i=0; i < anzahlTempMessungen; i++)   
    {
      TempWerte[i] = temp;
    }       
    initialisiert = true;   
  }  
  else
  {
    // Messwerte shiften
    for (byte i = anzahlTempMessungen-1; i > 0; i--)   
    {
      TempWerte[i] = TempWerte[i-1];
    }   
    TempWerte[0] = temp;  
  }
   
  // MessArray kopieren
  for (byte i=0; i < anzahlTempMessungen; i++)   
  { 
     TempWerteSortieren[i] = TempWerte[i];
  }
  
  // TempWerteSortieren der größe nach sortieren
  for(byte i=0; i<(anzahlTempMessungen-1); i++) 
  {
    for(byte j=0; j<(anzahlTempMessungen-(i+1)); j++) 
    {
      if(TempWerteSortieren[j] > TempWerteSortieren[j+1]) 
      {
        int k = TempWerteSortieren[j];
        TempWerteSortieren[j] = TempWerteSortieren[j+1];
        TempWerteSortieren[j+1] = k;
      }
    }
  }
  
  //ersetzen des niedrigsten Wertes
  TempWerteSortieren[0] = TempWerteSortieren[1];  
   //ersetzen des höchsten Wertes
  TempWerteSortieren[anzahlTempMessungen-1] = TempWerteSortieren[anzahlTempMessungen-2];
  
  int WinsorMittel = 0;  
  // berechnung des Winsormittels
  for (byte m=0; m < anzahlTempMessungen; m++)   
  {
    WinsorMittel += TempWerteSortieren[m];
  }
   
  WinsorMittel = WinsorMittel/anzahlTempMessungen;    
  return WinsorMittel;
}

void setup() 
{
  pinMode(tempPin, INPUT);
  Serial.begin(115200); 
}
 
void loop() 
{  

  static unsigned long previousMillis = 0; // speichert wie viele Sekunden seit derletzten Änderung vergangen sind

  if (  (millis() - previousMillis) > TempAusleseIntervall ) 
  {
    previousMillis = millis();  
 
    static int tempMittelWert = 0;
    tempMittelWert = WinsorisiertesMittel();
    
    Serial.print("Die Temperatur ist: "); 
    Serial.print(tempMittelWert);
    Serial.println("\xB0" "C ");
  }   
}

Ein stark wechselnder Meßwert kann 2 Gründe haben: wechselndes Ausgangssignal am LM35; Keine Konstante Referenzspannung am Arduino.

Deinen Aufbau verstehe ich nicht ganz: Hast Du einen Basiswiderstand am BJT? Welche Refernezspannnungsquelle vom Arduino verwendest Du? Woher nimmst Du die Versorgungsspannung für den StepUp Booster/Schaltregler?

Grüße Uwe

also ich habe ein 5V Netzteil.

An dieses ist ein StepUp Booster/Schaltregler angeschlossen. An dem Ausgang des StepUp Boosters/Schaltreglers (12V) ist am GND der Emitter des BJTs und am +12V der +Pol des Lüfers. Der -Pol des Lüfters kommt dann an den Collector des BJTs. Zum Schutz vor Induktionsspannung des Lüfters ist zwischen Kollector und +12V des Schaltreglers parallel eine Schutzdiode. Um den Basisstrom zu begrenzen habe ich einen kleinen Widerstand an der Basis des BJTs, welcher mit dem anderen Ende an PIN 11 des Megas angeschlossen ist.

Das ist die Verkabelung des Lüfters gewesen.

Zum TempSensor:

Dieser war/ist mit GND und +5V mit dem Netzteil verbunden. Das Datensignal des Tempsensors geht an A15 des Megas.

Zusätzlich ist das GND des Megas mit dem GND des Netzteils verbunden, damit die massen überbrückt sind.

Normalerweise sollte das stabil laufen. Da das ganze in einer Box laufen wird, muss es auch alles von dem einen Netzteil gespeist werden.

Zum debuggen, bzw. zum updaten des Programmes muss ich aber mit USB an das Mega dran und damit entstehen anscheinend Probleme.

Ich "könnte" zwar jetzt den Temperatursensor direkt an das Mega schließen (was auch schon zu testzwecken gemacht wurde und herausgekommen ist, dass der Tempsensor wunderbar funktioniert), aber ich müsste dabei die Verkabelung ändern. Zu testzwecken ist das ok, aber in der Box steckt zu viel Arbeit, als das ich jetzt nochmal alles anders verkabeln möchte. Außerdem möchte ich möglichst wenig Kabel in das Mega haben (das werden schon noch genug werden, da es den Lüfter steuert, Temperaturen einliest, IR-Dioden befeuert, einen IR-Transistor liest, über Bluetooth kommuniziert, über WLAN kommuniziert und mit einem Raspberry Pi kommuniziert) damit ich es zur Wartung oder bei Problemen einfacher herausnehmen oder sogar ersetzen kann.

Wie kann nun die Temperatur ausgelesen werden, wenn ich mit USB verbunden bin und der Tempsensor über das NT gespeist werden soll? GND ist ja bereits überbrückt.

Wenn ich das +5V des Netzteils nehme und an die 5V des Megas anschließe, dann wird das zwar gehen, ich riskiere aber, dass ich das Arduino zerstöre, wenn USB angeschlossen ist. Richtig?

Andere Ideen?

Hatte schon mal ein ähnliches Problem mit LM35CZ. Und zwar kann sich der Ausgang des LM35 aufschwingen an dem recht Hochohmigen Eingang des Arduinos. Abhilfe hat bei mir geholfen ein 100nF Kondensator an den Ausgang gegen Masse und den dann noch zusätlich mit einem 2k2 Ohm gegen Masse “belastet”.
Darauf bin ich gekommen sobald ich mein Messgerät an den Ausgang gehalten habe kamen vermeintlich Stabile Werte.
Was auf jeden Fall Hilft ist die Interne Spannungsrefern auf 1.1V zu Stellen dann kann man max 110° bzw 70° Messen mit der “negativTemepratur” Schaltung machen.
Da du einen Mega nutzt kannst du auch die 2,5 V Refrenz nehemen

Wie misst du die Negativen Werte ohne eine Negative Spannungsquelle?

Man kann dies mit dem LM35 mit Hilfe der Schaltung im Anhang machen auch an 5V und mit nur 1 Diode und 1K Widerstand parallel zur Diode.

Ich habe “meinen” LM35 damit stabil bekommen

LM35.JPG

Leon333: @nix_mehr_frei: Warum keinen Elko? Ich habe keine Folienkondensatoren hier :D

Folie, weil ein Elko ein u.U. paar mV wie eine Batterie liefern kann. Ein Folienkondensator ist dagegen wirklich "neutral" MKT oder MKP sind für sowas super.

Um den Basisstrom zu begrenzen habe ich einen kleinen Widerstand an der Basis des BJTs, welcher mit dem anderen Ende an PIN 11 des Megas angeschlossen ist.

Welchen Wert hat der Widerstand?

Grüße Uwe

@volvodani:
Ich habe mittlerweile mal einen 1µF Kondensator und einen 100 Ohm Widerstand (in Reihe) an dem Datenausgang gegen Masse geschaltet - damit bekomme ich auf jeden fall deutlich stabilere Werte.
Auf diese Maßnahme bin ich durch combie und nix_mehr_frei gekommen und habe die Werte an das Datenblatt Seite 7 angelehnt.

Wie genau sind denn deine Werte?
Und ich habe nicht ganz verstanden, ob du den 100nF Kondensator mit dem 2,2kOhm Widerstand in Reihe oder parallel gegen masse geschaltet hast.
Parallel würde aber keinen Sinn ergeben, daher bleibt nur eine Sache übrig, aber ich frage mal lieber nach :smiley:

Die Messwerte schwanken jetzt nur noch leicht in einem 3°C breiten Bereich.
An die im Datenblatt angegebenen 0,5°C oder sogar an die von nix_mehr_frei angegebenen 1/10°C komme ich damit aber natürlich nicht ran.

Meine Datenleitung ist übrigens ungeschirmt und etwa 20cm lang.

Außerdem habe ich die Referenzspannung von 1,1V genommen.
Da die Box im Innenbereich (genauer: Wohnzimmer) ihren Platz finden wird, brauche ich werder Minusgrade noch Temperaturen von über 110°C (hoffentlich :D).

Gemacht wird das so:

static int TempAusleseIntervall = 500;

void leseTemp() 
{ 
static byte temp;

 // get the temperature and convert it to celsius
  temp = analogRead(tempPin);
  temp = temp / 9.31;
  Serial.println(temp);


}


void setup() 
{
  
  pinMode(tempPin, INPUT); 
  analogReference(INTERNAL1V1);
}

void loop() 
{  

  static unsigned long previousTempMillis = 0; 

  if (  (millis() - previousTempMillis) > TempAusleseIntervall ) 
  {
    previousTempMillis = millis();  
 
    leseTemp();
   
  }   
 
}

Ist das soweit vom Programmieren her ok?

@nix_mehr_frei:
ich danke Dir für deine Erklärung!
Leider habe ich keine anderen Bauteile da und möchte auch nicht noch etwas kaufen, wenn es nicht unbedingt nötig ist.
Wenn ich keine Elko hier hätte, dann würde ich aber sicher gleich deiner Empfehlung folgen und das richtige einkaufen :wink:

@uwe:
Der Wiederstand ist 1k Ohm - kommt mir gerade ziemlich viel vor :smiley:
Ich vermute daher, dass der BJT im linearen Bereich betrieben wird, kann das gerade allerdings nicht ausrechnen, weil ich unterwegs bin.

Hat noch jemand Ideen wie ich exaktere Werte bekomme?
Im Prinzip reicht mir diese “Genauigkeit”, da ich dank einer art hysterese den Lüfter ab temperatur x einschalte, aber erst ausmache, wenn die Temperatur x-y ist.
Ist zwar etwas unsauber aber erstmal zweckdienlich solange ich nicht auf eure Genauigkeit komme.