Der DS18B20 ist ein Temperatur-Sensor mit einem Messbereich von -55 Grad bis +125 Grad und wird über 1-Wire angeschlossen.
Der BME280 eignet sich gut, um Lufttemperaturen zu messen. Für andere Aufgaben, wie zum Beispiel der Messung der Temperatur am Abgaskrümmer, ist er nicht geeignet. Hierfür eignet sich besser ein DS18B20 mit einem in einer Metallhülle vergossenem Sensor.
Für das Beispiel mit dem DS18B20 ist das Basis-Steckbrett mit dem Bauteil (hier die transistorähnliche Steckversion) zu erweitern. Das sollte dann so aussehen:
Wir nutzen den DS18B20 mit dem 1-Wire-Bus. Dazu ist 3,3 Volt, GND und Signal (GPIO 13) zu verbinden. Zusätzlich muss ein Pull-Up-Widerstand von 4700 Ohm zwischen 3,3 Volt und Signal (GPIO 13) eingesetzt werden. Wenn gerade kein 4.7 kOhm Widerstand zur Verfügung steht, dann geht auch das 10 kOhm Potentiometer (die beiden äußeren Pins).
Ihr müsst übrigens die Schaltungen aus den vorigen Beispielen nicht unbedingt abbauen. Die Beispiele sind so gestaltet, dass sich die unterschiedlichen Beschaltungen nicht in die Quere kommen.
Ein Steckbrett, mit allen Beispielen gleichzeitig gesteckt, sieht dann so aus:
Über den Arduino-IDE Bibliotheksverwalter installieren wir nun die Bibliothek "DallasTemperature". Das geht wieder mit "Sketch", "Bibliothek einbinden", "Bibliotheken verwalten...". Dann "Dallas" im Suchfeld eintragen und die angezeigte Bibliothek "DallasTemperature" installieren.
Nun laden wir das neue Beispielprogramm NMEA200-DS18B20.ino in die Arduino-IDE. Nach dem Hochladen auf den rechten ESP32 sollte der NMEA-Reader ein jetzt schon vertrautes Bild zeigen:
Die Temperatur wird wieder mit dem PGN 130312 gesendet und angezeigt.
Doch wo liegen die Unterschiede zur Temperaturanzeige mit dem BME280?
- Anstatt einen I2C-Bus nutzen wir mit dem DS18B20 einen 1-Wire-Bus.
- Das Auslesen des Sensors per 1-Wire kann bis zu 750 ms dauern (bei 12 Bit Genauigkeit). Wir hatten aber schon gelernt, dass es keine gute Idee ist, die loop()-Ausführung so lange zu verzögern.
- Daher nutzen wir die Multi-Tasking-Fähigkeit des ESP32 und erstellen die Lesefunktion als eigene isolierte Task. Diese funktioniert dann, ohne loop() stark zu beeinträchtigen.
Hier kommen die notwendigen Änderungen zum ersten Beispielprogramm:
Statt der Dateien für den BME280 benötigen wir nun die Informationen für das verwendete DS18B20-Modul:
// Include file for DS18B20
#include <DallasTemperature.h>
Die folgenden Zeilen zeigen die notwendigen Informationen für die Nutzung der Dallas-Temperature-Bibliothek:
// 1-Wire connection for temperature (Dallas DS18B20) is plugged into GPIO13 on the ESP32
#define ONE_WIRE_BUS 13
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
Mit:
volatile double Temperature = 0; // Variable to store Temperature
erzeugen wir noch eine globale Variable zum Speichern der Temperatur. "volatile" ist wichtig, da der Wert sich jederzeit ändern kann.
Nun fügen wir noch die globale Variable "TaskHandle_t Task1" hinzu:
// Task handle for OneWire read (Core 0 on ESP32)
TaskHandle_t Task1;
Gegenüber dem BME280-Programm sind einige Änderungen durchgeführt worden.
Statt des BME280-Moduls starten wir hier den Temperatur-Sensor.
// Start OneWire for DS18B20
sensors.begin();
Anschließend erzeugen wir die neue Task für die Funktion "GetTemperature", zu der wir später noch kommen.
// Create GetTemperature task for core 0, loop() runs on core 1
xTaskCreatePinnedToCore(
GetTemperature, /* Function to implement the task */
"Task1", /* Name of the task */
10000, /* Stack size in words */
NULL, /* Task input parameter */
0, /* Priority of the task */
&Task1, /* Task handle. */
0); /* Core where the task should run */
Zum Auslesen des Temperatursensors wird die Funktion "GetTemperature" genutzt:
void GetTemperature( void * parameter) {
float tmp = 0;
for (;;) { // Endless loop
sensors.requestTemperatures(); // Send the command to get temperatures
vTaskDelay(100);
tmp = sensors.getTempCByIndex(0);
if (tmp != -127) Temperature = tmp;
vTaskDelay(100);
}
}
Die Funktion GetTemperature() wird einmalig bei der Task-Erzeugung in setup() aufgerufen und darf auf keinen Fall verlassen werden (Folge: Absturz des ESP32).
Daher wird mit "for (;;) {" eine endlose Schleife definiert.
In der Schleife wird mit "sensors.requestTemperatures();" und "tmp = sensors.getTempCByIndex(0);" die Temperatur ausgelesen. 1-Wire erlaubt die Nutzung mehrerer Temperatursensoren an einem Bus. Wir nutzen hier nur einen Sensor. Daher "sensors.getTempCByIndex(0)". "0" entspricht erstem Sensor.
Bei einem Fehler beim Lesen wird der Wert auf -127 gesetzt. Nur fehlerfreie Werte werden der globalen Variablen "Temperatur" zugewiesen. Die "vTaskDelay(100);"-Funktionen erzeugen Pausen zwischen den Lese-Versuchen. Hier stören sie nicht.
Die Funktion SendN2kTemperature() unterscheidet sich nur wenig vom ersten Beispiel mit dem BME280.
void SendN2kTemperature(void) {
static unsigned long SlowDataUpdated = InitNextUpdate(SlowDataUpdatePeriod, TempSendOffset);
tN2kMsg N2kMsg;
if ( IsTimeToUpdate(SlowDataUpdated) ) {
SetNextUpdate(SlowDataUpdated, SlowDataUpdatePeriod);
Serial.printf("Temperature: %3.1f °C \n", Temperature);
// Definition from N2kMessages.h
// void SetN2kPGN130312(tN2kMsg &N2kMsg, unsigned char SID, unsigned char TempInstance, tN2kTempSource TempSource,
// double ActualTemperature, double SetTemperature=N2kDoubleNA);
// tN2kTempSource is defined in N2kTypes.h
// Set N2K message
SetN2kPGN130312(N2kMsg, 0, 0, N2kts_ExhaustGasTemperature, CToKelvin(Temperature), N2kDoubleNA);
// Send message
NMEA2000.SendMsg(N2kMsg);
}
}
Statt einer lokalen Variable "double Temperature" und dem Auslesen des BME280, wird hier einfach direkt die globale variable "Temperature" als Argument in der Funktion "SetN2kPGN130312" genutzt.
In loop() rufen wir natürlich auch wieder SendN2kTemperature() auf:
void loop() {
SendN2kTemperature();
NMEA2000.ParseMessages();
CheckSourceAddressChange();
So, jetzt können wir auch Sensoren mit dem 1-Wire-Bus verwenden.
Im nächsten Teil sehen wir, wie wir Spannungen und Widerstände messen können.