DS18B20 als defekt erkennen

Hallo zusammen

ich verwende in meiner Solaranlagensteuerung zwei DS18B20 Temperatursensoren die an einem Eingang hängen .
Als Defekterkennung habe ich bis jetzt ,die Abfrage ob die Temperatur unter einen bestimten Wert gesunken ist, verwendet.
Aber es gibt auch Situationen bei denen die Temperatur dann bei 85°C ligt. Da funktioniert die Plausibilitätsabfrage nicht .

Gibt es da ein eleganteren Weg um die korrekte Funktion der Sensoren zu überprüfen?

Wie wäre es mit Redundanz?
Daran könnten auch defekte und Unplausibilitäten erkannt werden.

Ich kenne mich mit den DS18B20 recht gut aus. Ich habe auch ein paar "teils" defekte Sensoren. Sie funktionieren unter bestimmten timing Umständen gut, unter anderen Umständen garnicht. Eine Erkennung ob defekt oder nicht kenne ich von DS aus nicht.
Frägst du auch die 127,5°C als Defekt ab?

Hi
Danke für die promte Antwort.
Das mit der Redundanz verstehe ich jetzt nicht.
Zur Zeit frage ich die Temperatur der Sensoren unter 8°C sind. Wenn ja dann wird der Sensor als defekt deklariert.
Dies funktioniert aber nur wenn vom Sensor keine Daten kommen wenn z.B. die + Leitung eines Sensors fehlt dann wir 85°C angezeigt und in Diesem Fall wird der Sensor nicht als defekt deklariert.

Rudi01:
...
Das mit der Redundanz verstehe ich jetzt nicht.
...

Mehrere Sensoren (zwei oder drei) und dann gegeneinander die Temp überprüfen.

Wenn eine Leitung des Sensors fehlt, dann fehlt er auch bei der Adressabfrage in der Lib. Du musst natürlich regelmäßig die Anzahl der Sensoren und deren Adressen über die Lib abfragen.

Ich denke, die Sensoren liefern einfach "nix", wenn sie kaputt sind. Die 85 °C entstammen der lib (DS18S20.cpp):

    if (present==0) {
      ds18s20[no].temp=85.0;
      return;
      }

Mache da einfach etwas, das außerhalb der Sensor-Norm liegt) hin, z.B. -200°C, schon ist es sinnvoll prüfbar.

@mde110 meinst du nicht -127°C ??
Das zeigen meine jedenfalls an, wenn sie z.B. nicht erreichbar sind.

@mwyraz: guter Ansatz, ich hab immer gedacht,das die 85° vom DS18B20 kommen.
Da es diesen Wert aber auch real gibt, war hier eine Abfrage auf defekt schwierig.
Wenn das aber aus der lib kommt, dann kann man ja auch einen wirklich unrealistischen Wert einsetzen um abzufragen.
Werde ich mal testen.
Gruß

Wenn eine Leitung des Sensors fehlt, dann fehlt er auch bei der Adressabfrage in der Lib. Du musst natürlich regelmäßig die Anzahl der Sensoren und deren Adressen über die Lib abfragen.
Genau sowas schwebt mir vor doch wie wird sowas gemacht?

Rudi01:
Gibt es da ein eleganteren Weg um die korrekte Funktion der Sensoren zu überprüfen?

Also ich persönlich kenne ja gar nix von DS18B20 Sensoren, aber wenn ich mir die Arduino-Library zum Sensor ansehe, dann sehe ich dort, dass der Sensor seine Daten mit einer CRC Prüfsumme sendet und die Library eine Funktion zum Berechnen des CRC-Wertes aus den Daten hat.

Der elegante Wert zum Prüfen auf gültige Werte vom Sensor dürfte also darin bestehen:

  • Daten mit CRC Prüfsumme vom Sensor empfangen
  • Aus den Daten (ohne CRC Prüfsumme) selbst die CRC Prüfsumme errechnen
  • Feststellen, ob die vom Sensor gesendete Prüfsumme mit der errechneten Prüfsumme übereinstimmt
    Und dann nur davon ausgehen, dass gültige Daten vom Sensor empfangen wurden, wenn die vom Sensor empfangene Prüfsumme mit der selbst aus den empfangenen Daten errechneten Prüfsumme übereinstimmt.

