Forum: Mikrocontroller und Digitale Elektronik Problem mit Casts von Datentypen


von Raphael F. (erdbewohner)


Lesenswert?

Hallo!
Ich möchte für meinen ATXmega eine Funktion schreiben, die den Wert des 
internen Temperatursensors in °C umwandelt:
1
int8_t calcTemperature(void)
2
{
3
  return (((uint16_t)((ADCA_CH1_RES * (uint32_t)tempCalcCoeff)>>13)) - 273);
4
}
Wenn ich nun das disassembler anschaue, sehe ich, dass vom Wert in 
Kelvin nur 0x11 und nicht 0x111 (=273) abgezogen werden:
1
return (((uint16_t)((ADCA_CH1_RES * (uint32_t)tempCalcCoeff)>>13)) - 273);
2
00000124  LDS R18,0x022C    Load direct from data space 
3
00000126  LDS R19,0x022D    Load direct from data space 
4
00000128  LDS R22,0x2001    Load direct from data space 
5
0000012A  LDS R23,0x2002    Load direct from data space 
6
0000012C  LDI R24,0x00    Load immediate 
7
0000012D  LDI R25,0x00    Load immediate 
8
0000012E  LDI R20,0x00    Load immediate 
9
0000012F  LDI R21,0x00    Load immediate 
10
00000130  CALL 0x0000024E    Call subroutine 
11
00000132  MOVW R26,R24    Copy register pair 
12
00000133  MOVW R24,R22    Copy register pair 
13
00000134  LDI R18,0x0D    Load immediate 
14
00000135  LSR R27    Logical shift right 
15
00000136  ROR R26    Rotate right through carry 
16
00000137  ROR R25    Rotate right through carry 
17
00000138  ROR R24    Rotate right through carry 
18
00000139  DEC R18    Decrement 
19
0000013A  BRNE PC-0x05    Branch if not equal 
20
}
21
0000013B  SUBI R24,0x11    Subtract immediate 
22
0000013C  RET     Subroutine return
Ich habe schon alle möglichen Varianten mit typen-cast ausprobiert, aber 
es hat alles nichts gebracht.
Könnt ihr mir helfen?
Vielen Dank!
Erdbewohner

von Peter II (Gast)


Lesenswert?

Raphael F. schrieb:
> Wenn ich nun das disassembler anschaue, sehe ich, dass vom Wert in
> Kelvin nur 0x11 und nicht 0x111 (=273) abgezogen werden:

273-256 = 0x11

die 0x11 ist also richtig für das low-byte.

Ich würde die rechenschritte mal einzeln machen.

uint16_t tmp = (ADCA_CH1_RES * (uint32_t)tempCalcCoeff)>>13;
tmp -= 273;
return tmp;

wie gross ist denn ADCA_CH1_RES?

von Karl H. (kbuchegg)


Lesenswert?

> int8_t calcTemperature(void)
  ******

Ich denke hier liegt das "Problem".

Ob du nur vom Lowbyte 0x11 abziehst, oder von einem unsigned 16 Bit 
Ergebnis 0x0111 ist ziemlich irrelevant, wenn du dann sowieso vom 
Ergebnis das High_byte verwirfst und das ganze danach als eine Zahl mit 
Vorzeichen verkaufst.

von Raphael F. (erdbewohner)


Lesenswert?

Arrrrrggg!!
Natürlich!
Meine Überlegung war, dass der Wert in Kelvin ja noch grösser als 128 
ist, und dass darum auch 273 und nicht nur 17 abgezogen werden sollten. 
Aber wenn man das High Byte weglässt und annimmt, dass es 1 ist (sonst 
geht es sowieso nicht), geht es natürlich.
Vielen Dank!

von Karl H. (kbuchegg)


Lesenswert?

Ich würde hier
1
 return (((uint16_t)((AD....

auch nicht nach unsigned casten, sondern auf int16_t.
Das Ergebnis könnte sonst bei negativen Celsius Temperaturen 
'interessant' werden, wenn du von 250K 273K abziehst.

von Raphael F. (erdbewohner)


Lesenswert?

ja, das lasse ich lieber weg. Es war nur ein Versuch von vielen, die ich 
gemacht habe, um das vermeintliche Problem zu lösen.

von W.S. (Gast)


Lesenswert?

Raphael F. schrieb:
> return (((uint16_t)((ADCA_CH1_RES * (uint32_t)tempCalcCoeff)>>13)) - 273);

Bei solchen Zeilen wird mir schlecht. Schreib dein Zeugs doch besser 
einzeln und nicht in einem Klumpen.

long temp;

temp = ADCA_CH1_RES * tempCalcCoeff;
if (temp>blabla) temp = blabla;  // Sättigung ist besser als Abhacken
temp = temp>>13;
return temp;

Bei einem einigermaßen vernünftigen Compiler kommt damit ein optimaler 
Code heraus, weil temp sowieso in einem Register gehalten wird. Es ist 
also überhaupt kein Grund vorhanden, mit Typecasts um sich zu schmeißen.

Merke: Typecasts sollten die Ausnahme sein, nicht die Regel. Wenn 
jemand für jeden Furz einen Typecast braucht, dann macht er etwas 
gründlich falsch.

W.S.

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.