DS18S20 Temperaturwerte in signed integer wandeln

OP #2886074
Lesenswert?

Hallo,

ich wollte den Temperaturwert eines DS18S20, zur weiteren 
Datenübertragung,in einen signed integer (int16_t) umwandeln. Dafür habe 
ich mir folgenden Code geschrieben:
1
void rechne(uint8_t msb, uint8_t lsb, uint8_t count_remain){
2
  ausgabe_u(msb);
3
  ausgabe_u(lsb);
4
  ausgabe_u(count_remain);
5
  //integer
6
  int16_t tempi = msb * 0x100 + lsb;
7
  ausgabe_i(tempi);
8
  tempi /= 2;
9
  ausgabe_i(tempi);
10
  tempi *= 100;
11
  ausgabe_i(tempi);
12
  tempi -= 25;
13
  ausgabe_i(tempi);
14
  ausgabe_i((count_per_c * 100 - count_remain * 100) / count_per_c);
15
  tempi += (count_per_c * 100 - count_remain * 100) / count_per_c;
16
  ausgabe_i(tempi);
17
  uart_puts("\r\n");
18
}

Zur Kontrolle habe ich mir die Werte über die USART ausgegeben lassen.
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <avr/pgmspace.h>
6

7
#define BAUD     38400
8
#include <util/setbaud.h> 
9
#include "uart.c"
10

11
#define count_per_c    0x10
12

13
void ausgabe_i(int16_t wert){
14
  char buf[7];
15
  itoa(wert, &buf[0], 10);
16
  uart_puts(&buf[0]);
17
  uart_putc(';');
18
}
19

20
void ausgabe_u(uint8_t wert){
21
  char buf[4];
22
  utoa(wert, &buf[0], 10);
23
  uart_puts(&buf[0]);
24
  uart_putc(';');
25
}
26

27
int main(void){
28
  uart_init();
29
  uart_puts("Start\r\n");
30
  for(int16_t temp = 0xFF92; temp < 0x00AB; temp++){
31
    for(uint8_t count_remain = 0x00; count_remain < 0x10; count_remain++){ 
32
      rechne((uint8_t) (temp >> 8), (uint8_t) temp, 0x0F - count_remain);
33
    }
34
  }
35
    
36
  while(1){                              // leere Endlosschleife
37
  }
38
}
Anbei das Logfile. Dort sieht man das sehr viele Werte stimmen aber 
ebend nicht alle.
Nach jetzt schon langem Grübeln, wo ich den Bock geschossen habe komme 
ich zu keinem Ergebniss. Vieleicht fällt euch ja dazu was ein.

Gruß Rene
Angehängte Dateien:
Moderator Persönliche Seite #2886121
Lesenswert?

Rene Zimmermann schrieb:
> Anbei das Logfile.

In dieser Datenwurst findet sich doch keiner zurecht.  Welches soll
denn die Stelle sein, wo es nicht stimmt?

Hier ist eine DS18B20-Funktion, die ich mal benutzt habe:
1
double
2
Read_Temperature(void)
3
{
4
  uint8_t get[9];
5
  uint8_t temp_lsb,temp_msb;
6
  uint8_t k;
7

8
  ow_reset();
9

10
  ow_write_byte(0xCC); //Skip ROM
11
  ow_write_byte(0x44); // Start Conversion
12

13
  _delay_ms(750);
14

15
  ow_reset();
16

17
  ow_write_byte(0xCC); // Skip ROM
18
  ow_write_byte(0xBE); // Read Scratch Pad
19

20
#ifdef DEBUG
21
  PRINT("1wire: ScratchPAD DATA = ");
22
#endif
23
  for (k = 0; k < 9; k++){
24
    get[k] = ow_read_byte();
25
#ifdef DEBUG
26
    PRINTF("%02X ", get[k]);
27
#endif
28
  }
29
  k = ow_checkcrc(get, 9);
30
#ifdef DEBUG
31
  PRINTF(" (CRC %s)\r\n", k == 0? "OK": "FAIL");
32
#endif
33
  if (k != 0)
34
    return 0;
35

36
  temp_msb = get[1]; // Sign byte + lsbit
37
  temp_lsb = get[0]; // Temp data plus lsb
38
  int i = (temp_msb << 8) | temp_lsb;
39

40
  return i / 16.0;
41
}

(Lizenbedingungen für Weiternutzung: "Beer-Ware License")
#2886159
Lesenswert?

Karlheinz schrieb:
> Rene Zimmermann schrieb:
>>   tempi /= 2;
>>   ausgabe_i(tempi);
>>   tempi *= 100;
>>   ausgabe_i(tempi);
>
>
> vertausche die beiden Operationen, multipliziere zuerst mit 100 und
> teile dann durch 2 !!! dann gehen keine (wichtigen) Stellen verloren

Auch das ist ok.
Er muss zuerst das LSB loswerden (laut Maxim Doku). Die *100 sind nur 
der Festkommaarithmetik geschuldet, mit der dann die Nachkommastellen 
aus COUNT_REMAIN einrechnen will.
OP #2886164
Lesenswert?

