Temperatursteuerung mit DS1820

Hallo allerseits,

vor wenigen Tagen bin ich im Netz zufällig über Arduino gestolpert - oute mich nun als Anfänger :stuck_out_tongue: -und wollte mein erstes Projekt meiner Gartendusche widmen:
Ein in der Sonne liegender Schlauch soll bei genügend Temperaturunterschied eine in einem Fass liegende Lenzpumpe ansprechen.

Siehe meine Mausgrafik dazu im Anhang :%

Ich kopierte also die DS1820-Bibliothek und ~Beispiele in das Arduino-Tool. Ich fand aber nur Beispiele einer Temperaturanzeige, keines über eine Steuerung damit.
Ich nahm also dann das Temperatur-Tester-Skript und probierte einige Zeit, die Werte - den Temperaturfühler und Temperatur - in eine Varible zu verpacken. Dann kam ich dann zu dieser Lösung, welche zu funktionieren scheint:

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

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 3
#define TEMPERATURE_PRECISION 9

int DEVICE = 0;
float WERTX = 0;
float WERTY = 0;
float WERTDEV0 = 0;
float WERTDEV1 = 0;

// 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);

int numberOfDevices; // Number of temperature devices found

DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address

void setup(void)
{
  // start serial port
  Serial.begin(9600);
  Serial.println("Dallas Temperature IC Control Library Demo");
  pinMode(13, OUTPUT);
  
  // Start up the library
  sensors.begin();
  
  // Grab a count of devices on the wire
  numberOfDevices = sensors.getDeviceCount();
  
  // locate devices on the bus
  Serial.print("Locating devices...");
  
  Serial.print("Found ");
  Serial.print(numberOfDevices, DEC);
  Serial.println(" devices.");
  
  //DEVICE=(numberOfDevices, DEC);
  
  // report parasite power requirements
  Serial.print("Parasite power is: "); 
  if (sensors.isParasitePowerMode()) Serial.println("ON");
  else Serial.println("OFF");
  
  // Loop through each device, print out address
  for(int i=0;i<numberOfDevices; i++)
  {
    // Search the wire for address
    if(sensors.getAddress(tempDeviceAddress, i))
	{
		Serial.print("Found device ");
		Serial.print(i, DEC);
		Serial.print(" with address: ");
		printAddress(tempDeviceAddress);
		Serial.println();

		Serial.print("Setting resolution to ");
		Serial.println(TEMPERATURE_PRECISION,DEC);
		
		// set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
		sensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION);
		
	        Serial.print("Resolution actually set to: ");
		Serial.print(sensors.getResolution(tempDeviceAddress), DEC); 
		Serial.println();
	}else{
		Serial.print("Found ghost device at ");
		Serial.print(i, DEC);
		Serial.print(" but could not detect address. Check power and cabling");
	}
  }
}

// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
  // method 1 - slower
  //Serial.print("Temp C: ");
  //Serial.print(sensors.getTempC(deviceAddress));
  //Serial.print(" Temp F: ");
  //Serial.print(sensors.getTempF(deviceAddress)); // Makes a second call to getTempC and then converts to Fahrenheit

  // method 2 - faster
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print("Temp C: ");
  Serial.print(tempC);
  delay(5000);  // 5 Sekunden Pause

  //beide Variablen uebertragen die Temperatur, WERTY nur zu Testzwecken, wird nicht weiter ausgewertet
  WERTX=(tempC);
  WERTY=(sensors.getTempC(deviceAddress));

  //Serial.print(" Temp F: ");
  //Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}

void loop(void)
{ 
  // call sensors.requestTemperatures() to issue a global temperature 
  // request to all devices on the bus
  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");
 
   // Loop through each device, print out temperature data
  for(int i=0;i<numberOfDevices; i++)
  {
    // Search the wire for address
    if(sensors.getAddress(tempDeviceAddress, i))
	{
	     // Output the device ID
	     Serial.print("Temperature for device: ");
	     Serial.println(i,DEC);

             DEVICE=(i);

	     // It responds almost immediately. Let's print out the data
	     printTemperature(tempDeviceAddress); // Use a simple function to print out the data
             Serial.print("\n");
             Serial.print("\n"); 
          
             switch (DEVICE)
             {
             case 0:
             //definiere Inhalt Device 0
             WERTDEV0=(WERTX);
             case 1:
             // definiere Inhalt Device 1
             WERTDEV1=(WERTX);
             }
             
             //geht nur richtig, wenn DEVICE gleich 1 ist, sonst haben 0 und 1 gleiche Werte...
             if (DEVICE == 1)
             {   
               Serial.print("Temp.0:  ");
               Serial.print(WERTDEV0);
               Serial.print("\n");
               Serial.print("Temp.1:  ");
               Serial.print(WERTDEV1);
               Serial.print("\n");
               Serial.print("\n");
               
               if (WERTDEV0 > WERTDEV1)
               {
                 digitalWrite(13, HIGH);
               }
               else
               {
                 digitalWrite(13, LOW);
               } 
               
             }
             
         } 
	//else ghost device! Check your power requirements and cabling
	
  }
}

// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
   }
}

Wenn nun Temperaturfühler Device 0 einen höheren Wert als Device 1 besitzt, so wird Pin13 angesteuert.
Allerdings werden die Variablen von Device 0 und Device 1 nur dann richtig gesetzt, wenn Device 1 ausgegeben wird. Das verstehe ich nicht, habe es aber mit einer if-Anweisung abgefangen :cold_sweat:

Gibt es für diesen Zweck mit den DS1820 schon eine Lösung, welche evtl. etwas eleganter ist?

Beste Grüße
Jörn

Gartenpumpe.jpg

Hallo Jörn,
ich habe mir eine Heizungssteuerung gebaut incl. Solaranlage und Kachelofen, wobei der Kachelofen einen Wasserkreislauf besitzt und sowohl Warmwasser als auch Heizung beliefert. Das ist ja im Prinzip nichts anderes als das was du machst.
Es geht sicherlich viel einfacher, hier mal ein Beispiel, welches alle 8 Sekunden 6 Dallas 18B20 einliest:
delay halt ich für ziemlich ungünstig, warum das Programm anhalten?

void SensorLesen(){
 jetzt = millis();
 if(jetzt - vorher > 8000){ //Sensoren werden nur alle 8 sec gelesen
  sensors.requestTemperatures();
  Temperatur[0] = sensors.getTempC(Sensor0); Temperatur[1] = sensors.getTempC(Sensor1);
  Temperatur[2] = sensors.getTempC(Sensor2); Temperatur[3] = sensors.getTempC(Sensor3);
  Temperatur[4] = sensors.getTempC(Sensor4); Temperatur[5] = sensors.getTempC(Sensor5);
  vorher=millis();
 }
}

Falls du Fragen hast melde dich.
Gruß
Bernward

Hallo Bernward,

danke Dir für die rasche Antwort. Die Lösung von Dir ist das, was ich suche...

Das sind meine Anfängerfehler und ~Probleme, ich beschäftige mich erst seit ein paar Stunden mit dem Arduino und habe mit den Befehlssatz und der Syntax etwas zu kämpfen :~

Ich wusste nicht, dass ich mit delay des Programm anhalte, ich habe es irgendwo aufgeschnappt und eingebastelt...
Wo ich richtig am grübeln war, ist den Temperaturfühler zu definieren und ihm einen Wert zuzuweisen.
Das hast Du ja mit deiner Funktion sensors.requestTemperatures(); ja sauber hinbekommen. :slight_smile:
Wie hast Du die Varible oder Adresse(?) Sensor(N) bei sensors.getTempC(...) definert?

Viele Grüße
Jörn

Hallo Jörn,
als erstes die Deklaration hier nur das wichtigste:

#include <OneWire.h>
#include <LiquidCrystal.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 22 // alle Temperaturfühler an PIN 22
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
float Temperatur[6];
int sensoranzahl, 
unsigned long vorher, jetzt;
// Sensoren 0-5 feste Vorgabe der Seriennummern der Temperatursensoren
DeviceAddress Sensor0 = {0x28, 0xBB, 0x7B, 0xDA, 0x02, 0x00, 0x00, 0xA9};
DeviceAddress Sensor1 = {0x28, 0xA3, 0x82, 0xDA, 0x02, 0x00, 0x00, 0x06};
DeviceAddress Sensor2 = {0x28, 0x0C, 0x9E, 0xDA, 0x02, 0x00, 0x00, 0x23};
DeviceAddress Sensor3 = {0x28, 0x06, 0xCB, 0xDE, 0x02, 0x00, 0x00, 0xA5};
DeviceAddress Sensor4 = {0x28, 0x13, 0x81, 0xDA, 0x02, 0x00, 0x00, 0x4F};
DeviceAddress Sensor5 = {0x28, 0x47, 0xFA, 0x8D, 0x02, 0x00, 0x00, 0xFE};

bei der festen Vorgabe kannst du die Sensoren nachher stecken wie du willst, mit Sensor0 wird immer der erste angesprochen, egal wo er
in der Reihe angeschlossen ist.

