Forum: Mikrocontroller und Digitale Elektronik DS18B20 Temperaturberechnung


von Stefan U. (unti)


Lesenswert?

Hallo

Weiß zufällig jemand nach welcher Formel die Temperatur beim DS18B20 
berechnet wird.

MfG Unti

von (prx) A. K. (prx)


Lesenswert?

Wert/16

von Stefan U. (unti)


Lesenswert?

?????????????????

von Roland .. (rowland)


Lesenswert?

Digitalwert * 0,0625 = T [°C]

von Stefan U. (unti)


Lesenswert?

Achso :)

Danke

von Brat (Gast)


Lesenswert?

Roland ... schrieb:

> Digitalwert * 0,0625 = T [°C]

Funktioniert bei negativen Temperaturen nicht.

Ansonsten: http://datasheets.maximintegrated.com/en/ds/DS18B20.pdf

von (prx) A. K. (prx)


Lesenswert?

Brat schrieb:
>> Digitalwert * 0,0625 = T [°C]
>
> Funktioniert bei negativen Temperaturen nicht.

Weshalb nicht?

von Stefan U. (unti)


Lesenswert?

In dem Datenblatt steht nichts wie man die Temperatur berechnet ==> 
KEINE FORMEL !!!!!!!!!!

von Karl H. (kbuchegg)


Lesenswert?

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.

von Brat (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Angehängte Dateien:

Lesenswert?

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
von Peter D. (peda)


Lesenswert?

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"

von Karl H. (kbuchegg)


Lesenswert?

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.

von Brat (Gast)


Lesenswert?

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 :)

von Karl H. (kbuchegg)


Lesenswert?

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
von Stefan Untner (Gast)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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
von Mirki (Gast)


Lesenswert?

Wert durch 16 teilen....wurde doch schon zweimal erwähnt...

von Cyblord -. (cyblord)


Lesenswert?

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.

von Wolfgang-G (Gast)


Lesenswert?

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.

von Cyblord -. (cyblord)


Lesenswert?

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

von Gerry L. (Gast)


Lesenswert?

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

von Stefan U. (unti)


Lesenswert?

Meine Frage wäre da noch was genau ist bzw. macht int16_t

von Karl H. (kbuchegg)


Lesenswert?

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
von Stefan U. (unti)


Lesenswert?

danke
und was heist dann (int16_t)0xFFF8 = -8

von Karl H. (kbuchegg)


Lesenswert?

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
von Hmm.. (Gast)


Lesenswert?

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!

von Karl H. (kbuchegg)


Lesenswert?

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
von Cyblord -. (cyblord)


Lesenswert?

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
von Stefan U. (unti)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Cyblord -. (cyblord)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Cyblord -. (cyblord)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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
von Stefan U. (unti)


Lesenswert?

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.

von Hortel (Gast)


Lesenswert?

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?

von Michael (Gast)


Lesenswert?

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. ;-)

von Karl H. (kbuchegg)


Lesenswert?

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
von Lutz (Gast)


Lesenswert?

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

von Josef D. (jogedua)


Lesenswert?

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.

von Lutz (Gast)


Lesenswert?

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 ...

von Karl H. (kbuchegg)


Lesenswert?

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
von Lutz (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Jens S. (jens_s56)


Lesenswert?

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 ;-(

von Mike (Gast)


Lesenswert?

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.

von Jens S. (jens_s56)


Lesenswert?

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
von Wolfgang A. (Gast)


Lesenswert?

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 ;-)

von Jens S. (jens_s56)


Lesenswert?

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
von Wolfgang A. (Gast)


Lesenswert?

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 ;-)

von Jens S. (jens_s56)


Lesenswert?

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
von Jens S. (jens_s56)


Lesenswert?

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
von Jens S. (jens_s56)


Lesenswert?

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
Noch kein Account? Hier anmelden.