jurs:
Also ich persönlich kenne ja gar nix von DS18B20 Sensoren, aber wenn ich mir die Arduino-Library zum Sensor ansehe, dann sehe ich dort, dass der Sensor seine Daten mit einer CRC Prüfsumme sendet und die Library eine Funktion zum Berechnen des CRC-Wertes aus den Daten hat.

Der elegante Wert zum Prüfen auf gültige Werte vom Sensor dürfte also darin bestehen:

  • Daten mit CRC Prüfsumme vom Sensor empfangen
  • Aus den Daten (ohne CRC Prüfsumme) selbst die CRC Prüfsumme errechnen
  • Feststellen, ob die vom Sensor gesendete Prüfsumme mit der errechneten Prüfsumme übereinstimmt
    Und dann nur davon ausgehen, dass gültige Daten vom Sensor empfangen wurden, wenn die vom Sensor empfangene Prüfsumme mit der selbst aus den empfangenen Daten errechneten Prüfsumme übereinstimmt.

Das macht die Lib schon.

...
  Valid = _wire->crc8(deviceAddress, 7) == deviceAddress[7];
...
  readScratchPad(deviceAddress, scratchPad);
  isConn = _wire->crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC];
...

Rudi, wie ist es nun mit Redundanz aus?

Rudi01:
Genau sowas schwebt mir vor doch wie wird sowas gemacht?

// returns true if address is valid
bool validAddress(uint8_t*);

// attempt to determine if the device at the given address is connected to the bus
bool isConnected(uint8_t*);

Hi

