Hallo, Im Datenblatt vom DS18S20 steht, das fur den Wert 0xFFFF ich eine Temperatur von -0.5C bekommen sollte. Erstmal was funktioniert: 0xFF92 soll -55.0 sein: 0xFF92 = 0b1111111110010010 LSB = 0b10010010 MSB = 0b11111111 Bit 0 von LSB ist 0, also hat der Wert eine 0 nach dem komma. Vom MSB geht hevor das es ein negativer Wert ist. Ich invertiere die bits und bekomme 0b01101101, da es sich aber um einen 7bit Wert handelt, ist der wert 0b00110110, dazu +1 und wir haben 0b00110111 was decimal 55 entspricht. Funktioniert also prima. Jetzt das was ich nicht verstehe: 0xFFFF = 0b1111111111111111 LSB = 0b11111111 MSB = 0b11111111 Bit 0 von LSB ist 1, also hat der Wert ein 5 nach dem komma. Sign bit ist 1, also ist es ein negativer Wert. Ich invertiere die bits und bekomme 0b00000000, da es sich aber um einen 7bit wert handelt, ist der wert 0b0000000, dazu +1 und wir haben 0b0000001 was decimal 1 entspricht, dazu 0.5, ergibt zusammen 1.5. Wieso steht im Datenblatt 0.5 ? Kann ich nicht richtig zahlen ? Grus an Alle
Hallo, es gibt noch eine andere Möglichkeint, eine Zahl im zweierkomplement in eine Zahl im Zehnersystem umzuwandeln: Das niederwertigste Bit in MS Byte hat die Wertigkeit -2^7, das höchstwertigste Bit in LS Byte hat die Wertigkeit 2^6, das nächste Bit die Wertigkeit 2^5 ... das niederwertigste Bit in LS Byte hat die Wertigkeit 2^(-1) = 1/2. 0xFFFF kann man dann schreiben als (die 7 höchstwertigsten Bits in MS Byte kann man weglassen, das ist sowieso nur das Vorzeichenbit): 11111111.1 = -128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 + 0,5 = -0,5, was auch im Datenblatt steht vgl. auch http://de.wikipedia.org/wiki/Zweierkomplement#Umwandlung_ins_Dezimalsystem im Abschnitt "Umwandlung ins Dezimalsystem" unten. Wo dein Denkfehler ist weiß ich gerade nicht, vielleicht sieht das ja jemand anderes... Viele Grüße Michael
Scheinbar funktioniert die Hilfsregel "invertieren + 1 addieren" nur, wenn es sich um eine Zahl aus Z (also keine Nachkommastellen) handelt Viele Grüße Michael
Hallo Michael, ich kenne jetzt deine Hilfsregel nicht, aber vollständig wäre die Anweisung ja: invertieren -> rechts shiften -> +1 Wenn die Reihenfolge tatsächlich so wäre: invertieren -> +1 -> rechts shiften würde sie immer stimmen. Scheint mir auch logischer zu sein.
W. P. schrieb: > 0b0000001 was decimal 1 entspricht, dazu 0.5, ergibt zusammen 1.5. **** Deine eigentliche Zahl ist ja negativ. Also 0.5 wegzählen. Nicht dazu. Du kannst es auch so sehen: 0xFFFF ist die erste negative Zahl, die überhaupt möglich ist. Da bei dir die 'Zahlauflösung' 0.5 Einheiten beträgt, ist die erste negative Zahl dann eben -0.5 ( -1 * 0.5 -> -0.5 )
> Bit 0 von LSB ist 1, also hat der Wert ein 5 nach dem komma.
Hier ist dein Denkfehler.
Du verwechselst da 2 Operationen.
Die eine Operation ist: An die Zahl eine Stelle anhängen (und sei es nur
eine Nachkommastelle)
Die andere ist: Zu einer Zahl ein ander (eben 0.5) vorzeichenrichtig
addieren.
Bei positiven Zahlen liefern beide Operationen ein identisches Ergebnis.
Nur bei negativen eben nicht.
-x + 0.5
ist eben nicht dasselbe wie
-( x + 0.5)
Karl Heinz Buchegger schrieb: > Deine eigentliche Zahl ist ja negativ. Also 0.5 wegzählen. Nicht dazu. Mann bin ich blod... hast recht, ein Kerl will was mit uCs machen, kann aber nicht bis zwei zahlen :) Tausend Mal danke :)
W. P. schrieb: > Karl Heinz Buchegger schrieb: >> Deine eigentliche Zahl ist ja negativ. Also 0.5 wegzählen. Nicht dazu. > > Mann bin ich blod... hast recht, ein Kerl will was mit uCs machen, kann > aber nicht bis zwei zahlen :) > > Tausend Mal danke :) Und ich hoffe, das das nur eine theoretische Überlegung war. In einer Programmiersprache (zb C), die mit 2-er Komplement umgehen kann, brauchst du dich nicht darum kümmern. Ber der Ausgabe stellst du einfach fest, ob die Zahl negativ ist oder nicht und malst dann einfach ein '-' auf die Anzeige. In diesem Fall nimmst du dann auch das nagative der Zahl (um sie positiv zu machen) und gibst die einfach aus. Für den Vorkommaanteil dividierst du die Zahl durch 2, dann malst du einen Punkt hin und wenn der Moduls der (jetzt positiven) Zahl ungleich 0 ist malst du noch eine 5 hinten drann. if( zahl < 0 ) { Ausgabe( '-' ) Zahl = -Zahl } AusgabeInt( Zahl / 2 ) Ausgabe( '.' ) if( Zahl % 2 == 0 ) Ausgabe( '0' ) else Ausgabe( '5' )
Danke Euch allen, funtzt prima:
1 | #include <stdio.h> |
2 | #include <stdint.h> |
3 | |
4 | float raw_to_celsius(msb, lsb){ |
5 | float celsius = 0; |
6 | celsius = ((lsb & 1) == 1) ? 0.5 : 0; |
7 | celsius = ((msb & 1 << 7) == 1 << 7) ? celsius - 128 : celsius; |
8 | celsius += (lsb >> 1); |
9 | return celsius; |
10 | }
|
11 | |
12 | int main(){ |
13 | |
14 | printf("% 5.1f\n", raw_to_celsius(0x00, 0xAA)); |
15 | printf("% 5.1f\n", raw_to_celsius(0x00, 0x32)); |
16 | printf("% 5.1f\n", raw_to_celsius(0x00, 0x01)); |
17 | printf("% 5.1f\n", raw_to_celsius(0x00, 0x00)); |
18 | printf("% 5.1f\n", raw_to_celsius(0xFF, 0xFF)); |
19 | printf("% 5.1f\n", raw_to_celsius(0xFF, 0xCE)); |
20 | printf("% 5.1f\n", raw_to_celsius(0xFF, 0x92)); |
21 | |
22 | }
|
Das Resultat:
1 | 85.0 |
2 | 25.0 |
3 | 0.5 |
4 | 0.0 |
5 | -0.5 |
6 | -25.0 |
7 | -55.0 |
Danke nochmal und Grus an Alle.
>
1 | > float raw_to_celsius(msb, lsb){ |
2 | > float celsius = 0; |
3 | > celsius = ((lsb & 1) == 1) ? 0.5 : 0; |
4 | > celsius = ((msb & 1 << 7) == 1 << 7) ? celsius - 128 : celsius; |
5 | > celsius += (lsb >> 1); |
6 | > return celsius; |
7 | > } |
Ich habs befürchtet. Ich habs befürchtet. Die Welt kann manchmal so grausam sein Wenn schon float
1 | float raw_to_celsius(uint8_t msb, uint8_t lsb) |
2 | {
|
3 | int16_t Temperature = ( msb << 8 ) + lsb; // Beide bytes zu einem signed int zusammensetzen |
4 | return Temperature / 2.0; // Der Chip liefert immer das Doppelte der tatsächlichen Temperatur, |
5 | // weil 1 Bit die Nachkommastelle darstellt.
|
6 | }
|
@kbuchegg, Das Beispiel von Dir gibt mir:
1 | 85.0 |
2 | 25.0 |
3 | 0.5 |
4 | 0.0 |
5 | 32767.5 |
6 | 32743.0 |
7 | 32713.0 |
Was mache if falsch ?
W. P. schrieb: > Ok, int16_t anstatt vom int. Welchen µC benutzt du? Ich hatte die int16_t nachgebessert um das etwas klarer zu machen. Auf einem AVR ist int16_t und int allerdings identisch.
Den Quellcode habe ich auf meinem Laptop per gcc am laufen. Prototyping befor ich das auf meinem ATMEGA8 schmeisse. Die LCD routinen fur mein Projekt habe ich schon, und laufen auf dem AVR ok. Jetzt noch eine Routine fur zwei DS18S20 an zwei Pins basteln und fertig. Ich weiss, ist Pinverschwendung, aber ich brauch nichts anderes anzuschliesen auser noch einen Relais und es macht das auslesen / austauschen der Sensoren einfacher.
W. P. schrieb: > Den Quellcode habe ich auf meinem Laptop per gcc am laufen. > > Prototyping befor ich das auf meinem ATMEGA8 schmeisse. Dann ist alles klar. Am PC ist ein int heutzutage 32 Bit gross. Daher: Bei solchen Sachen explizit sein (hätt ich gleich tun sollen. Sorry)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.