Forum: Compiler & IDEs 16-Bit Ergebnis aus 8-Bit-Variablen berechnen?


von Erik H. (agutanus)


Lesenswert?

Ich möchte in einer Lüftersteuerung aus einer gemessenen Temperatur und 
diversen Variablen ein PWM-Wert für Lüfter berechnen.
Gerechnet werden soll ausschließlich mit positiven Integer-Werten und 
das Ergebnis soll, falls größer 255 auf 255 reduziert werden.

Während das Ergebnis und Zwischenwerte größer 255 werden können, sind 
alle Ausgangswerte 8-Bit-Variablen.
Wie sage ich dem Compiler, dass er die Rechnung als 16-Bit-Rechnung 
compilieren soll? Reicht es eine 16-Bit-Variable als Ergebnis anzugeben?

>>Informationen:
µC:  ATmega168
Compiler: AVR-GCC (AVR-Studio 4)
Varibalen:
eingelesene Temperatur (T), Einschalt-Temperatur (Tmin), Temperatur für 
volle Drehzahl (Tmax), an Lüfter übertragener PWM-Wert (PWM), minimal 
möglicher PWM-Wert (PWMmin), maximal gewollter PWM-Wert (PWMmax)
Rechenweg:
PWM = ( ((T-Tmin) * (PWMmax-PWMmin)) / (Tmax-Tmin) ) + PWMmin

von Alex E. (tecnologic) Benutzerseite


Lesenswert?

hi,

das Problem lößt man mit den sog. casts dh.

PWM = (uint8_t)( ((uint16_t)(T-Tmin) * (PWMmax-PWMmin)) / (Tmax-Tmin) ) 
+ PWMmin

(typ)Variable

du schreibst in die Klammern den Typ mit dem der Compiler die Variable 
interpretieren soll. Bei deiner Rechnung heißt das das du (T-Tmin) als 
16 bit auswertest und das gesamte Ergebnis wieder als 8 bit der 
Variablen PWM zu weist.

ich hoffe das war halbwegs verständlich.

MfG

Tec

von Karl H. (kbuchegg)


Lesenswert?

Kanst du dir alles sparen:
Alte C-Regel:  gerechne twird mindestens im Datentyp int.
Auf dem AVR also mit 16 Bit

von Erik H. (agutanus)


Lesenswert?

ich kann mir nicht vorstellen, dass auf einem 8-Bit µC jede Berechnung 
mit 16-Bit erfolgt... das wäre nun doch recht ineffizient!
Aber ich werde es mal mit einem Cast vor der gesamten Rechnung 
probieren.
Ohne Casts kommt recht Schnell ziemlicher Mist raus!

von Karl H. (kbuchegg)


Lesenswert?

Erik H. schrieb:
> ich kann mir nicht vorstellen, dass auf einem 8-Bit µC jede Berechnung
> mit 16-Bit erfolgt... das wäre nun doch recht ineffizient!

LIes ein C-Buch.

Es spielt keine Rolle was du dir auf einem 8-Bit µC vorstellen kannst 
und was nicht. C ist eine genormte Sprache. Entscheidend ist, was in 
dieser Norm steht. Und da steht nun mal drinnen, dass mindestens in int 
gerechnet wird.

Es steht allerdings auch drinnen, dass es die AS_IF Regel gilt.
Wenn der Compiler beweisen kann, dass sich am Ergebnis nichts ändert, 
wenn er anstelle von in 16 Bit, die ganze Berechnung nur in 8-Bit 
realsiert, dann darf er das tun.
Allerdings wird ihm das in deinem Fall schwer fallen.

von Erik H. (agutanus)


Lesenswert?

Woran kann ich erkennen, wie groß "int" im GCC-Compiler ist?

Ich Kompiliere immer mit der Optimierung: "-0s" könnte das zu Problemen 
führen?

habe es so probiert:

16-bit-variable = (uint16_t)(rechnung);

Die Rechenergebnisse sind noch immer  recht verwirrend... Irgendwie viel 
zu gering.

von Karl H. (kbuchegg)


Lesenswert?

Erik H. schrieb:
> Woran kann ich erkennen, wie groß "int" im GCC-Compiler ist?

sizeof(int)
sagt es dir.
Aber im WinAVR ist siezof(int) gleich 2. Also 16 Bit

> Ich Kompiliere immer mit der Optimierung: "-0s" könnte das zu Problemen
> führen?

Kann.
Aber anders als du denkst. Der Compiler bearbeitet deinen Text deswegen 
immer noch nach den C-Regeln. Nur nutzt er konsequenter Möglichkeiten 
aus, die du ihm offen lässt. Darum ist es auch wichtig, die C-Regeln zu 
kennen.
Denn dein Compiler lässt sich nicht weichkochen. Der hält sich 
konsequent an: Unwissenheit schützt nicht vor Strafe.

> 16-bit-variable = (uint16_t)(rechnung);

Das bringt nichts.

Einem Kind, das schon in den Brunnen gefallen ist, kannst du hinterher 
Mund zu Mund Beatmung machen, bis du umfällst. Das bringt niemanden 
weiter.
Du musst im Vorfeld schon dafür sorgen, dass es erst gar nicht 
reinfällt!

http://www.mikrocontroller.net/articles/FAQ#Datentypen_in_Operationen

von Karl H. (kbuchegg)


Lesenswert?

OK.
Jetzt mal Tacheles

PWM = ( ((T-Tmin) * (PWMmax-PWMmin)) / (Tmax-Tmin) ) + PWMmin

Nachdem wir jetzt einig sind, dass das als int (oder unsigned int, 
aufpassen! Max - Min darf dann natürlich nicht negativ werden) gerechnet 
wird:
wie sehen deine Zahlenwerte aus? bzw. Wobei gibt es Ärger?

von Erik H. (agutanus)


Lesenswert?

Hab den Fehler Gefunden:
War lediglich ein Denkfehler und etwas ungenaues Hinsehen...
Sobald die gemessene Temperatur (T) größer als Tmax war, stiegen die 
errechneten Werte über das PWMmax. Ist aber auch logisch!
Vor der Rechnung frage ich zwar ab, ob T < Tmin aber nicht ob T > Tmax.
Nun läufts!


Die Variablen wurde mit Absicht als unsigned gewählt, da nirgends ein 
negativer Wert vor kommen sollte.

Der Sensor misst bis -30°C, daher wird die Temperatur mit einem Offset 
von 30 verarbeitet: -30°C werden dann als 0 verarbeitet. Positive Werte 
vereinfachen die Umrechnung vom ADC-Wert in die Temperatur und später in 
den PWM-Wert.
Zum Ausgeben verwende ich sowieso selbst geschriebene 
"my_utoa()"-Funktionen, sodass ich diese für den Temperatur-Offset 
angepasst habe.

Nun versuche ich den PWM-Wert direkt über den ADC-Wert zu berechnen, da 
dann die Sprünge von 1K (Kelvin) nicht mehr so groß sind. (5x LSB-ADC = 
1K)

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.