Hallo Ich brauche einen Denkanstoß. Ich komme bei dem DS18B20 Sensor nicht weiter. Ich habe einen funktionierenden Code in C für den DS1820. Jetzt mein Problem Ich möchte den Code für den DS 1820 an den DS18B20 anpassen und komme mit den zwei Byte nicht weiter. Der DS 19B20 gibt die Temperatur und das Vorzeichen in 2 Byte aus. ". The temperature data is stored as a 16-bit sign-extended two’s complement number in the temperature register The sign bits (S) indicate if the temperature is positive or negative: for positive numbers S = 0 and for negative numbers S = 1. If the DS18B20 is configured for 12-bit resolution." Ich habe dann im Programm die zwei Byte ausgelesen. und einzeln vorliegen. LS BYTE bit 0 bis 7 und MS BYTE bit 8 bis 15. bit 11 bis 15 gibt das Vorzeichen aus und bit 0 bis 10 den Temperaturwert. Wie kann ich aus den bit 0 bis 10 verteilt in zwei byte den Wert reelle Zahl in einer Variablen erzeugen und aus den bit 10 bis 15 das Vorzeichen ( bit 10 bis 15 ist 0 bei positiv und 1 bei negativ erzeugen. Ist wahrscheinlich simpel aber ich komme nicht weiter mit den 2 einzelnen byte und den bits für das Vorzeichen. Viel habe ich noch nicht programmiert. vielen Dank
Zweierkomplement ist die ganz normale Darstellung von Integern. Du musst die beiden Bytes also einfach wieder hintereinander basteln, und hast dann einen signed short. Oliver
Hm, du brauchst doch nur die 2 Byte in einen int zu packen und fertig. Oder verstehe ich die Frage falsch?
So:
1 | ***SNIPPET***** |
2 | |
3 | if( id[0] == 0x28 || id[0] == 0x10 ){ // temperature sensor |
4 | w1_byte_wr( READ ); // read command |
5 | temp = w1_byte_rd(); // low byte |
6 | temp |= (uint)w1_byte_rd() << 8; // high byte |
7 | if( id[0] == 0x10 ) // 9 -> 12 bit |
8 | temp <<= 3; |
9 | }
|
10 | else
|
11 | return(0); |
12 | return(temp >> 4); // Divided by 16 |
Danke für die Antworten. Ich habe in dem einen Byte die Vorzeichen bits 11 bis 15, die muss ich irgend wie abtrennen sonst erhalte ich falsche werte und dann die restlichen Bits zu dem anderen byte dazutun oder wie ? Der Wert hat nur die 11 bits. Grüße Holger
Sensordaten sind in data[0] und [1]
1 | /* First two bytes of scratchpad are temperature values */
|
2 | temperature = data[0] | (data[1] << 8); |
3 | |
4 | /* Reset line */
|
5 | OneWire_Reset(OneWire); |
6 | |
7 | /* Check if temperature is negative */
|
8 | if (temperature & 0x8000) { |
9 | /* Two's complement, temperature is negative */
|
10 | temperature = ~temperature + 1; |
11 | }
|
12 | }
|
Holger W. schrieb: > Ich habe in dem einen Byte die Vorzeichen bits 11 bis 15, die muss ich > irgend wie abtrennen sonst erhalte ich falsche werte Sagt wer? Schau dir die Definition des Zweierkomplements an. Oliver
:
Bearbeitet durch User
Ich empfehle dem TO zunächst den Kerninghan & Ritchie in der Ausgabe von 1980, wo das Zweierkomplement erklärt ist. >>Ist wahrscheinlich simpel Ja, ist es, ein Zweizeiler. Und nebenbei eine wahnsinnig gute Seite, die es lohnt abgespeichert zu werden: https://graphics.stanford.edu/~seander/bithacks.html Damit ist man geholfen!
Danke erst mal. Die zwei oben genannten Beispiele verstehe ich noch nicht. Ich werde mich mit dem Zweierkomplement erst mal schlau machen. Wie gesagt die zwei byts habe ich als uint8_t scratchpad[0] und scratchpad[1] Ich muß aus den beiden nur noch eine positive oder negative reelle Zahl erzeugen. für das zusammenbasteln der zwei byts habe ich dass gefunden: uint16_t u16; uint8_t u8_low; uint8_t u8_high; u16 = u8_high * 256 + u8_low; ------ oder uint16_t make_u16(uint8_t high_byte, uint8_t low_byte) { return ( ((uint16_t)high_byte)<<8 | low_byte) } bei den positiven Werten wird das funktionieren? bei den negativen werde ich sehen was passiert und mit den Nachkommastellen muß dann mal sehen. die bits 0 bis 3 sind die Kommastellen. Grüße Holger
nein, bei negativen wirds natürlich nicht funktionieren. uint16 ist der falsche Datentyp.
u16 = u8_high * 256 + u8_low; ist übrigens das gleiche wie u16 = (u8_high << 8) + u8_low; Wurde hier auch schon ein paarmal in diversen Codeschnipseln gezeigt. Bitshifting muss man bei µC Programmierung halt können, da machste nix.
H.Joachim S. schrieb: > Hm, du brauchst doch nur die 2 Byte in einen int zu packen und fertig. Aber nur, wenn auf dem Compiler ein int Integer genau zwei Byte lang ist. Besser wäre wohl int16_t.
ja klar uint16_t geht bei 0 los, ich muss int16_t nehmen. Ich werde es morgen testen, auch die anderen Vorschläge, währe ja fast zu einfach, mal sehen. Grüße Holger
Codix schrieb: > ***SNIPPET***** > > if( id[0] == 0x28 || id[0] == 0x10 ){ // temperature sensor > w1_byte_wr( READ ); // read command > temp = w1_byte_rd(); // low byte > temp |= (uint)w1_byte_rd() << 8; // high byte > if( id[0] == 0x10 ) // 9 -> 12 bit > temp <<= 3; > } > else > return(0); > return(temp >> 4); // Divided by 16 Hallo, mit diesen Code geht es. Danke noch eine Frage warum am Ende noch durch 16 teilen? Im Datenblatt steht das nicht.
Holger W. schrieb: > Ich brauche einen Denkanstoß Ich meine Du hast eine 1-Wire Implementierung realisiert. Ich habe so was gemacht, was mit allen !-Wire-Devices von Dallas funktioniert, auch mit dem von angesprochenen DS18B20. Wenn Du daran Interesse hast und keine kommerziellen Ansätze verfolgst könnten wir ins Geschäft kommen. Gruß zeno
Holger W. schrieb: > noch eine Frage warum am Ende noch durch 16 teilen? Im Datenblatt steht > das nicht. 1. Damit "***SNIPPET*****" die Temperatur in Einheiten von °C zurück gibt. 2. Datenblatt S.3f
Hallo, hier ein Auszug aus dem Datenblatt: The DS18B20 output temperature data is calibrated in degrees Celsius; for Fahrenheit applications, a lookup table or conversion routine must be used. The tempera- ture data is stored as a 16-bit sign-extended two’s comple- ment number in the temperature register (see Figure 4). Codix schrieb: > ***SNIPPET***** > > if( id[0] == 0x28 || id[0] == 0x10 ){ // temperature sensor > w1_byte_wr( READ ); // read command > temp = w1_byte_rd(); // low byte > temp |= (uint)w1_byte_rd() << 8; // high byte > if( id[0] == 0x10 ) // 9 -> 12 bit > temp <<= 3; > } > else > return(0); > return(temp >> 4); // Divided by 16 Die richtige Temperatur wird jetzt bei mir angezeigt aber diesen Codeteil habe ich noch nicht verstanden. Ich habe mir erstmal ein Buch für c bestellt. trotzdem noch meine Frage warum am Ende durch 16 teilen? Im Datenblatt steht das nicht und vielleicht kann mir jemand kurz diesen Codeteil erkären bis das Buch da ist. Grüße Holger
H.Joachim S. schrieb: > ohne Worte :-) mit Worte: die Ausgabe des Sensors ist eine 16bit-Integer-Zahl mit Vorzeichen, aber die Einheit ist 1/16 Grad! 4 bit Rechtsschieben schmeisst die Grad-Bruchteile einfach weg, wenn du die aber wissen willst (wahrscheinlich ist der Sensor aber nicht so genau), musst du statt Schieben echt dividieren, und das Ergebnis muss dann natürlich vom Typ real sein. Georg
Georg schrieb: > H.Joachim S. schrieb: >> ohne Worte :-) > > mit Worte: die Ausgabe des Sensors ist eine 16bit-Integer-Zahl mit > Vorzeichen, aber die Einheit ist 1/16 Grad! 4 bit Rechtsschieben > schmeisst die Grad-Bruchteile einfach weg, wenn du die aber wissen > willst (wahrscheinlich ist der Sensor aber nicht so genau), musst du > statt Schieben echt dividieren, und das Ergebnis muss dann natürlich vom > Typ real sein. > > Georg So macht man das aber nicht auf kleinen Controllern. Man dividiert ganzzahlig (schieben) durch 16 und den Bruchteil erhält man durch eine Modulo 16 Operation. Diesen kann man mit ABS vom Vorzeichen befreien und dann kann man beides zusammen z.B. auf einem LCD anzeigen. Textlich muss noch ein Komma dazwischen.
Cyblord -. schrieb: > So macht man das aber nicht auf kleinen Controllern Da hast du im Sinn der Effektivität sicher recht, aber das dürfte den TO doch noch überfordern - schliesslich fängt er gerade erst an sich mit den Grundlagen von C zu beschäftigen. Und von Assembler hat er sicher höchstens mal ganz entfernt was gehört. Georg
Hi > aber das dürfte den TO doch noch überfordern - Und da fängt man mit 1-Wire an? >schliesslich fängt er gerade erst an sich mit >den Grundlagen von C zu beschäftigen. Dann sollte er auch mit den Grundlagen anfangen. MfG spess
Georg schrieb: > mit Worte: die Ausgabe des Sensors ist eine 16bit-Integer-Zahl mit > Vorzeichen, aber die Einheit ist 1/16 Grad! 4 bit Rechtsschieben > schmeisst die Grad-Bruchteile einfach weg, wenn du die aber wissen > willst (wahrscheinlich ist der Sensor aber nicht so genau), musst du > statt Schieben echt dividieren, und das Ergebnis muss dann natürlich vom > Typ real sein. Ein bisschen bessere Resultate soll mann dann schon bekommen mit
1 | return((temp + 8) >> 4); // Divided by 16 |
Dann wird aus 0,96°C wenigstens 1°C statt 0°C :-)
Ja, dass mit dem Teilen durch 16 habe ich verstanden. Integerzahlen in Binärschreibweise haben keine Dezimalstellen. Diese werden hier mit der Teilung durch 16 erzeugt. Teilung durch 16 weil die letzen 4 bit die Dezimalstellen darstellen und 4 bit 1/16 darstellt. Also ist jede Werterhöhung um 1 in dieser Integerzahl nur ein 1/16 Grad. Im Falle des Schiebens (4 bit Rechtsschieben) und wegschmeißen wird nicht mehr dividiert, dann ist die Integerzahl die Gradzahl. Wenn mir jemand noch etwas zu dieser Zeile sagen kann,habe ich alles soweit verstanden if( id[0] == 0x10 ) // 9 -> 12 bit temp <<= 3; Ist das etwas mit der Anzahl der Dezimalstellen ? Wird hier gerundet? Weil ich in der Ausgabe nur die erste Dezimalstelle erhalte, die andern sind Null bei der Teilung durch 16. vielen Dank Holger
Bitte sagt mir noch etwas kurz zu dieser Zeile: Wass macht diese: if( id[0] == 0x10 ) // 9 -> 12 bit temp <<= 3; Grüße Holger
Ich will nicht nerven, aber bitte redet mit mir. Mein neues Buch kommt erst morgen. Holger
Da wird nur geschaut, welcher Sensortype ( 9 oder 12 Bit, langsam oder langsammer ;-) ) es ist. Steht aber auch im Datenblatt. Hans
Cyblord -. schrieb: > So macht man das aber nicht auf kleinen Controllern. Man dividiert > ganzzahlig (schieben) durch 16 und den Bruchteil erhält man durch eine > Modulo 16 Operation. Diesen kann man mit ABS vom Vorzeichen befreien und > dann kann man beides zusammen z.B. auf einem LCD anzeigen. Textlich muss > noch ein Komma dazwischen. Modulo 16 liefert Werte von 0 bis 15. Wie man damit nur durch Integer-Arithmetik entweder auf die vierstelligen oder sinnvollerweise auf eine Stelle nach dem Komma gerundeten Werte kommen kann, erschließt sich mir jetzt auf Anhieb aber noch nicht. 0x07d0 -> 125,0000 °C -> 125,0 °C .. .. .. 0x000f -> 0,9375 °C -> 0,9 °C .. .. .. 0x0003 -> 0,1875 °c -> 0,2 °C 0x0002 -> 0,1250 °C -> 0,1 °C 0x0001 -> 0,0625 °C -> 0,1 °C 0x0000 -> 0,0000 °C -> 0,0 °C 0xffff -> -0,0625 °C -> -0,1 °C .. .. .. 0xfc90 -> -55,0000 °C -> -55,0 °C int16_t temp; ... printf("%.4f °C", temp / 16.0); bzw. printf("%.1f °C", temp / 16.0); liefert hingegen das gewünschte Ergebnis auch ohne Verrenkungen, bläht die Sache aber natürlich auf 8-Bit-Rechnern auch deutlich auf. Mit besten Grüßen Murmelchen
also mit eurer Hilfe funktioniert alles so wie es soll und ich habe auch alles so weit verstanden. Jetzt sind auch die DS 1820 angekommen. Ich werde mal die Tolleranz zu den DS 18B20 testen. Ich kann ja jetzt beide verwenden. Danke noch mal. Holger Weiß
zum Vergleich der Sensoren DS 18B20 16,1 grad DS 1820 17,2 grad DS 1820 17,0 grad Die beiden 1820 sind gleich aber der 18B20 weicht um ein grad ab !!! Mir ist noch aufgefallen, dass nur die 1820 nach dem anschließen um 0,5 grad ansteigen. Ist dass eine eigene Erwärmung nach den anschließen (Verlustleistung)?? Beim 1820 ist das nicht der Fall, der ist einer Edelstahlhülse. Vielleicht verhindert die Edelstahlhülle die eigene Erwärmung und leitet die Verlustleistung ab? , dann wäre die Differenz noch im Rahmen. Ich habe den ganzen Aufwand nur wegen dem Abgleich für ein älteres Projekt mit analogen Sensoren gemacht und jetzt habe ich wieder keine exakte Referenztemperatur. Hat jemand einen Vorschlag ? Ein grad Abweichung ist mir zu hoch. Gibt es bessere digitale Sensoren für 1-Wire? Grüße Holger
Holger W. schrieb: > Die beiden 1820 sind gleich aber der 18B20 weicht um ein grad ab !!! Vorab, die gelieferten Werte der Sensoren können durchaus um 1 Grad voneinander abweichen. Zudem sind die 1820 vermutlich auch schon älter und da gab es zumindest Gerüchte, dass dann auch noch größere Abweichungen möglich sein sollen, das heißt, dass die Sensoren dann auch möglicherweise durch Aufnahme von Feuchtigkeit verursacht auch Werte außerhalb ihrer Spezifikation liefern können. Aber stimmen deine Berechnungen denn auch wirklich? Auch das ist ja aufgrund der vorherigen Beiträge auch nicht völlig auszuschließen. Und es geistern auch recht viele Quelltexte durchs Internet, bei denen die Berechnung zumindest unsauber oder sogar schlicht falsch programmiert wurde. Mach Dir doch mal die Mühe, anhand der vom Sensor gelieferten Bits die jeweiligen Temperaturen von Hand zu berechnen und vergleiche die Ergebnisse dann mit denen durch die C-Routinen angezeigten Werte. Murmelchen
Holger W. schrieb: > Gibt es bessere digitale Sensoren für 1-Wire? ich habe diverse ds1820 im Einsatz. Diese sind im Bereich 15-35° mindestens auf 0,2° genau, eher noch besser. Z.B. habe ich ds1820-Sensoren neben den PT1000-Sensoren eines geeichten Wärmemengenzählers sitzen. Ein signifikantes Abweichen der gemessenen Werte im Bereich 15-35° war nicht feststellbar.
@ TO Dieses abschliessende abschliessende Schieben um 4 Bit nach rechts (was als Division kommentiert ist) hat auch zur Folge, dass ein Rundungsfehler entsteht. Die Nachkommastellen der Festkommazahl werden nämlich damit einfach ignoriert. Das Wort Division suggeriert zumindest die Möglichkeit, dass damit auch eine Rundung geschehen könnte. Falls Du das gedacht hast: Das ist nicht so. Es wären zwei interessante Übungen, Einmal zu prüfen ob eine Rundung nötig ist, und die zu berücksichtigen und zum Zweiten, die Nachkommastellen tatsächlich auszugeben. Damit solltest Du auch höher aufgelöste Werte angezeigt bekommen. Ob der Sensor selbst so genau ist, wie gewünscht kann ich allerdings nicht sagen. Aber das siehst Du dann, weil Du die tatsächlichen Werte siehst und nichts falsch gerundetes oder mit weniger Stellen als möglich sind.
Cyblord -. schrieb: > Man dividiert > ganzzahlig (schieben) durch 16 und den Bruchteil erhält man durch eine > Modulo 16 Operation. dazu muss man wissen dass die "Modulo-Operation" in C keine Modulooperation im mathematischen Sinn ist, sondern eher eine "Divisionrest-Operation"
Walter S. schrieb: > dazu muss man wissen dass die "Modulo-Operation" in C keine > Modulooperation im mathematischen Sinn ist, sondern eher eine > "Divisionrest-Operation" Dann zeigt doch mal eine (zumindest halbwegs elegante) Lösung, die für den hier behandelten Fall nur durch Integer-Arithmetik für alle Werte das vollständige oder das auf eine Stelle nach dem Komma korrekt gerundete Ergebnis liefert. Murmelchen
Cyblord -. schrieb: > So macht man das aber nicht auf kleinen Controllern. Doch, genauso macht man das.
Walter S. schrieb: > Cyblord -. schrieb: >> Man dividiert >> ganzzahlig (schieben) durch 16 und den Bruchteil erhält man durch eine >> Modulo 16 Operation. > > dazu muss man wissen dass die "Modulo-Operation" in C keine > Modulooperation im mathematischen Sinn ist, sondern eher eine > "Divisionrest-Operation" Wo ist denn nun, mathematisch, der Unterschied zwischen einer "Divisionrest-Operation" und einer Modulo-Operation? Ich hätte das jetzt Synonym gesehen.
Bernd K. schrieb: > Cyblord -. schrieb: >> So macht man das aber nicht auf kleinen Controllern. > > Doch, genauso macht man das. Da wolltest auch mal was sagen?
printf und float auf kleinem Controller - habe es gerade mal für einen AVR compiliert: +3200 byte. Also für kleine Controller ist das eher nichts.
H.Joachim S. schrieb: > printf und float auf kleinem Controller - habe es gerade mal für einen > AVR compiliert: +3200 byte. Also für kleine Controller ist das eher > nichts. Ja aber Bernd K. sagt das macht man so ;-) Du hast natürlich recht, darum Festkomma und für die Anzeige als Text entsprechend aufbereiten. Das ist bei den DS18B20 tausendfach bewährt. Man braucht kein float und auch kein sprintf.
Cyblord -. schrieb: > Wo ist denn nun, mathematisch, der Unterschied zwischen einer > "Divisionrest-Operation" und einer Modulo-Operation? Ich hätte das jetzt > Synonym gesehen. siehe Wikipedia: Steht in einer Sprache wie C(++) oder Java nur die symmetrische Variante zur Verfügung, kann man Ergebnisse nach der mathematischen Variante erhalten mit: a mod b = ( a % b + b) % b wobei % der symmetrischen Modulooperation entspricht und mod der mathematischen.
Und das ist tatsächlich was anderes? Zum Rest addiert man nochmal den Teiler und teilt dann wieder durch den? Auf den ersten Blick sieht das identisch aus - aber manchmal wundert man sich ja.
Hans schrieb: > Es macht bei negativen Zahlen einen Unterschied. ganz genau, und jetzt frag ich mich welche Null mir für meinen Post eine -1 gibt, wäre interessant wenn die Bewertungen nicht anonym wären
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.