Edler weg der Umrechnung

Gast #6748522
Lesenswert?

Hi,

ich habe einen DS18B20 1-Wire Temperatursensor.
und würde hier gerne die Temperatur Umrechnen.
1
// Auslesen
2
      lsb = onewire_Read();
3
      msb = onewire_Read();
4
      temperature = (msb<<8)+lsb;
5
// Umrechnen
6

7
// 1. Möglichkeit, leider ohne Nachkommastellen
8
      temperature = (temperature >> 4);
9

10
//2. Möglichkeit
11
// (Gibt nen Integerwert zurück und die zwei Nachkommastellen sind dabei)
12
      temperature *= 625;  //(0.0625 C je Bit);
13
      temperature /= 100;

Gibt es hier keine andere Lösung (kein float)?


Vielen Dank
Angehängte Dateien:
#6748534
Lesenswert?

Die 4 LSBs sind je 1/16°C wert. Das ist bereits der Nachkommaanteil, 
aber binär. Blöderweise lässt sich der nur krumm als 
Dezimal-Nachkommateil abbilden.

Wenn du die Division am Ende vermeiden willst, greife dir doch die 4 
LSBs ab und stecke die in eine Lookuptabelle.

Für eine Anzeige in Dezimal-Vorkomma als Text muss der Vorkommaanteil 
übrigens in der printf oder sprintf (oder sonst wie) sowieso umgerechnet 
werden.

Vielleicht kommst du mit fraktionalen Zahlen hin, wo dann das Ergebnis 
ein Integer in 1/100 °C-Schritten ist.

mfg mf
Gast #6748535
Lesenswert?

Ein Profi nimmt die Lösung, die seine Anforderungen am besten erfüllt.
Kommt dein Rechner mit seiner Rechenleistung an seine Grenzen, dann ist 
die Lösung 1. die richtige. Brauchst du höhere Genauigkeit und dir 
stehen mehr freie Rechenkapazitäten zur Verfügung, dann die Lösung 2.
Was Float Zahlen betrifft: Ist dein Rechner ein 8Bit AVR und hat so um 
die 500 Takte frei zwischen zwei Aufgaben die er berechnet, dann geht 
auch float.

Gruß,
#6748558
Lesenswert?

Simon schrieb:
> Gibt es hier keine andere Lösung (kein float)?

Was genau ist denn eigentlich das Problem?

Du erhältst doch eine Ganzzahl zurück, die linear aufsteigende 
Bitwertigkeiten hat. Ein Float macht doch bei dieser Anwendung überhaupt 
keinen Sinn.

Oder übersiehst du gerade das naheliegende?
1
int16_t temperature; // signed
2
// Wert ermitteln
3
float f = temperature;
4
f /= 16;
5
// f passt jetzt sogar für printf usw.

(Wenn du unbedingt den Float haben willst.)
#6748577
Lesenswert?

Mit fraktionalen Zahlen, hier:
1
// Auslesen
2
lsb = onewire_Read();
3
msb = onewire_Read();
4
temperature = (msb<<8)+lsb;
5

6
// fraktionale Q30_2 Umrechnungskonstante
7
#define SENSOR_TO_1_100DEGC ((int32_t)((0.0625/0.010)*((float)(1ul << 2u))))
8

9
int32_t Temp1_100;
10

11
// temperature ist Q12_4, also Temp1_100 Q28_4
12
Temp1_100  = (int32_t)temperature;
13

14
// Q28_4 mal Q30_2 wäre Q58_6, im Ergebnis Q26_6
15
Temp1_100 *= SENSOR_TO_1_100DEGC;
16

17
// schieben um 6 um den Nachkommaanteil wegzuschneiden und 1/100 degC zu bekommen
18
Temp1_100 >>= 6u;

Wer einen Fehler findet, darf ihn gern verbessern ^^

mfg mf

PS. Sehe gerade, dass die Rechnung auch in 16bit rein passen würde, wenn 
man nur positive Temperaturen hat. Der Achim muss sich also warm 
anziehen ;)
Gast #6748586
Lesenswert?

Simon schrieb:
> Hi,
>
> ich habe einen DS18B20 1-Wire Temperatursensor.
> und würde hier gerne die Temperatur Umrechnen.
> // Auslesen
>       lsb = onewire_Read();
>       msb = onewire_Read();
>       temperature = (msb<<8)+lsb;
> // Umrechnen
> // 1. Möglichkeit, leider ohne Nachkommastellen
>       temperature = (temperature >> 4);
> //2. Möglichkeit
> // (Gibt nen Integerwert zurück und die zwei Nachkommastellen sind
> dabei)
>       temperature *= 625;  //(0.0625 C je Bit);
>       temperature /= 100;
>
> Gibt es hier keine andere Lösung (kein float)?
>
> Vielen Dank

Falls du den Wert in Berechnungen benutzt oder nur irgendwo anders 
hinüberträgst, kannst du die Berechnung bzw das Übertragungsformat in 
Festkomma gestalten, so wie es Achim angedeutet hat. Konstanten kann man 
zB ja so anpassen, dass die Zahlengleichung mit 1/16°C umgehen kann. Ich 
würde mir da noch ein paar Typedefs als Hilfestellung anlegen, sowas wie
[c]typedef uint32_t uq26_6;[\c]
Wenn du es nur anzeigen möchtest, ist eine Umrechung auf Dezimal mit 
zwei Nachkommastellen, wie sie von Achim optimiert wurde, doch 
eigentlich optimal, oder?
Gast #6748606
Lesenswert?

Warum muss die Temperatur überhaupt umgerechnet werden?
Und wenn ja, in was?

Wenn die Temperatur in eine PID rein muss, um damit etwas zu regeln, 
dann kannst du doch auch dort in 16tel Grad rechnen.
Und für eine Ausgabe auf ein Display reicht ein sekündliches Update. Da 
kann man auch Floats nehmen.

Also, warum soll auf was umgerechnet werden?

Achja, beim meinen LM73 nehme ich nur die 1/4 Grad, und die schwanken 
schon ordentlich. Die Genauigkeit mit 16tel Grad würde ich ignorieren. 
So genau sind die Sensoren nicht.
Persönliche Seite #6748671
Lesenswert?

Wolfgang schrieb:
> Du schmeißt Auflösung und Genauigkeit durcheinander. Auflösung ist
> manchmal wichtiger als Genauigkeit - hängt von der Anwendung ab.

Wobei die relative Genauigkeit sicher höher als die absolute ist. Eine 
hohe Auflösung kann hierbei von Vorteil sein. Ein Regler benötigt 
beispielsweise keine Absoluttemperatur sonder eher 
Temperaturdifferenzen.
#6748691
Lesenswert?

Hab ich schon 2011 gemacht:
Beitrag "DS18S20 - extended resolution bei Temperaturen um 0°C"
1
//Idea and code (C) by eProfi
2
//for better understanding  look at the table in
3
//www.mikrocontroller.net/topic/202928#1999183
4
//output format:
5
//  1      2      3    4  5   6    7
6
//sign hundreds tens ones , 1/10 1/100
7
const PROGMEM char         //store the array in the flash
8
  g[16]="0011233455667889",//first  fractional digit
9
  h[16]="0639518406395184";//second fractional digit
10
  unsigned char a[9];     //Dallas DS1820 Scratchpad array
11
  char t;                 //temperature in absolute degrees
12
  char f;                 //fractionals (1/16°) of absolute degrees
13
  char c,s;               //sign (if zero, the sign was printed already)
14
  int  t12;               //12bit temperature value
15
  t12=3+8*a[0]-((a[6]-1)&7);//alternate way of calculation for DS18S20 (substitute DS18B20 code to read the 12bit here)
16
  if(a[1]){t12-=128*16;}  //correct by -128°
17
  if(t12>=0){s='+';}      //calc absolute temp
18
  else{t12=-t12;s='-';}
19
  f=t12&15;               //fractionals
20
  t=t12>>4;//must be signed int  for the calculation of tens-digit (while)
21
  if(t>99){putch(s);s=0;  //absolute temp is higher than 99 (and lower than 128)
22
    putch('1');t-=100;}   //sign-digit is the sign, hund-digit is 1
23
  else{putch(' ');        //absolute temp is lower than 100, sign-digit is a space
24
    if(t>9){putch(s);s=0;}//if 10..99: hund-digit is the sign
25
    else    putch(' ');}  //if  0.. 9: hund-digit is a space
26
  c='0'-1;                //calculate tens
27
  while(c++,(t-=10)>=0);  //this should be faster than c='0';while((t-=10)>=0)c++;
28
  if(s)putch(s);          //if sign was not printed yet, do it now at tens-digit
29
  else putch(c);          //tens-digit
30
  putch(58+t);putch(',' );//ones-digit   '0'+10+t, as t is negative here
31
  putch(g[f]);putch(h[f]);//the fractional digits are not calculated
32
  putch('°' );putch('C' );//but stored in 2 arrays
Gast #6749439
Lesenswert?

Danke dir eprofi...
wenn ich das so sehe... Puh...

Ich werde mal die ganzen Lösungen ausprobieren und schauen was am Ende 
am schnellsten funzt.

Ob das natürlich wirklich Sinn macht das zu überoptimieren ist fraglich.


Für was die Temperatur gebraucht wird? sie wird ansich nur an eine 
Datenbank weiter geschickt. Von daher wäre auch eine Zahl ohne jegliche 
Nachkommastelle akzeptabel.

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