also das mit der Redundanz ist an sich keine schlechte Idee.Doch da muss ich a für jeden Messwert 2 Sensoren vorsehen da wird`s in den Themeraturmeßröhrchen ein wenig eng.
Außerdem muss dann der redundant Sensor über eine eigene Stomversorgung und auch einen separaten Dateneingang verfügen.

Leider kenne ich mich in der Programmierung noch nicht so gut aus.

Könnte mir da vielleicht jemand das ein wenig erklären.
bool validAddress(uint8_t*);

Lässt sich da nichts mit einer Art Adressabfrage machen.
Ich suche mal den Code und stelle ihn mal hier ein.

Du kannst "beliebig" viele DS1820 an eine Leitung hängen. D.h. einfach "Huckepack" übereinander löten.
Allerdings ist zu beachten, dass bei der 2-Draht-Variante die Sensoren einer nach dem anderen ausgelesen werden müssen - mit genügend Zeit dazwischen, um den internen Kondensator aufzuladen. Bei der 3-Draht-Verkabelung kannst Du alle direkt auslesen ohne warten zu müssen.

Hintergrund:

Dei der 2-Draht-Variante (Parasitic Power genannt) laden die Sensoren einen internen Kondensator über den Pegel auf der Signalleitung auf. Beim Senden wird die Leitung ja immer kurz auf Masse gezogen, es steht also keine Versorgungsspannung zur Verfügung. Der interne Kondensator reicht aber, dass einer der Sensoren seine Daten senden kann. Die Kondensatoren der ggf. vorhandenen weiteren Sensoren sind in der Zwischenzeit aber leer. D.h. es muss mind. die Zeit für eine neue Messung gewartet werden, bevor der nächste Sensor ausgelesen werden kann.

Bei der 3-Draht-Variante wird der Sensor über eine extra Leitung dauerhaft mit Strom versorgt. Damit kann man die Daten mit der Geschwindigkeit auslesen, die der 1-Wire-Bus hergibt.

In jedem Fall können viele (bis zu einigen Hundert?) 1-Wire-Sensoren über zwei bzw. drei Adern angeschlossen werden und benötigen alle zusammen nur einen Daten-Pin vom Arduino.

Wenn möglich, würde ich immer die 3-Draht-Variante wählen.

Ich verwende die 33-Draht Variante .Doch wenn mal die Versorgungsspannung ausfällt oder die Masseverbindung oder was auch möglich wäre ein defekter Sensor zieht die Datenleitung nach Masse oder Plus und schon funktioniert das mit der Redundanz auch nicht mehr.
Ich finde eine korrekte Redundanz sollte aus zwei möglichst getrennten Systemen bestehen.

Kommt darauf an, was du mit der Redundanz absichern möchtest. Wenn die Leitung defekt ist (oder ein Sensor auf Masse zieht), bekommst du keine Sensordaten und weißt, dass da was faul ist. Um dennoch eine Temperatur zu erhalten, benötigst Du eine zweite Sensorstrecke.

Wenn der Arduino defekt sein könnte, bräuchtest du einen zweiten, um den redundant auszulegen.

Wenn Du nur sicherstellen möchtest, dass Du keine falschen Sensordaten bekommst (also ein Sensor falsch misst, jedoch formal korrekte Signale in den Bus sendet), benötigst Du 2 Sensoren an einem Kabel.

Wenn Du 2 "relativ" unabhägige Sensoren haben willst, benötigst Du 4 Adern (Masse, Versorgung, 2x Daten).

Es geht mir nicht darum die Daten auf jeden Fall zu erhalten sondern eine falsche Temperaturübermittlung und die daraus entstehenden fehlerhaften Programmschritte zu vermeiden.

Wir drehen uns im Kreis.
Poste mal deinen Sketch und lass uns sehen was du bereits hast und was es kann.

Hi

jetzt komme ich endlich an den Sketch.

/*
  Differenztemperatursteuerung Sonnenkolektor mit 1XPT100 im Kollektor
                                                  1XDS18B20 im Speicher 1
                                                  1XDS18B20 im Speicher 2
*/

// Laden der Libary:
#include <LiquidCrystal.h>
#include <OneWire.h>
#include <DallasTemperature.h>

// initialisieren der LCD Pins ( Für das Orginal Arduino-Pad )
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);


#define ONE_WIRE_BUS A3

///char buffer[20] = "";                                     // Speicherbereich für Datenkonvertierung

OneWire oneWire(ONE_WIRE_BUS);                            // Library für Datenleitung des Tempatursensors Dallas DS18xx 
DallasTemperature sensors(&oneWire);


//die Variablen deklarieren

float tempK;
float tempS1;
float tempS2;
int tempPin1 = 1;
int Pumpe1 = 13;
int Pumpe2 = 12;
int SpeichertempPin1 = A3;        //Temperatur SpeichertempPin1 wird an Analogpin3 angeschlossen
int DifferenztemperaturS1 = 0;      //Hier nichts eingeben
int DifferenztemperaturS2 = 0;      //Hier nichts eingeben
int Schalttemperatur = 14;         //Hier die Schalttemperatur der Differenz Kolektor -> Speicher, bei der die Pumpe gestartet wird, eingeben
int SpeicherTempAusStufe1 = 50; //Hier schaltet die Ladund auf den anderen Speicher um
int SpeicherTempladebereit = 70;//Hier schaltet die Ladepumpe wieder ein
int SpeicherTempAusVoll = 75; //Hier schaltet die Ladung entgültig aus
int SpeicheTempVollwiederBereit =31; //Hier ist der Speiche wieder bereit für die Ladung Stufe 1
int SpeicherTempMax = 85;         //Hier die Maxtemperatur des Speichers, bei der die Pumpe ausgeschaltet wird und eine Fehlermeldung ausgegebeb wird ( muss quittiert werden ) eingeben
int KolektorTempMax = 130;        //Hier die Maxtemperatur des Kolektors, bei der die Pumpe ausgeschaltet wird  und eine Fehlermeldung ausgegebeb wird ( muss quittiert werden ) eingeben
int KolektorTempMaxHysterese = 2; //Hier die Hysterese der Ausschaltemperatur des Kolektors, bei der die Pumpe wieder eingeschaltet wird, eingeben
int SpeicherTempUnplausibel = 8; //Unter 8°C ist Meßwert im Speicher unplausibel
int FehlereldungSpeicher1MaxVariable = 0; //zum speichern des Fehlers auch wenn die Fehlerursache wieder verschwindet
int FehlereldungSpeicher2MaxVariable = 0; //zum speichern des Fehlers auch wenn die Fehlerursache wieder verschwindet
int FehlereldungSpeicher1UnplausibelVariable = 0; //zum speichern des Fehlers auch wenn die Fehlerursache wieder verschwindet
int FehlereldungSpeicher2UnplausibelVariable = 0; //zum speichern des Fehlers auch wenn die Fehlerursache wieder verschwindet
// Datendraht an Pin A3
#define ONE_WIRE_BUS A3


DeviceAddress SensorS1 = { 0x28, 0xB2, 0x4B, 0xA1, 0x03, 0x00, 0x00, 0x2C }; 


DeviceAddress SensorS2 = { 0x28, 0xF2, 0x75, 0xA1, 0x03, 0x00, 0x00, 0x7F };


[font=Verdana]hier oben sind die Zwei Sensoren die an einem Eingang hängen sie werden durch die Adresse identifiziert . Es müßte doch möglich sein über diese Adressen azufragen ob die Sensoren vorhanden sind[/font]



void setup(){
  
  byte addr[8];  
  Serial.begin(9600);
  sensors.begin();
  sensors.setResolution(SensorS1, 10);
  sensors.setResolution(SensorS2, 10);
  
  
  
  
  
  

  pinMode (Pumpe1, OUTPUT);
  pinMode (Pumpe2, OUTPUT);
}

void loop(){
  
  //Start Abfrage DS18B20
  sensors.requestTemperatures();
  
  //Temperaturen DS18B20 in Variable ablegen
  float tempS1 = sensors.getTempC(SensorS1); //zwischenspeichern in Variable tempZ1
  float tempS2 = sensors.getTempC(SensorS2); //zwischenspeichern in Variable tempZ2
  
  
  sensors.requestTemperatures();  
  
 
   lcd.begin(20, 4);//LCD hat 20 Zeichen und 4 Spalten
  
  
  
 
  
  // das Ergebnis ans Display senden
 
 
 
 
  
  if(DifferenztemperaturS1  > ( Schalttemperatur + 2 ) && tempS1 < SpeicherTempladebereit && tempK < KolektorTempMax - KolektorTempMaxHysterese) // Pumpe einschalten für Stufe1
  digitalWrite(Pumpe1, HIGH); // Pumpe wird eingeschaltet Pin 13
 
 if(DifferenztemperaturS1  > ( Schalttemperatur + 2 ) && tempS1 < SpeicheTempVollwiederBereit && tempK < KolektorTempMax - KolektorTempMaxHysterese) // Pumpe einschalten für Stufe1
  digitalWrite(Pumpe1, HIGH); // Pumpe wird eingeschaltet Pin 13
 
  if(DifferenztemperaturS1 < ( Schalttemperatur - 2 )  || FehlereldungSpeicher1MaxVariable == 1 || tempK > KolektorTempMax || tempS1 < SpeicherTempUnplausibel || tempS1 > SpeicherTempAusStufe1) // Pumpe abschalten
  digitalWrite(Pumpe1, LOW); // Pumpe wird ausgeschaltet Pin 13
  
  if(DifferenztemperaturS1 < ( Schalttemperatur - 2 )  || FehlereldungSpeicher1MaxVariable == 1 || tempK > KolektorTempMax || tempS1 < SpeicherTempUnplausibel || tempS1 > SpeicherTempAusVoll) // Pumpe abschalten
  digitalWrite(Pumpe1, LOW); // Pumpe wird ausgeschaltet Pin 13
  
  //Betriebsmeldung in Zeile 4
 lcd.setCursor(13, 1);
 if(tempS1 < SpeicherTempMax & FehlereldungSpeicher1MaxVariable == 0){ //wenn diese zwei Störungsmeldungen nicht anstehen werden die Betriebsmeldungen geschrieben
 lcd.setCursor (3,2);
 lcd.print(digitalRead(Pumpe1) == HIGH? "laden":"warten"); // Anzeige Beladen oder Standby
 lcd.setCursor (0, 2);
 lcd.write ("S1-");}
 if (tempS1 > SpeicherTempAusStufe1){ //Die Betriebsmeldung Speicher Stufe1 wird geschrieben
 lcd.write("Stufe1   ");}
  
 
  
  (DifferenztemperaturS1 = tempK - tempS1);
  (DifferenztemperaturS2 = tempK - tempS2);
   
  lcd.setCursor(0, 3);
  lcd.print("Diff=") ;
  if (DifferenztemperaturS1 > 0){    // Der Differenztemperaturwert wird nur geschrieben wenn er positiv ist
  lcd.setCursor(5, 3);
  lcd.print(DifferenztemperaturS1,1); // Die Differenztemperatur wird geschrieben
  lcd.print("K   ");}
  else
  lcd.setCursor(6, 3);
  lcd.print("<0");     //Wenn die Differenztemperatur negativ ist wird dies geschrieben
  
  
// Anzeige der Speichertemperatur und der Speicher1 Fehlermeldungen

lcd.setCursor(0, 1);
  lcd.print("S1=");
  lcd.setCursor(3, 1);
  lcd.print(tempS1,1);// Ausgabe des Variablen S1 Inhalt, die 1 sind die Anzahl der Stellen nach Komma
  lcd.write(0xD0 + 15); // das ° Zeichen wird geschrieben
  lcd.write("C");
 
 
   
 
  
  if(tempS2 < SpeicherTempMax & FehlereldungSpeicher1MaxVariable == 0){ //wenn diese zwei Störungsmeldungen nicht anstehen werden die Betriebsmeldungen geschrieben
 lcd.setCursor (11,2);
 lcd.write ("S2-");
 lcd.print(digitalRead(Pumpe2) == HIGH? "laden":"warten"); // Anzeige Beladen oder Standby
  }
 
 
  lcd.setCursor(0, 2);
  lcd.write("S1-");
if (tempS1 > SpeicherTempAusStufe1){ //Die Betriebsmeldung Speicher Stufe1 wird geschrieben
lcd.write("Stufe1");} 
if (tempS1 > SpeicherTempAusVoll){ //Die Betriebsmeldung Speicher Voll wird geschrieben
lcd.write("Voll  ");}   
 if(tempS1 > SpeicherTempMax)(  // Die Fehlermeldung UebtmpSp wird geschrieben 
 FehlereldungSpeicher1MaxVariable = 1);
  
 if (FehlereldungSpeicher1MaxVariable == 1){
 lcd.setCursor(0, 3);
 lcd.write("UebertempSp1");}
 
  lcd.setCursor(11, 3);
  lcd.print("Diff=") ;
  if (DifferenztemperaturS2 > 0){    // Der Differenztemperaturwert wird nur geschrieben wenn er positiv ist
  lcd.setCursor(16, 3);
  lcd.print(DifferenztemperaturS2,1); // Die Differenztemperatur wird geschrieben
  lcd.print("K");}
  else
  lcd.setCursor(17, 3);
  lcd.print("<0");     //Wenn die Differenztemperatur negativ ist wird dies geschrieben
 
 
 // Anzeige der Speichertemperatur und der Speicher2 Fehlermeldungen 
 
  lcd.setCursor(11, 1);
  lcd.print("S2=");
  lcd.setCursor(14, 1);
  lcd.print(tempS2,1);// Ausgabe des Variablen S2 Inhalt, die 1 sind die Anzahl der Stellen nach Komma
  lcd.write(0xD0 + 15); // das ° Zeichen wird geschrieben
  lcd.write("C");
  
  
  //  Stufe1 Speicher1 wird bis zu 35°C geladen
   if(DifferenztemperaturS2 > ( Schalttemperatur + 3 ) && tempS2 < SpeicherTempladebereit  && tempK < KolektorTempMax - KolektorTempMaxHysterese && digitalRead(Pumpe1) == LOW && tempS2 < 35 ) // Pumpe einschalten
  digitalWrite(Pumpe2, HIGH); // Pumpe2 wird eingeschaltet füe Stufe1Pin 12

 if(DifferenztemperaturS2 < ( Schalttemperatur -2 )  || FehlereldungSpeicher2MaxVariable == 1 || tempK > KolektorTempMax || tempS2 < SpeicherTempUnplausibel || tempS2 > SpeicherTempMax || tempS2 > SpeicherTempAusStufe1 || digitalRead(Pumpe1) == HIGH || tempS2 > 30 ) // Pumpe abschalten
  digitalWrite(Pumpe2, LOW); // Pumpe2 wird ausgeschaltet für Stufe1 Pin 12

  
   if(DifferenztemperaturS2 > ( Schalttemperatur + 3 ) && tempS2 < SpeicherTempladebereit  && tempK < KolektorTempMax - KolektorTempMaxHysterese && digitalRead(Pumpe1) == LOW && tempS1 > SpeicherTempladebereit ) // Pumpe einschalten
  digitalWrite(Pumpe2, HIGH); // Pumpe2 wird eingeschaltet füe Stufe1Pin 12
  
  if(DifferenztemperaturS2 < ( Schalttemperatur -2 )  || FehlereldungSpeicher2MaxVariable == 1 || tempK > KolektorTempMax || tempS2 < SpeicherTempUnplausibel || tempS2 > SpeicherTempMax || tempS2 > SpeicherTempAusStufe1 || digitalRead(Pumpe1) == HIGH ) // Pumpe abschalten
  digitalWrite(Pumpe2, LOW); // Pumpe2 wird ausgeschaltet für Stufe1 Pin 12

ich habe den letzten Teil des Sketches weggelassen da er sonst zu groß ist.
Er ist auch ziemlich unübersichtlich aber ich bin gerade am überarbeiten.

In der loop könntest du zb folgendes machen:

const boolean SensorS1valid = sensors.validAddress(SensorS1);
const boolean SensorS1isConnected = sensors.isConnected(SensorS1);

Die Funktionen geben dir die Rückmeldung, ob die Sensoren vorhanden sind.
Normalerweise such man aber erst mal den ganzen Bus ab und schaut welche Sensoren dran hängen. Danach aktiviert man bekannte Sensoren und verwendet diese dann.

Du kannst es aber auch so lassen...

Ich habe mich heute nochmal näher mit der Thematik beschäftigt, da ich die DS18S20 library als DS18x20 auch für den Typ DS18B20 fitt gemacht habe.
Fehlerhafte Sensoren können verschiedene Werte liefern:

  • ca. -0.06°C - das passiert, wenn der Sensor einfach weg ist und die OneWire-Lib alle Bits auf 1 setzt (dann kommt 0xFFFFFFFFFFFFFF) raus, je nachdem was man damit anstellt kommt ein Temperatur-Wert knapp unter 0 raus. Abhilfe: Prüfen, dass nicht alle Bits der Message 1 sind.
  • +85.00°C - dieser Wert wird von der Original-Library gesendet, wenn der 1-Wire-Bus nicht antwortet.
  • +85.00°C - auch wenn der Sensor noch nicht mit der 1. Messung fertig ist, sendet er 85°C. Dies ist der Power-On-Initialwert laut Datenblatt. Da der Wert "in echt" nicht dauerhaft exakt zu messen sein wird, sollte er als "Fehler" interpretiert werden
    (Edit: Dieser Wert kommt auch, wenn zwischen 2 Messungen kurz der Strom des Sensors weg war).
  • alle Werte <-55°C und >+125°C sollten als Fehler interpretiert werden, da diese außerhalb des Sensor Messbereiches liegen.