Forum: Mikrocontroller und Digitale Elektronik Edler weg der Umrechnung


von Simon (Gast)


Angehängte Dateien:

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

von Achim M. (minifloat)


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

von berliner (Gast)


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ß,

von berliner (Gast)


Lesenswert?

und wenn du nie fertig werden willst, dann nimmst du einfach den "edlen 
Weg der Umrechnung" :-D

von Lars R. (larsr)


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

: Bearbeitet durch User
von Achim (Gast)


Lesenswert?

1
temperature *= 625;  //(0.0625 C je Bit);
2
temperature /= 100;

ist gleich:
1
temperature *= 25;  //(0.0625 C je Bit);
2
temperature /= 4;

vermutlich macht der Compiler bereits das gleich wie:
1
temperature *= 25;  //(0.0625 C je Bit);
2
temperature >>= 2;

von Achim M. (minifloat)


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

: Bearbeitet durch User
von Jemand (Gast)


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?

von Simon (Gast)


Lesenswert?

Hehe, ja fertig werden trifft es :-)

geht um einen MSP430_2x, der sollte die division können :-)

von PittyJ (Gast)


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.

von Wolfgang (Gast)


Lesenswert?

PittyJ schrieb:
> Die Genauigkeit mit 16tel Grad würde ich ignorieren. So genau sind die
> Sensoren nicht.

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

von Christian H. (netzwanze) Benutzerseite


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.

von Vorn N. (eprofi)


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

: Bearbeitet durch User
von Simon (Gast)


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.

von Peter D. (peda)


Lesenswert?

Simon schrieb:
> temperature *= 625;  //(0.0625 C je Bit);
>       temperature /= 100;

Na dann warte mal, bis Winter ist. Dann liefert Deine Rechnung Mumpitz.

Der Sensor braucht 750ms je Messung. In der Zeit hat jeder 8Bitter 
vorzeichenrichtig das bischen float gerechnet und dreht den Rest der 
Zeit Däumchen.

: Bearbeitet durch User
von Axel R. (axlr)


Lesenswert?

Er sucht einen "edlen Weg der Umrechnung"
Ich dachte der "Edler" sei abhanden gekommen. :) Hab den Eröffnungspost 
auch gewissenhaft gelesen und für mich "Edler" mit "Integer" im Zuge der 
Autokorrektur assoziiert.
Sowas aber auch...
(War ich wieder der einzige?)

von Vorn N. (eprofi)


Lesenswert?

Was heißt hier "puh"?
Das ist schon fast Assembler-Niveau. Jede Zeile dürfte 2-5 Befehle 
ergeben, d.h. 100 Befehle. Schneller, kürzer und edler geht kaum. :-)
Und bedenke, Du brauchst kein printf etc.
Das ganze Programm sind vielleicht 500 Bytes.

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.