>In dieser Datenwurst findet sich doch keiner zurecht.

Ja war vieleicht etwas viel. ;-)

Das Auslesen der Sensoren ist nicht mein Problem. Ich will den Wert des 
MSB, LSB und count_remain Registers zu einem signed Integer verrechnen. 
Um zu prüfen ob es geht habe ich einfach alle Werte für die 3 Register 
durchrechnen lassen und mitgeschnitten. Deshalb auch so eine grosse 
Datei.

Wenn man das für z.B. MSB=0x00, LSB=0x01 und count_remain=0x05 rechnet 
kommt 0.94 Grad Celsius heraus. Nur leider nicht bei meiner Routine.

Gruß Rene
OP #2886260
Lesenswert?

Oh man,

so was blödes, ich suche einen Fehler wo es keinen gibt. Na super.

Hat noch einer eine Idee zu dem Rundungsfehler? Nicht das es mich stört 
aber korrekt ist es ja nicht.

Dann schreibe ich jetzt mal den Code für die Ausgabe in Grad Celsius mit 
zwei Nachkommastellen. Damit ich auch wieder was zum Fehler suchen habe. 
;-)

Vielen Dank
Rene
#2886263
Lesenswert?

Rene Zimmermann schrieb:
> Oh man,
>
> so was blödes, ich suche einen Fehler wo es keinen gibt. Na super.
>
> Hat noch einer eine Idee zu dem Rundungsfehler? Nicht das es mich stört
> aber korrekt ist es ja nicht.

vergiss ihn.
Die Temperatur stimmt sowieso nicht auf 1/100 Grad genau.

Es ist eine Sache einen Wert auf 4 Nachkommastellen auszugeben. Es ist 
aber eine ganz andere Sache, welche von den 4 Nachkommastellen reine 
Phantasie sind und welche nicht. Nur weil in einer Rechnung 4 
Nachkommastellen rauskommen, heißt das ja nicht, dass das physikalische 
System deswegen exakt diese Wert hat. Den WOhnraum zeigst du mir mal, 
bei dem die komplette Luftmasse im Raum auf 1/100 Grad genau diesen 
einen Wert hat.
Moderator Persönliche Seite #2886272
Lesenswert?

Wenn du zwei Nachkommastellen haben willst, dann nimm einen SHT-21
bzw. seinen nicht-feuchtemessenden kleinen Bruder STS-21.  Die
können auch keinen 10 mK absolut genau messen, aber bei denen passt
die 10-mK-Stelle dann zumindest noch in der Tendenz.  (Hier wurde
neulich noch ein anderer Sensor genannt, der noch einen Tick genauer
ist, aber den Typ habe ich vergessen.)

Bei den billigeren Sensoren ist oft schon die 100-mK-Stelle nur noch
Rauschen.
OP #2886293
Lesenswert?

>Wenn du zwei Nachkommastellen haben willst, dann nimm einen SHT-21
>bzw. seinen nicht-feuchtemessenden kleinen Bruder STS-21.

Nee, das ist nicht notwendig. Wir reden hier über die Wassertemperatur 
in meinem Pool und der Poolheizung sowie der Umgebungsluft. Das sind 
Daten die ich per Funk zu meinem Server schicke. Somit weiss ich immer 
was los ist und die Steuerung wenn sie die Pumpe zu schalten hat. Mir 
ging es hier hauptsächlich darum nur 2 Bytes zu übertragen. Vorher habe 
ich einfach 3 x 9 Bytes SCRATCHPAD + 2 Bytes Checksumme gesendet. Jetzt 
reichen 3 x 2 Bytes + 2 Bytes Checksumme.

Gruß Rene
#2886299
Lesenswert?

Rene Zimmermann schrieb:

> Nee, das ist nicht notwendig. Wir reden hier über die Wassertemperatur
> in meinem Pool und der Poolheizung sowie der Umgebungsluft.

In dem Fall würde ich mir noch nicht mal Gedanken um die Zehntelgrad 
machen. Die 0.5°, die du standardmässig kriegst sind nämlich schon 
falsch.

Also jetzt nicht 'falsch' im Sinne von 'der Sensor liefert falsche 
Werte'. Sondern falsch im Sinne von 'das Wasser' im Pool hat 23.5°C. 
Denn das hat es ganz sicher nicht überall.
OP #2886316
Lesenswert?

>In dem Fall würde ich mir noch nicht mal Gedanken um die Zehntelgrad
>machen. Die 0.5°, die du standardmässig kriegst sind nämlich schon
>falsch.

Grundsätzlich muß ich dir da recht geben. Nur ist das bei uns in der 
Firma schon so eine Art Kult. Jeder darf im Sommer mal schauen was die 
Wassertemperatur macht. Ihr glaubt gar nicht was da los ist. Da ich mir 
aber keine Daten aus den Fingern saugen will nehme ich mal 1/10 Grad. 
Für die Technik kann ich ja nichts. ;-)

Gruß Rene

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren