Hallo,
ich beschäftige mich seit einiger Zeit mit dem DS18S20. Nun habe ich
versucht, die Temperatur für Auflösungen größer 9Bit gemäß der Formel im
Datenblatt zu berechnen:
Das funktioniert auch, nur bei Minus-Temperaturen um die 0°C zeigt mir
mein Display riesige Werte an. Ich vermute, dass der Fehler daraus
resultiert, dass mir der Sensor für COUNT_REMAIN Werte größer 12 schickt
und TEMP_READ nach der notwendigen Zweierkomplementbildung 0 ist. Damit
hätte ich bei der Addition am Ende einen negativen Wert, der meine
riesigen Werte erklären würde. Muss ich das ganze irgendwie
softwareseitig abfangen, also z.B. durch folgende Prüfung?
1
if((TEMP_READ==0)&&(COUNT_REMAIN>12))
2
{
3
COUNT_REMAIN=12;
4
}
Zur Zeit habe ich das so realisiert, nur eigentlich geht mir dann mit
dieser Abfrage Genauigkeit verloren. Hat irgendjemand dasselbe Problem
und dafür eine Lösung parat?
Danke,
Biff
Biff schrieb:> Ich vermute
Das ist ganz schlecht.
Mit Vermutungen kann man kein Programm schreiben.
Lass dir die Werte ausgeben, dann WEISST du es!
(und kannst nebenbei auch mal händisch alles durchrechnen und nachsehen,
was sich bei Zwischenergebnissen so alles tut)
Ich denke, du hast eher irgendwo einen signed-unsigned Fehler. Aber ohne
Code und dem Wissen über die beteiligten Datentypen der Variablen sind
das alles nur Mutmassungen.
Hallo,
anbei die Funktion, die die Werte vom DS18S20 ausliest. Bei der
Berechnung habe ich bereits verschiedene Versionen ausprobiert, da ich
erst dachte, dass es an meiner Formel liegt. Ich habe dann eine andere
Berechnung genutzt, aber auch da habe ich das gleiche Problem.
1
uint16_tw1_getmultitemp(uint8_tactsensor)
2
3
{
4
5
uint8_ti,temp_msb=0;
6
uint16_ttemp=0,temp_lsb=0,count_remain=0;
7
8
9
10
w1_reset();
11
12
w1_writebyte(MATCH_ROM);//1wire: Match ROM-Befehl senden
count_remain = count_remain >> 4; //Division durch 16
77
78
temp = temp_lsb - 25 + 100 - count_remain;
79
*/
80
81
if(temp_msb)//wenn die Temperatur < 0°C
82
{
83
temp=temp|0x8000;//Setzen des MSB als Indikator für Minustemperaturen
84
}
85
86
87
return(temp);
88
89
}
Meine Frage ist, ob der Sensor bei Minus-Temperaturen überhaupt die
Kombination TEMP_READ = 255 und COUNT_REMAIN > 12 schickt? Weil dann
käme es bei der Formel im Datenblatt zu einem negativen Resultat,
nachdem man das Zweierkomplement von TEMP_READ gebildet und den Wert
einmal nach rechts geschoben hat.
Danke,
Biff
Hallo visitor,
eigentlich ja nicht, da es dieses Problem mit der Formel ja nur dann
gibt, wenn der Wert TEMP_READ == 0 ist und COUNT_REMAIN > 12 ist. Wenn
eine der Bedingungen nicht erfüllt ist, dann kann es gemäß der Formel ja
nicht passieren, dass am Ende der Subtraktion ein Wert kleiner 0
herauskommt. Deswegen habe ich diese beiden Bedingungen "verunded".
Biff
Der Sensor funktioniert so wie du es möchtest. Hab ihn selber schon mal
so benutzt. Nur du rechnest falsch und verschluderst wahrscheinlich
irgendwo Vorzeichen. Überall nur uint Variablen. Denk mal drüber nach,
prüfe alle Zwischenergebnisse und du kommst selber drauf. Karl-Heinz
schrieb es ja auch schon oben.
Hallo,
ich habe jetzt mal Karl-Heinz' Ratschlag befolgt und mir die Messwerte
ausgeben lassen. Die Kombination aus TEMP_READ == 0 und COUNT_REMAIN
scheint es nicht zu geben. Für alle die es interessiert ist im Anhang
der Log, interessant für mein Problem sind die Zeilen 169-228. Somit
liegt mein Problem in meiner Berechnung. Ich werde mal gucken, ob ich
hier im Forum ein Beispielcode finde. Danke erstmal,
Biff.
Vielen Dank für die aufschlussreichen Logs, leider fehlen ein paar
Zeilen, z.B.
000;000;075;070;255;255;016;016;
Es gibt etliche Fallstricke beim Rechnen mit signed ints, z.B. (-1)/2=+0
Wer seinen Algorithmus testen will, hier die korrekte Zuordnung:
Mein Testobjekt: DS1820 von Pollin 180014 (2,50)
Für die 12bit-4Nachkommastellen-Ausgabe kann man die die Periodizität
nutzen: die letzten beiden Ziffern sind jedes 4. Mal gleich.
Ich gebe nur 2 Nachkommastellen mit LookUp aus:
char s[32]="00061319253138445056636975818894";
if(temp12<0){tabs12=-temp12;sign='-';}else{tabs12=temp12;sign='+';}
...
put(s[help=2*(tabs12&15)];put(s[help+1]);
In den Anhängen findet Ihr ein neues Testfile (gleich aufgebaut wie die
o.g. Logs), ein Programm, das das Testfile auf verschiedene Arten
umrechnet und die Ausgabe dieses Programms.
Wozu soll das hier gut sein
if (temp_msb) //wenn die Temperatur < 0°C
{
temp_lsb = (~temp_lsb + 1) & 0x00FF; //2er-Komplement
}
Ich würde ehrlich gesagt da nicht grossartig auf Bitebene rumpfriemeln.
Du kriegst erst mal die beiden Bytes für die Temperatur. Die werden vom
DS freundlicherweise schon im 2-er Komplement geschickt.
D.h. die beiden Bytes setzt ich in einer int16_t Variablen zusammen und
hab dann schon einen fix/fertigen Wert (inklusive Vorzeichen), der dem
doppelten der tatsächlichen Temperatur entspricht.
Und ab da rechne ich alles nur noch mit signed integer Variablen
(int16_t), so wie es im Datenblatt angegegeben ist, wobei ich es
tunlichst unterlasse schlauer als mein Compiler zu sein.
Hallo Biff,
wo lässt Du den Wert "count per °C" ?
Soweit ich deinen Code verstanden habe, liest Du den Wert Count_per_C
nicht in eine Variable. Du kannst deshalb in deiner Berechnung auch
keine sinnvollen Ergebnisse erzielen.
das Geheimnis der Sensoren besteht darin, dass die Spanne von einem Grad
Celsius eine Anzahl Counts liefert, die sich über den Messbereich
ändert.
z.B. von 10-11°C 73 Counts und von 20 bis 21°C 80 Counts.
Gruß
Joachim
Von mir wieder einmal ein Runde Kraftfutter,
HighDensityCode vom Feinsten:
Die komplette Auswertung des gelesenen Temperaturwertes samt
- Umwandlung in druckbare Zeichen,
- Unterdrückung führender Nullen,
- Verschiebung des Vorzeichens
- zwei Nachkommastellen
in 10 Zeilen (ohne die Kommentare). Ich kann gar nicht verstehen, wie
man hierfür kilometerlangen Code schreiben kann.
Ohne Verwendung von printf, *, / oder % ,
ergibt auch auf kleinen µC einen Mini-Code.
>in 10 Zeilen (ohne die Kommentare). Ich kann gar nicht verstehen, wie>man hierfür kilometerlangen Code schreiben kann.
Weil es übersichtlicher ist und nicht so ein scheisse
formatierter Schrott wie von dir.
Von mir wieder einmal ein Runde Kraftfutter,
HighDensityCode vom Feinsten:
Die komplette Auswertung des gelesenen Temperaturwertes samt
- Umwandlung in druckbare Zeichen,
- Unterdrückung führender Nullen,
- Verschiebung des Vorzeichens
- zwei Nachkommastellen
in 10 Zeilen (ohne die Kommentare). Ich kann gar nicht verstehen, wie
man hierfür kilometerlangen Code schreiben kann.
Ohne Verwendung von printf, *, / oder % ,
ergibt auch auf kleinen µC einen Mini-Code.
grad=tabs12/16;//muss signed sein, damit divBySub funktioniert
Guten Appetit!
Anregungen, Kommentare, Verbesserungen ... immer gern gesehen!
Also gut, hier formatiert und kommentiert:
Habe den Code noch minimal geändert. Für t und f reicht char.
Das sind ein paar hundert Bytes Code.