Temperatur (1-3/3)

10. Arduino-Projekt: Temperaturmessung mit digitalem IC DS18B20

Der digitale Temperatursensor DS18B20 ist ein IC (Integrated Circuit), das die Temperaturwerte über einen seriellen Datenbus an den Arduino weitergibt. Laut Datenblatt arbeitet der Sensor in einem Temperaturbereich von -55°C bis +125°C.

Durch die serielle digitale Datenleitung kann der Sensor auch über eine relativ lange Leitung (ein Meter und mehr) ohne Messwertverfälschung angeschlossen werden.

Es gibt im Internet verschiedene "vergossene" Varianten mit Verbindungskabel, z. B. hier: https://www.az-delivery.de:

ds18b20
Quelle: https://www.az-delivery.de

Hardware

Die Verdrahtung des Sensors ist sehr einfach:

ds18b20_schaltplan

Für die Funktion wird der Widerstand R1 (Pullup-Widerstand genannt, weil er die Spannung bei fehlendem Signal auf die Versorgungsspannung hochzieht) benötigt, was im Datenblatt so nicht gleich ersichtlich ist.

Hier der Steckbrettaufbau:

ds18b20_steckbrett

Und so eine reale Verdrahtung:

IMG_20191206_163955

Programmierung

Der serielle Datenbus (1-Wire-Bus) und das vom Sensor verwendete Protokoll erfordern erheblichen Programmieraufwand, zum Glück kann die Arduino-IDE um externe Zusatzmodule (Libraries) erweitert werden und für den Sensor gibt es eine solche. Es werden folgende Libraries benötigt:

Die beiden entpackten Verzeichnisse müssen in das Libraries-Verzeichnis der Arduinoinstallation kopiert werden, z. B. nach C:\Program Files (x86)\Arduino\libraries.
 
/**
 * Temperaturmessung mit dem Sensor D18B20
 */

// Die benötigten Libraries werden eingebunden

#include <OneWire.h>
#include <DallasTemperature.h>

// Definition des Pin, an dem der Sensor hängt

#define SENSOR 9

// Jetzt wird ein OneWire-Instanz mit dem Namen "wire" erzeugt. 
// Das ist eine Variable, die alle Funktionen der Klasse 
// OneWire enthält, wie sie in der OneWire-Library definiert ist. 
// Die Instanz erhält gleich die Pinnumber mitgeteilt an der 
// der Sensor hängt. Das ist die One-Wire-Bus-Verbindung.

OneWire wire(SENSOR);

// Jezt wird eine Instanz der Klasse DallasTemperature
// erzeugt, wie sie in der gleichnamigen Library definiert
// ist. Die Instanz heißt "sensors" und bekommt bei der
// Erzeugung eine Referenz (Zeiger) auf die wire-Variable.
// Dass es sich um eine Referenz handelt, wird durch das
// vorangestellte "&" deutlich gemacht.

DallasTemperature sensors(&wire);

// Die setup()-Funktion

void setup(void)
{
  
  // Serielle Verbindung initialisieren
  
  Serial.begin(9600);

  // Die Library initialisieren
  
  sensors.begin();

}
  

// In der loop()-Funktion werden die Temperaturwerte eingelesen und 
// über die serielle Schnittstelle ausgegeben.

void loop(void)
{
  
  // Die Sensoren am Bus (es sind auch mehrere möglich!) werden
  // angewiesen die Temperaturwerte zu eruieren
  
  sensors.requestTemperatures(); // Send the command to get temperatures

  // Nun werden die Temperaturwerte in Grad Celsius vom ersten (und
  // einzigen) Sensor geholt, der den Index 0 hat.
  
  float temperature = sensors.getTempCByIndex(0);

  // Hier wird geprüft, ob eine sinnvolle Temperatur zurückgegeben
  // wird oder der Wert -127 (der in der DallasTemperature-Library
  // als DEVICE_DISCONNECTED_C definiert ist).
  
  if(temperature != DEVICE_DISCONNECTED_C) {

    // anzeige der Temperatur
    
    Serial.print("Grad Celsius: ");
    Serial.println(temperature);
    
  } else  {

    // Ausgabe einer Fehlermeldung
    
    Serial.println("Error: Die Temperatur kann nicht gelesen werden!");
    
  }
}

 Einige Erläuterungen:

// Die benötigten Libraries werden eingebunden

#include <OneWire.h>
#include <DallasTemperature.h>

Damit der Arduino-Sketch Zugriff auf die Funktionen der Libraries hat, müssen diese ins Programm eingebunden werden, was diese beiden Anweisungen bewirken.

// Definition des Pin, an dem der Sensor hängt

#define SENSOR 9

Das ist ein Variante zu Definition einer Konstante und wirkt im Wesentlichen wie eine const-Definition.

OneWire wire(SENSOR);