Im void setup kannst du bei Bedarf einmalig die Anzahl der Sensoren ermitteln:

 sensors.begin(); sensoranzahl=sensors.getDeviceCount(), DEC;

Der Rest wird in SensorLesen gemacht.

Und jetzt noch ein Beispiel für die Pumpe, hier am Beispiel der Solarpumpe:
das mit dem start[], beginn[] ende[] und Laufzeit[] kannst du weglassen, hier berechne ich die Laufzeiten der einzelnen Pumpen und gebe diese im LCD-Display aus.

void SolarPumpe(){ 
  // Pumpe (Solaranlage) stellt sich ein, wenn Wasser um Solardiff wärmer ist als im Speicher und gleichzeitig wärmer als Solarminwert ist
  // Pumpe (Solaranlage) stellt sich aus wenn Temperatur in Solaranlage <= Temperatur+3 im Speicher ist 
 flag=1;
 if (Temperatur[4] > Temperatur[2] + Solardiff && Temperatur[4] > Solarminwert){
  flag=0; 
  if (!start[3]){
   beginn[3] = int(millis()/1000); start[3] = true;
  }
 }
 if (Temperatur[4] <= Temperatur[2] + 3){
  flag=2; 
  if (start[3]){
   ende[3] = int(millis()/1000); start[3] = false;
   Laufzeit[3] = Laufzeit[3] + int(ende[3] - beginn[3]);
  }
 }
 if (flag == 0) digitalWrite(Relais03, HIGH); 
 if (flag == 2) digitalWrite(Relais03, LOW); 
}

noch ein Tip, ich würde allen Variablen "erklärende Namen" geben, wenn du mal richtig lange Programme mit
vielen Variablen hast ist es absolut von Vorteil, wenn der Name schon aussagt, worum es geht.
Und schließlich sind wir hier in einem deutschsprachigen Forum, warum dürfen Variablen dann nicht auch
deutsche Namen haben.
Gruß
Bernward

Hallo joe-eis

Ich weiß, daß ich wieder mal den Bösen spiele :wink:

Versuch zuerst mal ein Buch über Arduino zu lesen oder das offizielle Tutorial http://arduino.cc/en/Tutorial/HomePage durchzuarbeiten um etwas Gefühl für den Arduino zu bekommen.

Viele Grüße Uwe

Hallo Bernward,

ich danke für die ausführlichen Beiträge und Tipps, nun habe ich eine gute Vorlage für mein Projekt :slight_smile:

Hallo Uwe,

für den Einstieg hatte ich ich etwas Lektüre von freeduino.de, das ist ausreichend für einfache Standartsituationen und leichtverständlich, wenn man etwas Shell kann.
Danke Dir aber für den Link, ich werde bestimmt auf dies oder jenes Beispiel zurückgreifen. Heute lagen mein Display von tuxgraphics.org im Postkasten :wink:
Die Ansprech-Methodik der Dallas/Maxim 1-Wire Bausteine (DS1820, DS2413,...) wird aber hier nicht erläutert :cold_sweat:

Viele Grüße
Jörn

Such einfach mit eine Suchmaschiene "Arduino" und "1820"
Dann findest Du zB das hier: Arduino Playground - OneWire
Viele Grüße Uwe

Verdammt, Du hast recht. Der 3. Treffer ist es :~

Viele Grüße
Jörn

Auf dem Playground sind jede Menge Beispiele und Erklährungen der verschiedensten Hardware. Schau Dich dort auch mal um.
Viele Grüße Uwe

Hallo,

ich habe nun fertig :wink: und möchte mich für die Tipps bedanken.
Es ist nun ein Sketch entstanden, welche ich auch verstehe und deren Genauigkeit der Temperaturerkennung höher (?) ist:
Bernward, Du wirst Teile deines Codes wiedererkennen :wink:

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

// Data wire is plugged into port 8 on the Arduino
#define ONE_WIRE_BUS 8
#define TEMPERATURE_PRECISION 9

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// 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);

float Temperatur[2];
float TempDiffAn = 4;
float TempDiffAus = 1;
float TempStart = 20;
float TempEnde = 40;
int Zustand = 0;
unsigned long vorher, jetzt;

// Sensoren 0-1 feste Vorgabe der Seriennummern der Temperatursensoren
DeviceAddress Sensor0 = {0x28, 0x10, 0x26, 0xBB, 0x02, 0x00, 0x00, 0x6B};
DeviceAddress Sensor1 = {0x28, 0x30, 0x3F, 0xEC, 0x02, 0x00, 0x00, 0x0C};

void setup() {
  Serial.begin(9600); // Serielle Schnittstelle initiieren
  sensors.begin(); // Start up the sensor library
  pinMode(13, OUTPUT); //
  
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
}

