Hallo Weiß zufällig jemand nach welcher Formel die Temperatur beim DS18B20 berechnet wird. MfG Unti
Roland ... schrieb: > Digitalwert * 0,0625 = T [°C] Funktioniert bei negativen Temperaturen nicht. Ansonsten: http://datasheets.maximintegrated.com/en/ds/DS18B20.pdf
Brat schrieb: >> Digitalwert * 0,0625 = T [°C] > > Funktioniert bei negativen Temperaturen nicht. Weshalb nicht?
In dem Datenblatt steht nichts wie man die Temperatur berechnet ==> KEINE FORMEL !!!!!!!!!!
Im Datenblatt ist genau aufgeschlüsselt, wie die Bits zu interpretieren sind und welche Bedeutung sie haben. Die gehen halt davon aus, dass jemand der µC programmiert, selbst in der Lage ist, die Umrechnung in der Programmiersprache seiner Wahl korrekt zu implementieren.
Stefan Untner schrieb: > In dem Datenblatt steht nichts wie man die Temperatur berechnet ==> > KEINE FORMEL !!!!!!!!!! Wenn du zu faul bist, das Datenblatt zu lesen und zu verstehen, dann such' dir ein anderes Betätigungsfeld.
Das hier (Bild), zusammen mit der Information, dass 2-er Komplement verwendet wird, ist alles was man benötigt um daraus die Temperatur zu berechnen. Jeder Informatik-Student kann das fehlerfrei nach der Hälfte seines ersten Studien-Semesters interpretieren. Nämlich, dass er den aus High und Low-Byte zusammengesetzten Wert (wenn seine Maschine 2-er Komplement verwendet, was sehr wahrscheinlich ist), einfach nur durch 16 Dividieren muss. Denn genau das ist es, was durch die 4 Nachkommabits (deren Exponent negativ ist) ausgesagt wird.
:
Bearbeitet durch User
Brat schrieb: >> Digitalwert * 0,0625 = T [°C] > > Funktioniert bei negativen Temperaturen nicht. Also bei mir funktionierts: (int16_t)0xFFF8 = -8 -8 * 0,0625 = -0,5°C Man sollte natürlich das Datenblatt lesen können: "The temperature data is stored as a 16-bit sign-extended two’s complement number"
Brat schrieb: > Roland ... schrieb: > >> Digitalwert * 0,0625 = T [°C] > > Funktioniert bei negativen Temperaturen nicht. Doch, das funktioniert schon. Man muss nur aufpassen, wenn man Vorkomma und Nachkommaanteil selbst getrennt wegen der Ausnutzung von Integer Operationen ausrechnet. Setzt man aber Floating Point Operationen ein, dann kommt da auch das richtige Ergebnis raus.
Karl Heinz schrieb: > Brat schrieb: >> Roland ... schrieb: >> >>> Digitalwert * 0,0625 = T [°C] >> >> Funktioniert bei negativen Temperaturen nicht. > > Doch, das funktioniert schon. Du interpretierst in die Antwort von Roland mehr hinein, als tatsächlich in ihr enthalten ist :)
Brat schrieb: > Karl Heinz schrieb: >> Brat schrieb: >>> Roland ... schrieb: >>> >>>> Digitalwert * 0,0625 = T [°C] >>> >>> Funktioniert bei negativen Temperaturen nicht. >> >> Doch, das funktioniert schon. > > Du interpretierst in die Antwort von Roland mehr hinein, als tatsächlich > in ihr enthalten ist :) Nämlich? Die Antwort ist IMHO (fast) völlig korrekt. Erwähnenswert wäre eventuell noch, dass 'Digitalwert' einen Datentyp haben sollte, der prinzipiell ein Vorzeichen zulässt (ein int16_t in C), aber das ist dann schon wieder ein technisches Detail der verwendeten Programmiersprache.
:
Bearbeitet durch User
möchte mich für ("In dem Datenblatt steht nichts wie man die Temperatur berechnet ==> KEINE FORMEL !!!!!!!!!!") entschuldigen. War schon sehr gestersst und etwas genervt. Bin allerdings keine Informatikstudent sondern kompletter Anfänger und verstehe deswegen nur die Hälfte von dem was ihr Antwortet. (z.B.: (int16_t)0xFFF8 = -8 -8 * 0,0625 = -0,5°C ) bitte um erklärung ich brauche wirklich dringend eure Hilfe MfG Unti
In Worten: Der Wert im DS18B20 gibt die Temperatur in sechzehntel Grad Celsius an. Mit Vorzeichen im Zweierkomplement, also als int16_t. Division durch Sechzehn liefert also Grad Celsius.
:
Bearbeitet durch User
Stefan Untner schrieb: > möchte mich für ("In dem Datenblatt steht nichts wie man die Temperatur > berechnet ==> KEINE FORMEL !!!!!!!!!!") entschuldigen. > War schon sehr gestersst und etwas genervt. Bin allerdings keine > Informatikstudent sondern kompletter Anfänger und verstehe deswegen nur > die Hälfte von dem was ihr Antwortet. > (z.B.: (int16_t)0xFFF8 = -8 > -8 * 0,0625 = -0,5°C > ) > bitte um erklärung > ich brauche wirklich dringend eure Hilfe > > MfG Unti Wo ist denn nun noch dein Problem? Das was im Register steht, geteilt durch 16 ist deine Temperatur. Dann gabs Beispiele wie man das auf 8-Bittern am besten rechnen lässt. Dein Problem beschränkt sich leider nicht auf den DS18B20, sondern liegt wohl ebenfals in der nur sehr mäßgen Beherrschung deiner Programmiersprache. Ändere das doch einfach mal.
cyblord ---- schrieb: > wohl ebenfals in der nur sehr mäßgen Beherrschung deiner > Programmiersprache. Sagt er doch selbst >Ändere das doch einfach mal. fehlt nur noch: Wenn Du die Programmiersprache beherrscht--> noch einmal melden. Das klingt doch schon mehr oder weniger überheblich.
Wolfgang-G schrieb: > cyblord ---- schrieb: >> wohl ebenfals in der nur sehr mäßgen Beherrschung deiner >> Programmiersprache. > Sagt er doch selbst Na und dann? >>Ändere das doch einfach mal. > fehlt nur noch: Wenn Du die Programmiersprache beherrscht--> noch einmal > melden. > Das klingt doch schon mehr oder weniger überheblich. Nun das ist eben Vorraussetzung, dass man die Programmiersprache beherrscht. Denn du siehst ja, die Tipps helfen gar nichts, die Antwort auf seine Frage hat er bekommen, aber hilfts ihm weiter? Nein natürlich. Also ist mir ziemlich egal wie das klingt, es ist halt einfach wahr. gruß cyblord
Hier die angepasste Version von Peter Dannegger welche Negative Temperaturen und im 0.1 Format ausgibt. Such dir das passende raus. Hilft dir am Anfang mehr als die Hinweise aufs Datenblatt.
1 | /************************************************************************/
|
2 | /* */
|
3 | /* Access Dallas 1-Wire Devices */
|
4 | /* */
|
5 | /* Author: Peter Dannegger */
|
6 | /* danni@specs.de */
|
7 | /* */
|
8 | /************************************************************************/
|
9 | #include <avr/io.h> |
10 | #include <avr/interrupt.h> |
11 | #include <util/delay.h> |
12 | #include <string.h> |
13 | #include <stdlib.h> |
14 | |
15 | #include "../konfig.h" |
16 | |
17 | #if USE_D1820_SENSOR
|
18 | |
19 | #include "../main.h" |
20 | |
21 | #if DEBUG
|
22 | #include "../uart/uart.h" |
23 | #endif
|
24 | |
25 | #include "1wire.h" |
26 | |
27 | /*********************************************************************/
|
28 | void one_wire_init(void) { |
29 | /*********************************************************************/
|
30 | W1_SPANNUNG_DDR |= (1 << W1_SPANNUNG); // W1_SPANNUNG als Ausgang setzen |
31 | W1_SPANUNG_PORT |= (1 << W1_SPANNUNG); // W1_SPANNUNG Pin High |
32 | }
|
33 | /*********************************************************************/
|
34 | void one_wire_spannung_aus(void) { |
35 | /*********************************************************************/
|
36 | W1_SPANUNG_PORT &= ~(1 << W1_SPANNUNG); // Pin Low |
37 | }
|
38 | /*********************************************************************/
|
39 | void one_wire_spannung_ein(void) { |
40 | /*********************************************************************/
|
41 | W1_SPANUNG_PORT |= (1 << W1_SPANNUNG); // W1_SPANNUNG Pin High |
42 | }
|
43 | |
44 | /******************************************************************/
|
45 | uint8_t w1_reset(void) { |
46 | /******************************************************************/
|
47 | uint8_t err; |
48 | |
49 | W1_OUT &= ~(1 << W1_PIN); |
50 | W1_DDR |= 1 << W1_PIN; |
51 | _delay_us(480); |
52 | |
53 | cli(); |
54 | W1_DDR &= ~(1 << W1_PIN); |
55 | _delay_us(66); |
56 | err = W1_IN & (1 << W1_PIN); // no presence detect |
57 | sei(); |
58 | |
59 | _delay_us(480 - 66); |
60 | |
61 | if ((W1_IN & (1 << W1_PIN)) == 0) // short circuit |
62 | err = 1; |
63 | |
64 | return err; |
65 | }
|
66 | /******************************************************************/
|
67 | uint8_t w1_bit_io(uint8_t b, uint8_t pull) { |
68 | /******************************************************************/
|
69 | |
70 | cli(); |
71 | |
72 | W1_DDR |= 1 << W1_PIN; |
73 | |
74 | _delay_us(2); |
75 | if (b) |
76 | W1_DDR &= ~(1 << W1_PIN); |
77 | |
78 | _delay_us(10 - 2); |
79 | if ((W1_IN & (1 << W1_PIN)) == 0) |
80 | b = 0; |
81 | |
82 | _delay_us(60 - 10); |
83 | if (pull) { |
84 | W1_OUT |= (1 << W1_PIN); |
85 | W1_DDR |= (1 << W1_PIN); |
86 | } else |
87 | W1_DDR &= ~(1 << W1_PIN); |
88 | _delay_us(10); |
89 | |
90 | sei(); |
91 | |
92 | return b; |
93 | }
|
94 | /******************************************************************/
|
95 | uint16_t w1_byte_wr(uint8_t b) { |
96 | /******************************************************************/
|
97 | |
98 | uint8_t i = 8, j; |
99 | |
100 | uint8_t cnv = (b == CONVERT_T); |
101 | |
102 | do { |
103 | j = w1_bit_io(b & 1, cnv && i == 1); |
104 | b >>= 1; |
105 | if (j) |
106 | b |= 0x80; |
107 | } while (--i); |
108 | |
109 | return b; |
110 | }
|
111 | /******************************************************************/
|
112 | uint16_t w1_byte_rd(void) { |
113 | /******************************************************************/
|
114 | |
115 | return w1_byte_wr(0xFF); |
116 | }
|
117 | /******************************************************************/
|
118 | uint8_t w1_rom_search(uint8_t diff, uint8_t idata *id) { |
119 | /******************************************************************/
|
120 | |
121 | uint8_t i, j, next_diff; |
122 | uint8_t b; |
123 | |
124 | if (w1_reset()) |
125 | return PRESENCE_ERR; // error, no device found |
126 | |
127 | w1_byte_wr(SEARCH_ROM); // ROM search command |
128 | next_diff = LAST_DEVICE; // unchanged on last device |
129 | |
130 | i = 8 * 8; |
131 | do { |
132 | j = 8; |
133 | do { |
134 | b = w1_bit_io(1, 0); // read bit |
135 | _delay_us(2); |
136 | if (w1_bit_io(1, 0)) { // read complement bit |
137 | if (b) // 11 |
138 | return DATA_ERR; // data error |
139 | } else { |
140 | if (!b) { // 00 = 2 devices |
141 | if (diff > i || ((*id & 1) && diff != i)) { |
142 | b = 1; // now 1 |
143 | next_diff = i; // next pass 0 |
144 | }
|
145 | }
|
146 | }
|
147 | w1_bit_io(b, 0); // write bit |
148 | *id >>= 1; |
149 | if (b) // store bit |
150 | *id |= 0x80; |
151 | i--; |
152 | } while (--j); |
153 | id++; // next byte |
154 | } while (i); |
155 | |
156 | return next_diff; // to continue search |
157 | }
|
158 | |
159 | /******************************************************************/
|
160 | void w1_command(uint8_t command, uint8_t idata *id) { |
161 | /******************************************************************/
|
162 | uint8_t i; |
163 | |
164 | w1_reset(); |
165 | if (id) { |
166 | w1_byte_wr(MATCH_ROM); // to a single device |
167 | i = 8; |
168 | do { |
169 | w1_byte_wr(*id); |
170 | id++; |
171 | } while (--i); |
172 | } else { |
173 | w1_byte_wr(SKIP_ROM); // to all devices |
174 | }
|
175 | w1_byte_wr(command); |
176 | }
|
177 | /******************************************************************/
|
178 | uint8_t start_meas(void) { |
179 | /******************************************************************/
|
180 | if (W1_IN & 1 << W1_PIN) { |
181 | w1_command(CONVERT_T, NULL ); |
182 | W1_OUT |= 1 << W1_PIN; |
183 | W1_DDR |= 1 << W1_PIN; // parasite power on |
184 | return 1; |
185 | } else { |
186 | return 0; |
187 | }
|
188 | }
|
189 | /******************************************************************/
|
190 | uint8_t read_meas(void) { |
191 | /******************************************************************/
|
192 | uint8_t id[8], diff; |
193 | unsigned char scratchpad[9]; |
194 | int temp; |
195 | |
196 | DS1820_count = 0; |
197 | |
198 | for (diff = SEARCH_FIRST; diff != LAST_DEVICE;) { |
199 | |
200 | diff = w1_rom_search(diff, id); |
201 | |
202 | if (diff == PRESENCE_ERR) { // No Sensor found |
203 | # if DEBUG
|
204 | uart_puts_P(PSTR("No Sensor" CR)); |
205 | # endif
|
206 | return 87; |
207 | break; |
208 | }
|
209 | |
210 | if (diff == DATA_ERR) { // Bus Error |
211 | # if DEBUG
|
212 | uart_puts_P(PSTR("Bus Error" CR)); |
213 | # endif
|
214 | return 86; |
215 | break; |
216 | }
|
217 | |
218 | if (id[0] == 0x28 || id[0] == 0x10) { // temperature sensor prüfung ob Ds1820 Version S oder B |
219 | |
220 | w1_byte_wr(READ); // read command |
221 | |
222 | for (temp = 0; temp < 9; temp++) |
223 | scratchpad[temp] = w1_byte_rd(); // Scratchpad füllen (9 Bytes) |
224 | |
225 | if (id[0] == 0x10) { // DS18S20 |
226 | if (scratchpad[1]) { // Negativer Temperaturwert |
227 | scratchpad[0] ^= 0xFF; // Einer-Komplement |
228 | scratchpad[0]++; // inkrementieren |
229 | }
|
230 | scratchpad[0] >>= 1; // rechtes Bit für 0,5 °C rausschieben (durch 2 teilen) |
231 | |
232 | // Temperatur mit 0,1 °C Genauigkeit berechnen
|
233 | temp = (int) scratchpad[0] * 100 - 25 + (int) (scratchpad[7] - scratchpad[6]) * 100 / scratchpad[7]; |
234 | if (scratchpad[1]) // Negativer Temperaturwert |
235 | temp *= -1; |
236 | temp /= 10; // Zweite Nachkommastelle abtrennen |
237 | } else { // 0x28: DS18B20 |
238 | if (scratchpad[1] & 0xF8) { // Negativer Temperaturwert |
239 | scratchpad[0] ^= 0xFF; // Einer-Komplement |
240 | scratchpad[0]++; // inkrementieren |
241 | scratchpad[1] ^= 0xFF; // Einer-Komplement |
242 | temp = -(((int) scratchpad[1] << 8) | (int) scratchpad[0]) * 10 / 16; |
243 | } else { |
244 | temp = (((int) scratchpad[1] << 8) | (int) scratchpad[0]) * 10 / 16; |
245 | }
|
246 | }
|
247 | |
248 | if (temp == 850) { |
249 | return 85; |
250 | } else { |
251 | uint8_t i = 0; |
252 | |
253 | itoa(temp, DS1820[DS1820_count].temperatur, 10); // die Zahl in einen String umwandeln |
254 | while (DS1820[DS1820_count].temperatur[i]) // die Position der terminierende /0 finden |
255 | i++; |
256 | DS1820[DS1820_count].temperatur[i] = DS1820[DS1820_count].temperatur[i - 1]; // die Nachkommastelle nach rechts schieben |
257 | DS1820[DS1820_count].temperatur[i - 1] = '.'; // statt dessen ein Dezimaltrennzeichen einfügen |
258 | DS1820[DS1820_count].temperatur[++i] = 0; // Am Ende wieder eine /0 anfügen |
259 | }
|
260 | |
261 | DS1820_count++; // Terminator |
262 | }
|
263 | |
264 | }
|
265 | |
266 | return 1; |
267 | |
268 | }
|
269 | |
270 | #endif
|
Stefan Untner schrieb: > Meine Frage wäre da noch was genau ist bzw. macht int16_t Ein int16_t ist ein Datentyp. Der Name sagt es schon, es ist ein INteger, mit Vorzeichen (wegen dem fehlenden u), der aus 16 Bit besteht.
1 | int8_t 8 Bit, mit Vorzeichen |
2 | uint8_t 8 Bit, ohne Vorzeichen |
3 | int16_t 16 Bit, mit Vorzeichen |
4 | uint16_t 16 Bit, ohne Vorzeichen |
5 | int32_t 32 Bit, mit Vorzeichen |
6 | uint32_t 32 Bit, ohne Vorzeichen |
auf einem AVR ist int16_t dasselbe wie ein plain vanilla 'int'
:
Bearbeitet durch User
Stefan Untner schrieb: > danke > und was heist dann (int16_t)0xFFF8 = -8 der Wert 0xFFF8 wird auf einen int6_t umgecastet. In dieser Form (also als uint16_t) repräsentiert dieses Bitmuster den Zahlenwert -8 Das ist also die logische Beschreibung von * nimm deine 2 Bytes, die du vom Sensor bekommst und steck sie Endian-richtig in einen int16_t hinein. (zb kriegst du vom Sensor die Bytes 0xFF und 0xF8. Steckst du die in einen int16_t, so dass dieser dann bytemässig als 0xFFF8 aufgebaut ist, dann ist das dasselbe, als wie wenn du der int16_t Variable den Wert -8 zugewiesen hättest. Das 16 Bit Bitmuster (im 2-er Komplement) für -8 ist genau 0xFFF8 * lässt du dir diesen int16_t zb mittels
1 | int16_t wert = (int16_t)0xFFF8; |
2 | printf( "%d", wert ) |
ausgeben, dann steht an der Anzeige daher -8. 0xFFF8 als 16 Bit Zahl im 2-er Komplement interpretiert, ist nichts anders als die Bitrepräsentierung von -8 innerhalb des Rechners.
:
Bearbeitet durch User
Als "C-Götter" könntet ihr doch einfach ihm mal ein kurzen (funktionierenden) C-Schnipsel posten! Wurd Euch weder arm machen noch Schmerzen zufügen!
Hmm.. schrieb: > Als "C-Götter" könntet ihr doch einfach ihm mal ein kurzen > (funktionierenden) C-Schnipsel posten! Wurd Euch weder arm machen noch > Schmerzen zufügen! Nö. Entweder ER baut das oder er kauft sich ein fertiges Thermometer. Aber wenn ER das bauen will, dann soll auch ER das bauen. Und dazu gehört nun mal dazu, dass man die dazu notwendige Technik und Kentnisse auch erlernt. Wenn man nix kann, trotzdem aber etwas machen will, dann kann man vielleicht zu DSDS gehen und für ein paar Lacher bei den Zusehern sorgen. Aber in der Technik funktioniert das nicht. Es reicht eben nicht, nur mit dem Wunsch Fische fangen zu wollen, zum Fluss zu gehen. Man muss auch ein Netz mitbringen und es benutzen können. - alte indianische Weisheit.
:
Bearbeitet durch User
Hmm.. schrieb: > Als "C-Götter" könntet ihr doch einfach ihm mal ein kurzen > (funktionierenden) C-Schnipsel posten! Wurd Euch weder arm machen noch > Schmerzen zufügen! Nun es kommt stark darauf an was er damit tun will. Wo steht denn das? Beschreibt er denn überhaupt ein Projekt? Er stellt eine Frage und bekommt eine Antwort. Hier funktionierendes SchnipseL: Eine Möglichkeit um den Temperaturwert in 1/10 Grad zu bekommen wäre z.B.:
1 | int16_t convertTemp(int32_t raw) { |
2 | raw=raw*10; |
3 | raw=raw/16; |
4 | return (int16_t)raw; |
5 | }
|
Und aus der Praxis, so nutze ich den DS18B20 für meine Anwendung sehr oft. Und nun? Bringt ihm das was?
:
Bearbeitet durch User
Das bringt mir leider nicht viel. Mein Hauptproblem ist, wenn ich das richtig verstehe, dass ich das LSB als erstes gesendet bekomme, ich aber das MSB zuerst auswerten muss. Bin ich da schon auf dem richtigen Weg ??? und zu cyblord, ich will mit einem Temperatursensor Temperaturen messen. :P
Stefan Untner schrieb: > Das bringt mir leider nicht viel. Mein Hauptproblem ist, wenn ich das > richtig verstehe, dass ich das LSB als erstes gesendet bekomme, ich aber > das MSB zuerst auswerten muss. Bin ich da schon auf dem richtigen Weg > ??? Nein. Dein erster Schritt ist es, MSB und LSB (nachdem du sie hast) zu einer 16-Bit Zahl in einem int16_t zusammen zu setzen. Danach interessiert dich MSB und LSB nicht mehr. Du hast dann bereits die 16 Bit Zahl (inklusive Vorzeichen), mit der weiter gearbeitet wird.
Stefan Untner schrieb: > Das bringt mir leider nicht viel. Mein Hauptproblem ist, wenn ich das > richtig verstehe, dass ich das LSB als erstes gesendet bekomme, ich aber > das MSB zuerst auswerten muss. Bin ich da schon auf dem richtigen Weg > ??? Dermaßen Holzweg... Das sind ja verschiedene Schritte. 1 Schritt: Lese die 16 Bit Temperatur aus dem Sensor. Klar, das sind 2 Bytes, die musst du zu einem 16 Bit Wert zusammenbauen, und dann z.B. in einer int16_t Variable speichern. Als 2. Schritt kommt dann die Berechnung welche die Temperatur in °C berechnet. > und zu cyblord, ich will mit einem Temperatursensor Temperaturen messen. > :P Lustig. Dann bist du ja jetzt fertig. Schon vor der Berechnung hast du bereits die Temperatur gemessen. Wahrscheinlich willst du die Temp. aber noch auf einem LCD ausgeben, d.h. du musst das ganze noch in einen String umwandeln, mit Komma und allem. Aber hey, so lustig wie du bist, schaffst du das sicher alleine. Du hast ja nur 20 Posts gebraucht um dir erklären zu lassen wie man eine Zahl durch 16 teilt. Nur um dann am Ende anzukommen mit deiner LSB/MSB Geschichte. Lächerlich. Mal ehrlich, dein Wissenstand reicht eigentlich momentan für keine ernsthafte Anwendung aus. Wenns schon an Bytes to Int scheitert und am Verstehen von einfachsten Vorgehensweisen, Datentypen, Zahlenformaten, dann solltest du in diesem Bereich dringend etwas nachholen. Und danach den DS18B20 nochmal rauskramen. gruß cyblord
Karl Heinz schrieb: > Stefan Untner schrieb: >> Das bringt mir leider nicht viel. Mein Hauptproblem ist, wenn ich das >> richtig verstehe, dass ich das LSB als erstes gesendet bekomme, ich aber >> das MSB zuerst auswerten muss. Bin ich da schon auf dem richtigen Weg >> ??? > > Nein. > Dein erster Schritt ist es, MSB und LSB (nachdem du sie hast) zu einer > 16-Bit Zahl in einem int16_t zusammen zu setzen. > > Danach interessiert dich MSB und LSB nicht mehr. Du hast dann bereits > die 16 Bit Zahl (inklusive Vorzeichen), mit der weiter gearbeitet wird. Der Teil hier aus dem Code ...
1 | if (id[0] == 0x10) { // DS18S20 |
2 | if (scratchpad[1]) { // Negativer Temperaturwert |
3 | scratchpad[0] ^= 0xFF; // Einer-Komplement |
4 | scratchpad[0]++; // inkrementieren |
5 | }
|
6 | scratchpad[0] >>= 1; // rechtes Bit für 0,5 °C rausschieben (durch 2 teilen) |
7 | |
8 | // Temperatur mit 0,1 °C Genauigkeit berechnen
|
9 | temp = (int) scratchpad[0] * 100 - 25 + (int) (scratchpad[7] - scratchpad[6]) * 100 / scratchpad[7]; |
10 | if (scratchpad[1]) // Negativer Temperaturwert |
11 | temp *= -1; |
12 | temp /= 10; // Zweite Nachkommastelle abtrennen |
13 | } else { // 0x28: DS18B20 |
14 | if (scratchpad[1] & 0xF8) { // Negativer Temperaturwert |
15 | scratchpad[0] ^= 0xFF; // Einer-Komplement |
16 | scratchpad[0]++; // inkrementieren |
17 | scratchpad[1] ^= 0xFF; // Einer-Komplement |
18 | temp = -(((int) scratchpad[1] << 8) | (int) scratchpad[0]) * 10 / 16; |
19 | } else { |
20 | temp = (((int) scratchpad[1] << 8) | (int) scratchpad[0]) * 10 / 16; |
21 | }
|
22 | }
|
... ist in meinen Augen hauptsächlich eines: übermässig kompliziert und unnötig aufgeblasen. Warum? Weil genau diese 2-Teilung 'zusammensetzen der Bytes' und 'nachbearbeitung des daraus entstehenden 16-Bit Wertes' achtlos und sinnloserweise über Bord geworfen wurde. Daraus resultiert dann die scheinbare Komplexität.
An sich ist auch die ganze DS18B20 lib für den Anfang nicht nötig. Wenn man eine 1Wire lib hat, dann reicht: Reset Skip Rom Start Warten 1s Reset Skip Rom Read Byte 1 Read Byte 2 Und schon hat man seine 2 Temp. Bytes. Natürlich, kein CRC, nur ein Sensor erlaubt usw. usw. Trotzdem reicht es erstmal und man wird nicht durch den ganzen Scratchpad-Code verwirrt. gruß cyblord
cyblord ---- schrieb: > Und schon hat man seine 2 Temp. Bytes. Natürlich, kein CRC, nur ein > Sensor erlaubt usw. usw. Trotzdem reicht es erstmal und man wird nicht > durch den ganzen Scratchpad-Code verwirrt. Ja, kann man machen. Im verlinkten Code wird das Scratchpad ja nur deshalb zur Gänze ausgelesen, damit man die erweiterte Genauigkeit benutzen kann. Wobei ich in den meisten Fällen sowieso nicht viel davon halte, eine Temperatur (zb Raumtemperatur) in Zehntelgrad anzugeben. Denn die Zehntel stimmen sowieso nicht für den Raum als Ganzes gesehen. Gerade bei Temperaturen wird so dermassen viel Schindluder mit Nachkommastellen getrieben, das wird eigentlich nur noch von Wahlprognosen übertroffen. Der kleinste Lufthauch (durch eine sich schliessende Tür) und die Temperatur im Raum 'sinkt' um 3 Zehntel Grad, wenn der DS 'günstig' montiert ist. Etwas das ich nicht sinnvoll messen kann, will ich auch nicht auf der Anzeige haben. Für einen DS18B20 reicht ein einfaches
1 | ....
|
2 | // ... Scratchpad auslesen, wie im Beispiel
|
3 | for (temp = 0; temp < 9; temp++) |
4 | scratchpad[temp] = w1_byte_rd(); // Scratchpad füllen (9 Bytes) |
5 | |
6 | // Bytes zusammensetzen
|
7 | int16_t Temperatur = (int16_t)( ( scratchpad[1] << 8) | scratchpad[0] ); |
8 | |
9 | // in Grad umrechnen
|
10 | Temperatur = Temperatur / 16; |
meiner Meinung nach aus. Will man unbedingt Zehntelgrad haben, dann eben
1 | ...
|
2 | // in Grad umrechnen
|
3 | Temperatur = Temperatur * 10 / 16; |
4 | ...
|
und entsprechender Anpassung der Ausgabe.
:
Bearbeitet durch User
Ich wollte dich wirklich nicht beleidigen cyblord. Falls ich das doch getan habe tut es mir leid. Das was ich geschrieben habe ("und zu cyblord, ich will mit einem Temperatursensor Temperaturen messen. :P") war als kleinen Scherz gedacht, ich wollte dich damit keinenfalls beleidigen.
Mal eine dumme Frage zur Auflösung: Wenn ich z.B. nur 10 statt 12 bit Auflösung haben will, sind laut Datenblatt bit 1 und 0 undefined. Bedeutet das, daß ich dann bei der Temperaturberechnung diese bits vorher auf 0 setzen muß? Oder den gelesenen Wert um 2 nach rechts shiften und das Ergebnis einfach durch 4 statt 16 teilen?
Stefan Untner schrieb: > und zu cyblord, ich will mit einem Temperatursensor Temperaturen messen. Das macht der DS18B20 fast von selbst. Dein Problem ist das Auslesen der Messdaten und die formatierte Anzeige. ;-)
Hortel schrieb: > Mal eine dumme Frage zur Auflösung: Wenn ich z.B. nur 10 statt 12 bit > Auflösung haben will, sind laut Datenblatt bit 1 und 0 undefined. > Bedeutet das, daß ich dann bei der Temperaturberechnung diese bits > vorher auf 0 setzen muß? Oder den gelesenen Wert um 2 nach rechts > shiften und das Ergebnis einfach durch 4 statt 16 teilen? Weder, noch. Durch die Division durch 16 fallen die Bits dann sowieso weg, sodass sie im Endergebnis nicht aufscheinen. Interessant ist diese Information nur dann, wenn du den Teil 'Grad = Division durch 16' etwas komplexer gestaltest, so dass du eben den bei der Division entstehenden Rest auch noch auswertest, so dass du auf Zehntel Grad kommen könntest. Ich sach mal so. Wenn du eine gewisse Anzahl an Flaschen hast und auf eine Palette genau 10 Flaschen passen, dann dividierst du die Anzahl der Flaschen durch 10. Soweit so gut. Willst du nur wissen, wieviele Paletten du brauchst (= Anzahl an ganzen Grad), dann ist es wurscht, ob die Einerstelle deiner Anzahl an Flaschen korrekt ist oder nicht. Ob die korrekte Anzahl an Flaschen 92 oder 96 ist, spielt keine Roll, du brauchst in jedem Fall 10 Paletten (x / 10) + 1. Die Einerstelle wird erst dann interessant, wenn du wissen willst, wie 'voll' die letzte Palette ist, ändert aber nichts daran, dass du 10 Paletten brauchst.
:
Bearbeitet durch User
Jetzt bin ich aber verunsichert: Wenn ich z.B. aus Zeitgründen eine 10 bit Auflösung einstelle, sind laut Datenblatt die beiden LSB undefiniert. Ich interpretiere das so, daß die LSB sowohl 0 als auch 1 sein können; unabhängig vom Meßwert/Temperatur. Wenn ich aber jetzt trotzdem durch 16 teile, werte ich doch diese beiden bits mit aus oder nicht? Ich hätte bzw. habe bis jetzt auch gedacht, daß ich die undefinerten bits nach rechts rausshifte und den Teiler dann entsprechend der Wertigkeit setze: 12 bit: Teilen durch 16 11 bit: 1 rechts shiften und durch 8 10 bit: 2 rechts shiften und durch 4 9 bit: 3 rechts shiften und durch 2
Lutz schrieb:
...werte ich doch diese beiden bits mit aus oder nicht?...
Nein:
Bei der Integer-Division ergibt doch
1/16=0, ... , 15/16=0,
16/16=1, 17/16=1, ...
Da spielen die untersten 4 Bit keine Rolle.
Auch, wenn ich vorher den Wert in einer float-Variablen anstatt in einem int16_t speichere?
1 | // Bytes zusammensetzen
|
2 | float Temperatur = (float)( ( scratchpad[1] << 8) | scratchpad[0] ); |
3 | |
4 | // in Grad umrechnen
|
5 | Temperatur = Temperatur / 16; |
Mit float (Programmgröße, Laufzeit) ist zwar nicht so schön, aber wenn man es sich leisten kann ...
Lutz schrieb: > Auch, wenn ich vorher den Wert in einer float-Variablen anstatt in einem > int16_t speichere? Dann natürlich nicht. (Und darum ist es immer gut, konkreten Code zu posten. Inklusive Datentypen der beteiligten Variablen) Das tiefer liegende 'Problem', besteht darin, dass es dem Compiler piep-schnurz egal ist, welchem Datentyp du ein Ergebnis zuweist. Wenn es darum geht, zu bestimmen wie eine Operation durchzuführen ist, dann gelten einzige und alleine die Datentypen der beteilgten Operanden. In
1 | int16_t temp; |
2 | |
3 | temp = ..... Byte zusammensetzen |
4 | temp = temp / 16; |
gibt es die Berechnung
1 | ... temp / 16; |
temp ist ein Integer. 16 ist ein Integer. Also wird die Division als Integer-Division durchgeführt. Dass dieses Ergebnis danach unter Umständen einem float zugewiesen wird
1 | int16_t temp; |
2 | float Temperatur; |
3 | |
4 | temp = ..... Byte zusammensetzen |
5 | Temperatur = temp / 16; |
ist für die Division unerheblich. Erst das Ergebnis der Division wird ja
zugewiesen und daher wird auch erst dieses Ergebnis in einen float
umgewandelt.
Bei einer Integer Division entstehen aber keine Kommastellen. Es hat sie
nie gegeben, daher tauchen sie auch im Ergebnis nicht auf.
Im obigen Code war bisher immer nur von Integer-Operationen die Rede.
float kam da überhaupt noch nicht vor. Das hier
>
1 | > // Bytes zusammensetzen |
2 | > float Temperatur = (float)( ( scratchpad[1] << 8) | scratchpad[0] ); |
3 | >
|
4 | > // in Grad umrechnen |
5 | > Temperatur = Temperatur / 16; |
6 | >
|
verändert natürlich alles, da in
1 | ... Temperatur / 16; |
Temperatur bereits ein float ist. Daher wird diese Division als Gleitkomma-Division durchgeführt. Und die liefert selbstverständlich Nachkommastellen. Wenn also in Temperatur schon die 'undefined bits' mit drinnen waren, dann tauchen auch im Ergebnis davon abhängige 'undefined'-Anteile auf. Ergo: damit du dir hier nichts einhandelst, solltest du die Bits aus dem Status 'undefined' heraus holen und gezielt zb auf 0 setzen. Oder die Berechnung entsprechend modifizieren, so dass zuerst die undefined BIts 'rechts rausfallen' und dann eben durch etwas entsprechend kleineres dividieren. > Mit float (Programmgröße, Laufzeit) ist zwar nicht so schön, > aber wenn man es sich leisten kann .. Sagtest du nicht: > Jetzt bin ich aber verunsichert: Wenn ich z.B. aus Zeitgründen > eine 10 bit Auflösung einstelle Ja was denn nun? Aus Zeitgründen eine 10 Bit Auflösung, aber eine Floating Point Division ist kein Zeitproblem?
:
Bearbeitet durch User
Puh, da bin ich ja beruhigt. Natürlich hast du recht. Mein Fehler; bei konkret gepostetem Code hätten wir nicht aneinander vorbeigetippt. Das Beispiel float und Laufzeit paßt prinzipiell nicht gut zusammen, ich weiß. Aber es war halt nur ein (schlechtes) Beispiel. Spitzfindig betrachtet könnte ich aber auch behaupten, daß der Zeitoverhead einer float-Berechnung bei diversen MHz um ebenfalls diverse Zehnerpotenzen niedriger ist als die "gewonnene" Conversiontime des Sensors (187.5 ms bei 10 bit zu 700 ms bei 12 bit; also 512.5 ms Zeitgewinn minus ein paar µs mehr Laufzeit) ... Und so ein gaaaaaaanz bischen hatte ich auch das im Hinterkopf, was nur für 12 bit Auflösung gilt: Karl Heinz schrieb: > Brat schrieb: >> Roland ... schrieb: >> >>> Digitalwert * __0,0625__ = T [°C] >> >> Funktioniert bei negativen Temperaturen nicht. > ... > Setzt man aber Floating Point Operationen ein, dann kommt da auch das > richtige Ergebnis raus.
Ich geb dir in allem Recht Lutz. Einen Punkt möchte ich noch ins Spiel bringen, weil er gerne übersehen wird. > ist als die "gewonnene" Conversiontime des Sensors > (187.5 ms bei 10 bit zu 700 ms bei 12 bit; also 512.5 ms Zeitgewinn Der Sensor schreibt mir allerdings auch nicht vor, dass ich exakt nach 'bis zu 700ms nach Start der Conversion' mir das Ergebnis abholen muss. Ich darf mir da beliebig viel Zeit lassen. Zb kann ich auch diese Reihenfolge wählen
1 | Schleife |
2 | { |
3 | Ergebnis abholen |
4 | nächste Wandlung starten |
5 | |
6 | Ergebnis aufbereiten, umrechnen und anzeigen |
7 | irgendwas anderes machen |
8 | } |
so dass die letzten beiden Programmpunkte in die Zeit fallen, die der Sensor zum arbeiten braucht. Wenn die beiden Punkte eine erkleckliche Zeit beanspruchen, dann wirken sich die erzwungenen 700ms praktisch gar nicht mehr aus. In meiner Heizungssteuerung mach ich das so. Da messe ich nur alle 10 Sekunden. Mehr macht nicht Sinn, da sich eine Raumtemperatur eh nicht so schnell ändert. Die 10 Sekunden werden mit einem Timer gemacht. Durch den Timer angestossen hole ich mir das letzte Ergebnis und starte sofort den DS neu. Der hat dann 10 Sekunden Zeit, in aller Ruhe zu wandeln, bis ich mir das Ergebnis dieser Wandlung abhole und gleich wieder die nächste starte.
Mein Taschenrechner spinnt: 0xFFF8 / 16 (0x10) = 4095 = 0xFFF irgendwie kapiert der die negative Zahl nicht. wenn ich die Bits toggle komme ich in den positiven Bereich, aber mit den 4 letzten Bits klappt das nicht ;-(
Lutz schrieb: > Mit float (Programmgröße, Laufzeit) ist zwar nicht so schön, aber wenn > man es sich leisten kann ... Und welchen Vorteil versprichst du dir davon? Deine Temperatur wird sich bei einem DS18B20 immer im Bereich -55 ... +1xx°C bewegen. Der Genauigkeitsverlust bei Float zugunsten einer höheren Dynamik gegenüber einem Ganzzahlformat bringt dir also überhaupt nichts.
Ist ja schön, aber ich muss es ja irgendwie aufs LCD bringen, dazu muss ich eben die Zahlen handeln. Nützt ja nichts eine Temperaturmessung anzustoßen und das Ergebnis im schwarz/grauen Gehäuse zu verstecken ;-) Dim Wert as Integer rem -32768,0 bis +32767,0 Das ist schon klar Auch *100/16 (oder *25/4) dann sind es 100derstel Grad, Aber jetzt muss ich irgendwie mit den negativen Zahlen klar kommen. Und da ich nicht Informatik studiert habe und es schon über 20 Jahre her ist und .... Ich nehme Bascom, C ist mir zu anstrengend Zitat: Deine Temperatur wird sich bei einem DS18B20 immer im Bereich -55 ... +1xx°C bewegen. ist bekannt, niedrigere und hörere Temp kommen bei mir zu Hause nicht vor Zitat: Der Genauigkeitsverlust bei Float zugunsten einer höheren Dynamik gegenüber einem Ganzzahlformat bringt dir also überhaupt nichts. Was bedeutet die Dynamik bei Float und wie komme ich auf die Zahl?
:
Bearbeitet durch User
Jens S. schrieb: > Jetzt muss ich erst mal die Dynamic von Float googeln.... Bei einer 32-Bit Float Zahl im IEEE Format gehen 8 Bit für den Exponent flöten, d.h. für den Zahlenwert bleiben dir noch 24 Bit incl. Vorzeichen. Bei einer 32-Bit Integer hättest du 8 Bit mehr, da es dir bei Temperaturangaben wenig nützt wenn du um 0 rum eine höhere Auflösung zur Verfügung hättest. http://de.wikipedia.org/wiki/Gleitkommazahl#Exponent Und nicht vergessen: Floatzahlen sind nur eine Teilmenge der Rationalen Zahlen http://de.wikipedia.org/wiki/Rationale_Zahl Jens S. schrieb: > Und da ich nicht Informatik studiert habe und es schon über 20 Jahre her > ist und .... Wenn der Sinn eines Informatikstudiums wäre, richtig mit negativen Zahlen umzugehen, wäre das einfach traurig. Dafür gibt es in Schulen die Unterstufe ;-)
Ich wusste gar nicht das man jetzt an Grundschulen (Unterstufe) Informatik hat, muss mal meinen Sohn fragen. Ich habe Sek II, aber nicht in Informatik Wie wäre es denn hiermit: Negative Zahl vom DS18B20: (0xFE6F ExOR 0xFFFF) + 0x0001 = 0x0191 Danach ist es das selbe wie mit positiven Zahlen Wozu as LONG ? ich dachte der Temperaturbereich geht nur bis 125°C
:
Bearbeitet durch User
Jens S. schrieb: > Wozu as LONG ? Um die Float Variable einer gleich großen Integer Variablen gegenüber zu stellen. Und die Zeiten von 6-Byte Float-Formaten sind IMHO vorbei. Jens S. schrieb: > an Grundschulen (Unterstufe) Informatik Nicht Grundschule sondern Unterstufe (= Sekundarstufe I) http://de.wikipedia.org/wiki/Unterstufe und nicht Informatik, sondern negative Zahlen ;-)
Ich muss feststellen vor 20-30 Jahren hat man durch aus mit negativen Zahlen im Dezimalsystem gerechnet! Auch Zehnerpotenz ist ein Begriff, wie Primzahl und Bruchrechnung Nur bestand der "Informatik-Unterricht" aus 5x VC-20 und einem C64 und zwei Datasetten ! Sowie Monitoren die man besser als Röhrenfernseher bezeichnet hätte. Dazu gab es ein Buch von Data-Becker... Aber lassen wir das, kann ja auch nichts dafür, das die damaligen Lehrkräfte ihr Wissen 1:1 aus solchen Büchern lehrten und das noch nicht auf dem Lehrplan stand sondern freiwillige Sonder-AG war! Ja, ich weiß, die vom Gymnasium haben schon immer auf die anderen herab geschaut.... Aber Berufsausbildung und Berufserfahrung ist gleichwertig!
:
Bearbeitet durch User
Ohne mich wieder im Bildungssystem zu verlieren, folgender Code konnte ich erfolgreich simulieren, der Sensor ist noch nicht da.
1 | DIM Wert_aus_ds1820 As Integer |
2 | DIM Temperatur As Singel |
3 | DIM Sign As Bit |
4 | Config Lcd ... bla bla bla |
5 | |
6 | Do |
7 | Sensor aufwecken, und Wert_aus_ds1820 speichern |
8 | Gosub auswerten |
9 | bla, bla,bla |
10 | Loop |
11 | End |
12 | |
13 | |
14 | auswerten: |
15 | Rem Wert_aus_ds1820 = &B1111_1100_1001_0000 ' Beispielcode |
16 | ' Auswertung für DS18B20, nicht für DS1820, nicht für DS18S20 ! |
17 | Sign = 0 ' 0 = + | 1 = negative Zahl |
18 | If Wert_aus_ds1820 = 0 Then |
19 | ' -- >= Null Grad |
20 | Temperatur = Wert_aus_ds1820 |
21 | Else |
22 | If Wert_aus_ds1820.15 <> 0 Then ' negativ? |
23 | Sign = 1 |
24 | For I = 0 To 15 'ExOR 0xFFFF |
25 | Toggle Wert_aus_ds1820.i |
26 | Next |
27 | Incr Wert_aus_ds1820 ' +1 |
28 | End If |
29 | Temperatur = Wert_aus_ds1820 / 16 ' -- >= positiv |
30 | End If |
31 | Locate 2 , 1 |
32 | If Sign = 1 Then : Lcd "-" : Else : Lcd "+" : End If |
33 | Lcd Temperatur |
wie gesagt, der DS18B20 ist noch in der Post.
:
Bearbeitet durch User
Oder ganz kurz:
1 | auswerten: |
2 | |
3 | Temperatur = Wert_aus_ds1820 / 16 |
4 | Text = Str(temperatur) : Replacechars Text , "." , "," |
5 | Locate 2 , 1 : Lcd Text : Return |
6 | |
7 | Return |
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.