In C++ kann man Objekte definieren, die verschiedene Variablen, Konstanten und Funktionen beinhalten. Wir haben das bei der Klasse "Serial" gesehen. Im Gegensatz zur Serial-Klasse wird bei der OneWire-Klasse aber nicht direkt auf die Funktion in der Klasse zugegriffen, sondern es wird zuerst eine Instanz (Objekt) der Klasse mit dem Namen "wire" definiert. Auf diese Weise könnten auch mehrere unabhängige Instanzen der Klasse "OneWire" definiert werden, z. B. wireOne, wireTwo, was notwendig wäre, wenn mehrere Sensoren am Arduino hingen.

Die Klasseninstanz "wire" erhält die Pinnummer SENSOR (Pin 9) gleich bei der Erzeugung mitgeteilt.

DallasTemperature sensors(&wire);

Genauso ist "sensors" eine Instanz der Klasse "DallasTemperature", die in der gleichnamigen Library definiert ist. Die Instanz "sensors" erhält bei der Erzeugung ebenfalls gleich einen Wert übergeben, der allerdings durch das vorangestellte & etwas Besonderes ist, nämlich eine Referenz oder Zeiger auf eine Klasse. Im speziellen Fall eine Referenz auf die Instanz von "wire".

Referenzen sind nicht die Objekte selber, sondern nur Verweise darauf, ähnlich wie Adressen oder Internet-Links. Die Referenz spart Speicherplatz, da das referenzierte Objekt (hier die Instanz "wire") nur einmal mit allem Drum und Dran im Speicher existiert und die Funktionen der Instanz "sensors" trotzdem darauf zugreifen können.

Kniffliges

1. Modifizieren Sie die Hard- und Software so, dass ein zweiter Sensor desselben Typs angeschlossen werden kann.

2. Kombinieren Sie einen analogen Sensor des Typs TMP36 wie hier beschrieben und vergleichen Sie die Messwerte.

Screenshots wurden mit Fritzing erstellt, falls nicht anders angegeben (https://fritzing.org)

Angerer Harald - Freitag, 6. Dezember 2019 - Kategorien: ArduinoTutorials - Noch kein Kommentar ...

6. Experiment Verdunstungskälte

Bei der Verdunstung von Flüssigkeiten (z. B. Wasser) entsteht Kälte. Das kann mit der in "5. Arduino-Projekt: Temperaturmessung mit analogem Temperatursensor" vorgestellten Schaltung experimentell überprüft werden.

1. Ein Wattebausch wird mit Alkohol getränkt, da Alkohol bei Zimmertemperatur viel schneller als z. B. Wasser verdunstet.

IMG_20191206_090514

2. Den Wattebausch mit einem Stück Klarsichtfolie als Isolierung an den Temperatursensor der Schaltung geben und den seriellen Plotter oder den seriellen Monitor starten. Nicht vergessen, die Klarsichtfolie oben zu öffnen, damit die Verdunstung schneller vor sich geht.

IMG_20191206_090530

Jetzt heißt es ein bisschen Geduld aufzubringen und die Temperaturverläufe zu beobachten.

Nach einiger Zeit (10 - 20 Minuten) zeigen sich um 2 - 3 Grad niedrigere Temperaturen:

rtmp://fms.blikk.it/vod_forum:::mp4:neuemedien/fb/uploads/media/video_5dea3e3b321f8.mp4:::./forums/neuemedien/fb/uploads/media/video_5dea3e3b321f8.jpg

Angerer Harald - Freitag, 6. Dezember 2019 - Kategorien: ArduinoExperimente - Noch kein Kommentar ...

5. Arduino-Projekt: Temperaturmessung mit analogem Temperatursensor

Der Sensor

Für dieses Projekt wird der dem Arduino-Kit beiligende Temperatursensor oder ein ähnlicher verwendet:

IMG_20191206_072324TMP36 - Temperatursensor

Der Sensor kann laut Datenblatt mit einer Spannung bis 7V betrieben werden und liefert am Ausgang eine Spannung von 100 mV bis 2000 mV:

tmp36datasheet

Bei 25° C sind das 750 mV. Der Sensor liefert 10mV/1°C und hat einen Temperaturbereich von -40° C bis +125° C:

tmp36datasheet2

Das bedeutet, dass 0° C ein Spannungswert von 750mV - 25 * 10mV = 500mV anliegen.

tmp36datasheet1
Pin-Out des TMP36

Die Hardware

Der Anschluss des Temperatursensor TMP36 gestaltet sich sehr einfach, es wird der Ausgang des Sensors mit dem analogen Eingang A0 des Arduino verbunden:

tmp36schaltung

Und so kann der Aufbau mit dem Steckbrett aussehen:

tmp36aufbau

So könnte der Aufbau in echt aussehen:

IMG_20191206_090335

Programmierung

/**
 * Temperaturmessung mit TMP36
 */

// Pinbezeichnung des analogen Messeingang

const byte sensor = A0;


// In der setup()-Funktion wird die serielle
// Schnittstell zum Anzeigen der Werte initialisiert
// und der Pin "sensor" auf INPUT geschaltet (braucht es
// eigentlich nicht, denn nach dem Reset sind alle
// Pins auf INPUT.

void setup() {

  Serial.begin(9600);

  pinMode(sensor,INPUT);
  
}

// Im loop() wird die Spannung am Pin "sensor" gemessen
// und in eine Tempteraturangabe in °C umgerechnet und
// über die serielle Anzeige (USB-Kabel übernimmt diese
// Funktion) ausgegeben.

void loop() {

  // sensorValue enthält den Rohwert der gemessenen
  // Spannung. Der Arduino kann in der Standard-
  // konfiguration Spannungen mit einer Auflösung
  // von 10 Bit lesen. Damit lassen sich Werte von
  // 0 - 1023, also 1024 Werte abbilden.
  // Als Referenzspannung wird in der
  // Standardkonfiguration dabei die Betriebsspannung
  // von 5V verwendet. Man erhält also Rohwerte 
  // zwischen 0 (0V) und 1024 (5V).
  
  int sensorValue = analogRead(sensor);

  // Umrechnung des Rohwertes in Volt (s. oben)

  float volt = (sensorValue / 1024.0) * 5.0;

  // Umrechnung der Spannung in Temperatur. Die
  // verwendeten Werte ergeben sich aus dem Datenblatt
  // des Sensors.

  float temperature = (volt - 0.5) * 100;

  // Ausgabe der Werte über die serielle Schnittstelle

  Serial.print("Grad Celsius: ");
  Serial.println(temperature);

  // und etwas warten für die nächste Messung

  delay(1000);

}

Was ist neu?

  Serial.begin(9600);

Der Arduino bietet die Möglichkeit Werte und Texte über das USB-Kabel, das im Betrieb als serielle Datenverbindung zum PC fungiert, auszugeben. Die Werte werden mit dem "seriellen Monitor" angezeigt, der über das Symbol oben rechts in der Arduino-IDE geöffnet wird:

arduino_seriellermonitor

Serial : stellt den Bezug zu einer Klasse (oder einem Objekt) mit dem Namen "Serial" her, das fest in Arduino eingebaut ist. Die Klasse "Serial" besitzt eine Funktion "begin()".
Serial.begin() : ruft diese Funktion auf. Der Punkt (.) trennt den Klassen- vom Funktionsnamen.
9600 : gibt die sogenannte Baud-Rate an, das ist die Übertragungsgeschweindigkeit in Bits/s an. Der in der Serial.begin()-Funktion angegebene Wert muss mit den Einstellungen des seriellen Monitors oder des seriellen Plotters übereinstimmen.

 int sensorValue = analogRead(sensor);

analogRead() : die Pins A0 bis A5 können Analoge Spannungswerte mit Hilfe dieser Funktion einlesen, standardmäßig in 10-Bit-Auflösung (0-1023)
int sensorValue : eine Variable vom Typ "integer" (ganzzahlig), die Werte von -32,768 to 32,767 erfassen (ein byte-Typ wäre hier zu klein gewählt)

float volt = (sensorValue / 1024.0) * 5.0;

float volt : definiert eine Varibale mit Namen "volt" vom Typ "float", hier können sogenannte Fließkommazahlen abgespeichert werden, das sind sehr große und sehr kleine Zahlen, auch mit Nachkommastellen
1024.0 und 5.0 : der Punkt ist ein (angelsächsisches) Komma und wird hier angegeben, damit der Compiler, der den Arduino-Sketch in Maschinensprache übersetzt, gezwungen wird, das Ergebnis mit Nachkommastellen zu berechnen (da sensorValue ja eine Ganzzahl ist)

  Serial.print("Grad Celsius: ");
  Serial.println(temperature);

Serial.print : gibt die Zeichenkette "Grad Celsius: " über die serielle Verbindung am PC aus. Die Anführungszeichen markieren eine Zeichenkette, sonst würde der Compiler davon ausgehen, das "Grad" oder "Celsius" Variablen sind
Serial.println : dasselbe wie Serial.print, hängt aber zusätzlich einen Zeilenumbruch (ln) an, so dass die nächste Ausgabe in eine neue Zeile geschrieben wird. Hier wird der Inhalt der Variable "temperature" ausgegeben

Kniffliges

1. Den Aufbau und das Programm so erweitern, das bei jeder Messwertausgabe ein Led kurz blinkt.

2. Die Werte über den seriellen Plotter unter "Werkzeuge" im Arduino-Menu plotten lassen.

 

Screenshots wurden mit Fritzing erstellt, falls nicht anders angegeben (https://fritzing.org)

Angerer Harald - Freitag, 6. Dezember 2019 - Kategorien: ArduinoTutorials - Noch kein Kommentar ...