// liest aller 10 Sekunden Dallas 18B20 ein
void loop(){
 jetzt = millis();
 if(jetzt - vorher > 10000){ //Sensoren werden nur alle 10 sec gelesen
  sensors.requestTemperatures();
  Temperatur[0] = sensors.getTempC(Sensor0);
  Temperatur[1] = sensors.getTempC(Sensor1);
  vorher=millis();
  
  // Die Variablen-Inhalte
  Serial.print("\n");
  Serial.print("Variablen-Wert fuer Device 1 is: ");
  Serial.print(Temperatur[0]);
  Serial.print("\n");
  Serial.print("Variablen-Wert fuer Device 2 is: ");
  Serial.print(Temperatur[1]);
  Serial.print("\n");
  
  // Temperatur 1 = Solarschlange, Temperatur 2 = Duschfass
  // Pumpe soll anspringen, wenn Temperatur 1 um 4 Grad oder mehr höher als Temperatur 2  ist
  // Pumpe soll ausgehen, wenn Temperatur 2 um 1 Grad oder mehr kälter als Temperatur 2 ist
  // Pumpe soll nicht angehen, wenn Temperatur 1 kälter als 20°C ist
  // Pumpe soll nur angehen, wenn Temperatur 2 kälter als 40°C ist
  
  if (Temperatur[0] > Temperatur[1] + TempDiffAn && Temperatur[0] > TempStart && Temperatur[1] < TempEnde) {
     digitalWrite(13, HIGH);   // set the LED on
     Zustand = 1;
     }
     if (Temperatur[0] < Temperatur[1] + TempDiffAus) {
     digitalWrite(13, LOW);   // set the LED off
     Zustand = 0;
     }
     
  }
     lcd.setCursor(0, 0);
     lcd.print("Solar: ");
     lcd.print(Temperatur[0]);
     lcd.print(" C");
     
     lcd.setCursor(0, 1);
     lcd.print("Fass:  ");
     lcd.print(Temperatur[1]);
     lcd.print(" C");

     // belege das 16. Zeichen der 2. Zeile, bei Pumpe=1 soll dort ein P erscheinen:
     lcd.setCursor(15, 1);
     if (Zustand == 1) {
        lcd.print("P");
        }
     else {
        lcd.print(".");
        }
}

Grüße
Jörn

Übrigens, der Stromverbrauch liegt (bei Vin = 6V) so bei 57 mA, wobei ca. 10 mA auf die LCD-Beleuchtung entfallen.

DS1820_LCD_Ardino.jpg

DS1820-Anschluss.png

Hallo Jörn,
freut mich wenn ich helfen konnte, man muß ja nicht alles selber erfinden, wenn es das schon gibt.
Allerdings hab ich meine 6 Dallas 18B20 anders verschaltet als du in Bild 1.
Ich habe bei allen Pin 1 und 3 miteinander verbunden und auf Masse gelegt.
Und die +5V bei allen an Pin2 und den Arduino.
Gruß
Bernward

Hallo Bernward,

Ich habe bei allen Pin 1 und 3 miteinander verbunden und auf Masse gelegt.

Das Prinzip habe ich so aus dem Buch "Arduino Praxiseinstieg von Thomas Brühlmann" übernommen.
Mit +5V an Pin 3 wird der Master auf dem Bus definiert, der bzw. die anderen Bus-Mitglieder werden mit Masse auf diesem Pin als Slave definiert.
In wie weit das in der Praxis notwendig ist ..??

Interessant ist jedenfalls die höhere Genauigkeit gegenüber des Sketches meines ersten Beitrages.
Es war erst eine Auflösung von 0,5 Volt, wobei die beiden Sensoren schon beim Programmstart um diesen Betrag abwichen.
Nun ist die Ausgabe nach dem Komma zweistellig, beim Start zeigen beide Temperaturen den gleichen Betrag an und die Temperatursprünge liegen nun bei 0,06 °C.

Schön wäre auch eine Forum-Abteilung mit kompletten, nachbaufähigen Projektvorstellungen :wink:

Viele Grüße
Jörn

Die Beschaltung des DS1820 hat nach meinem Kenntnisstand nichts mit Master oder Slave zu tun, hier geht es schlichtweg um die Spannungsversorgung des Sensors. Die kann nämlich auf zwei Weisen erfolgen: extern (und somit 3 Leitungen zum Sensor) oder aber "parasite powered" (und damit über zwei Anschlussleitungen). Näheres dazu findet man im Datenblatt des Sensors.

Schön, das Du richtig liegst:

Nun spare ich einen Draht ein :wink:

Gruß
Jörn