Hallo,
ich baue gerade einen kleinen Temp-Logger für ein Abwasserrohr, das mir
vor ein paar Tagen eingefroren ist.
Dabei nutze ich den DS18B20. Es funktioniert soweit auch alles ganz gut.
Ich splitte Vorkommastelle und Nachkommastelle:
1
temp=0x12AB;// Beispiel
2
vorkomma=temp/16;
3
nachkomma=temp%16;
4
5
// Bei negativer Temperatur das Vorzeichen der Nachkommastelle korrigieren (ist sonst 0.-50 °C)
6
if(temp&0xF000){
7
nachkomma|=0xFFF0;
8
nachkomma=-nachkomma;
9
}
10
nachkomma=nachkomma*100/16;
Ich hab jetzt nur das Problem, dass ich Werte negative Temperaturen, die
vorne eine 0 haben (also z.B. -0.5°C) so nicht darstellen kann, da die 0
weder positiv noch negativ ist, ergo auch kein Vorzeichen hat.
Ich bau mir gerade ne double-krücke, aber so ganz elegant finde ich das
nicht. Gibt es eurer Meinung nach noch einen schöneren Weg? Ich setz
mich morgen sonst mal ran und bau ggf. einen eigenen Converter, der das
berücksichtigt und trotzdem schön ausrichtet (so, dass die Kommastellen
untereinander beleiben, wie es sprintf macht).
Für Tipps bin ich sehr dankbar & viele Grüße,
Matthias
Servus Matthias,
ich verwende den Code mit wechselnden Prozessoren( vom Atxmega bis
Atmega128) laufend. Über Null Grad (temp) unter Null Grad (~temp). Was
für eine Routine ich nehme, entscheidet die Frage >= oder <= 0xFC91.
Diesen Wert hab ich errechnet,getestet und auch irgend wo mal gelesen.
Das Vorzeichen "+" oder "-" übernehme ich direkt aus der if(..) Abfrage.
Ein kleiner Anzeigefehler besteht aber dennoch, da zum Beispiel bei
exakt 0 Grad immer ein Vorzeichen (+/-) erscheint. Das verschwindet
aber, wenn sich die Temp. um 0,5 Grad ändert! Das war's
Datenblatt ok!
Gruß GG
GG schrieb:
> nach dem Datenblatt wird bei Minus-Temperaturen> das Ergebnis negiert.
Das ist falsch. Laut Datenblatt wird nicht negiert, sondern das 2-er
Komplement verwendet, also eine übliche Darstellung der negativen Werte.
Zitat:
The temperature data is stored as a 16-bit sign-extended
two’s complement number in the temperature register (see Figure 2).
Zitat Ende
>> +25.0°C 0000 0000 0011 0010 0032h> +0.5°C 0000 0000 0000 0001 0001h> 0°C 0000 0000 0000 0000 0000h> -0.5°C 1111 1111 1111 1111 FFFFh> -25.0°C 1111 1111 1100 1110 FFCEh>
Die oben angegeben Werte stehen so nicht im Datenblatt des DS18B20.
> if(temp >= 0xFC91) // Minus> {> ~temp // weiter mit negierten Temp rechnen> ...
Damit ergibt sich ein Fehler, da nicht das 2-er Komplement verwendet
wird.
Also ich hole nur ungern diesen alten Thread wieder hoch, aber da ich
gestern eine gefühlte ewigkeit nach der korrekten Lösung gesucht habe,
hier nun meine Lösung:
- DS18B20 speichert negative werte als Zweierkomplement.
- Einfaches negieren des Wertes reicht da nicht.
So gehts:
//-----------------------------------
int16_t decimal;
uint8_t digit;
// Wert vom scratchpad holen
temp = temperature[0];
temp |= temperature[1] << 8;
if(temperature[1] > 7) // Sign bits gesetzt
{
temp = ~(temp - 1); // Rückwandeln vom zweierkomplement
decimal = (temp / 16) * -1; // Vorzeichen setzen
}
else
{
decimal = temp / 16;
}
*digit = temp % 16;
//-----------------------------------
Soweit ich es bisher beurteilen konnte, lieferte der sensor bisher mit
dieser Umrechnung nur glaubhafte Werte.
Florian T. schrieb:> Also ich hole nur ungern diesen alten Thread wieder hoch, aber da ich> gestern eine gefühlte ewigkeit nach der korrekten Lösung gesucht habe,> hier nun meine Lösung:
Ui - auch ich hole den Beitrag nochmals hoch nachdem ich auch schon eine
Weile google und nach der Lösung suche.
In der Lösung von Florian ist mir folgende Zeile ein Rätsel:
> *digit = temp % 16;
Was hat der "*" zu bedeuten?
Mein Compiler (Atmel Studio 7) kommt mit der Zeile nicht klar. Stern
weg, dann klappt es. Aber ich erhalte nicht den Nachkommawert den ich
erwarte.
Im Nachkommateil "digit" steht ja so der Modulo-Wert zwischen 0 und 15.
Oder verstehe ich das auch falsch?
Dann müsste ich den Modulo-Wert mit 0.0625 multiplizieren?
Wie wird die Temperatur, korrekt mit Kommastelle ausgegeben?
Mein Versuch:
sprintf(s, "%4d.%01dC",decimal, digit);
Vielen Dank schon mal
Grüsse
up_marki
@Markus B. (up_marki)
>In der Lösung von Florian ist mir folgende Zeile ein Rätsel:>> *digit = temp % 16;>Was hat der "*" zu bedeuten?
Eine Dereferenzierung eines Pointers.
Schreibe das Ergebnis von temp modulo 16 an den Ort, an den digit zeigt.
Steht in jedem C-Buch, das ist das kleine 1x1. digit ist hier ein
Pointer auf eine Variable. Der unvollständige Ausschnitt des Codes ist
Teil einer Funktion, digit ist ein Funktionsargument.
>Mein Compiler (Atmel Studio 7) kommt mit der Zeile nicht klar.
Kaum ;-)
>Im Nachkommateil "digit" steht ja so der Modulo-Wert zwischen 0 und 15.
Ja.
>Dann müsste ich den Modulo-Wert mit 0.0625 multiplizieren?
Nein.
>Wie wird die Temperatur, korrekt mit Kommastelle ausgegeben?
So.
Beitrag "Re: Onewire + DS18x20 Library"
Hallo Falk
Vielen Dank für die Antworten.
Werde Deinen Code mal genauer ansehen, hab ihn kurz überflogen.
>> Mein Compiler (Atmel Studio 7) kommt mit der Zeile nicht klar.> Kaum ;-)
Doch, doch er kommt damit nicht klar - weil *digit demzufolge bei mir
nicht richtig deklariert ist :-)
Bei mir liegt es nur noch an den Nachkomastellen, deswegen möchte ich
vorerst nicht komplett alles ändern.
Trotzdem verstehe ich nicht ganz, wie der Nachkommateil bei Florian
funktioniert. Mann müsste wohl den ganzen Code kennen?!
@ Markus B. (up_marki)
>Doch, doch er kommt damit nicht klar - weil *digit demzufolge bei mir>nicht richtig deklariert ist :-)
Was wohl eher weniger am Compiler liegt . . . 8-0
>Bei mir liegt es nur noch an den Nachkomastellen, deswegen möchte ich>vorerst nicht komplett alles ändern.
Musst du auch gar nicht. Wenn digit eine normale Variable ist, musst du
nur den Stern weglassen.
>Trotzdem verstehe ich nicht ganz, wie der Nachkommateil bei Florian>funktioniert. Mann müsste wohl den ganzen Code kennen?!
Nicht wirklich. Aber da ist viel unnötiger Hackerkram drin. Das kann man
DEUTLICH einfacher und geradliniger hinschreiben.
[c]
int digit, decimal, temp;
// Wert vom scratchpad holen und zusammenfügen
temp = ((int)temperature[1] << 8) | temperature[0];
decimal = temp / 16;
digit = abs(temp % 16);
[c]
Siehe Festkommaarithmetik
Hmm, war wohl gestern zu spät. Wenn gleich die Rechnung oben stimmt, so
will man die Nachkommastellen eher nicht 1/16 Bruchteile anzeigen, eher
dezimal als 1/10. Also muss man auf 1/10 Auflösung umrechnen, so wie es
die verlinkte Software tut.
Hallo Falk
Habe ich so probiert, aber jetz wären wir beim Titel dieses
ursprünglichen Thread's. Von 0 bis -1°C erhalte ich ein positives
Vorzeichen.
Da es mir aber gerade an Zeit mangelt, versuche ich es später nochmal.
Beim gestrigen überfliegen Deines Cods konnte ich nicht auf Anhieb
finden, wie negative Temperaturen behandelt werden. Der Sensor DS18B20
liefert ja bei negativen Temperaturen das Zweierkomplement.
Gruss
up_marki
@Markus B. (up_marki)
>ursprünglichen Thread's. Von 0 bis -1°C erhalte ich ein positives>Vorzeichen.
Wirklich? Wie merkst du das?
Ach so, ich weiß warum. Mein Fehler ;-)
Man muss das Vorzeichen prüfen und bei der Ausgabe berücksichtigen!
Etwa so.
Ich löse das meistens so:
if (temp2write and 0x8000) then
text[0] = "-"
temp2write = not temp2write + 1
end if
temp2write Ist der Wert der vom Sensor kommt.
@ Stefan (Gast)
>if (temp2write and 0x8000) then> text[0] = "-"> temp2write = not temp2write + 1> end if
Ist das cool oder einfach nur Hackermist? Man kann eine
vorzeichenbehaftete Zahl einfach als das handhaben, was sie ist.
Vorzeichenbehaftet. Man muss nicht beweisen, daß man früher mal ein
cooler Assemblerfreak war und die Definition des Zweierkomplements
verstanden hat.
Hi
Falk B. schrieb:> Ist das cool oder einfach nur Hackermist?
Vll. cooler Hackermist?
Was für ein Problem gibt es damit, daß man den Sensorwert, laut
Datenblatt, zurück rechnet?
Man braucht nicht für jeden Mückenschiss float mit zig Nachkommastellen,
nur weil ja noch Platz im µC ist.
Auch kann man, wenn man kann, selber entscheiden, ob das höchste Bit
hier ein Minus darstellen soll, oder ob das Gelump 'nur' eine Zahl ist.
Aus dem Grund, möglichst wenige Platz sinnlos zu verschwenden, wäre
meine Minus-Prüfung VOR der Ausgabe des Wert, da ich die Ausgabe nur 1x
benötige, nämlich, nachdem ich '-' oder ' ' ausgegeben habe (wo ich
direkt das 2er Komplement bilde, damit der Wert auch wieder passt).
In diesem Sinne, ab in die Rinne ...
PS: gibt's dafür nicht irgendwo eine LIB, daß man sich überhaupt gar
keinen Kopf mehr machen muß? Kann doch nicht sein, daß man selber
(nach-)denken muß ...
Hallo zusammen
Danke für alle Beiträge.
Seid doch ein bisschen brav zu einander. Jede der Meinungen ist denke
ich berechtigt.
Zum einen will man gut lesbaren Code - macht Sinn, ebenso ist es doch
sinnvoll etwas ressourcen optimiert zu coden.
Sehe mir bei Gelegenheit auch noch mal eure verlinkten Beiträge an.
Dann entscheide ich mich für eine Variante.
Frohes Schaffen oder davon Erholen :-)
up_marki
Hallo zusammen
Mich freut es immer, wenn ich in den Beiträgen die definitive Lösung
finde. Deshalb hier meine funktionierende Lösung, welche auf eueren
Beiträgen basiert. Danke nochmal.
Sollte jemand wesentliche Verbesserungen haben - nur zu...
Code:
1
uint16_ttemp;
2
int8_tsign;
3
int16_tdecimal;
4
uint8_tdigit;
5
6
temp=((int)temperature[1]<<8)|temperature[0];
7
sign=0;// Vorzeichen positiv
8
if(temp>0xF000)// Temperatur negativ
9
{
10
temp=~(temp-1);// Rückwandeln vom Zweierkomplement
Falk B. schrieb:>>if(temp > 0xF000) // Temperatur negativ>> Herzlichen Glückwunsch, du hat nichts verstanden!
Vielen Danke für die Glückwünsche! Freut mich.
...und was habe ich nicht verstanden ?
Wenn ich nichts verstanden hätte würde es gar nicht funktionieren :-)
gefiele Dir folgendes besser?
1
if(tempand0x8000)// Temperatur negativ
gem. Datenblatt sind im MSB Bit 4 - 8 als "Sign" deklariert.
Oder wo ist das Problem????
Falk B. schrieb:> @ Markus B. (up_marki)>>>if(temp > 0xF000) // Temperatur negativ>> Herzlichen Glückwunsch, du hat nichts verstanden!
Mag sein...
Ich habe nichts gegen vorzeichenbehaftete Zahlen und diese so weiter zu
Verarbeiten. Nur was ich bei deinem Beitrag:
Beitrag "Re: DS18B20: Negatives Vorzeichen bei -0.0625 bis -0.9375 ohne Float"
nicht verstehe - die negative Temperatur im ScratchPad ist nicht direkt
negativ um so weiter zu verarbeiten???
Hi
Die Temperatur besteht aus mehreren Bytes, nicht mehr, nicht weniger.
Es geht darum, wie Du diese Bytes interpretierst.
Bei 'uint' hat das Byte die Wertigkeit 0...255, bei 'vorzeichenbehaftet'
(ka, wie Das declariert wird) -128...127, obwohl genau die gleichen Bits
gesetzt sind.
Ist einzig die Art, wie Du mit den Zahlen weiter rechnen willst.
MfG