Forum: Mikrocontroller und Digitale Elektronik AVR Studio, Rechnen mit Fließkommazahlen


von Multi K. (multikulti)


Lesenswert?

Guten Tag,
ich benutze das Avr Studio 4.14. Ich möchte mir ein paar Konstanten zur 
präprozessorzeit vom Assembler ausrechnen lassen. Jetzt habe ich aber 
festgestellt das dieser mir die Fließkommazahlen einfach hinter dem 
Komma abschneidet.
Hier mal das Beispiel:

.equ Drehzahl = 60
.equ MessInterval = 0.1
.equ CPUFrequenz = 8000000
.equ PWMFrequenz = CPUFrequenz/256
.equ DrehzahlFaktor = (((Drehzahl/60)/MessInterval)/1000)*500

Die Konstante "DrehzahlFaktor" soll nacher im Code an den entsprechenden 
stellen eingefügt werden. Damit ich den wert nicht jedesmal neu 
ausrechnen will, habe ich die Formel dazu Geschrieben und ich brauch nur 
die Drehzahl ganz oben zu ändern. Ist jetzt eigentlich auch nicht 
relevant, denn das eigentliche Problem ist, das der AVR Asembler mir bei 
der Konstante "MessInterval" die 1 hinter dem komma abschneidet. Das 
erzeugt dann natürlich die Fehlermeldung das nicht durch 0 geteilt 
werden kann.

Was kann ich tun?

von spess53 (Gast)


Lesenswert?

Hi

Und das überrascht dich?

Was geht ist (im Assembler2) z.B

.equ DrehzahlFaktor = Q7((((Drehzahl/60)/MessInterval)/1000)*500)

oder

.equ DrehzahlFaktor = Q15((((Drehzahl/60)/MessInterval)/1000)*500)

Das ergibt Werte, wie sie bei FMULxx verwendet werden. Also im Bereich 
-1<x<+1.

MfG Spess

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

> Was kann ich tun?

Der Preprozessor arbeitet mit 32-Bit-Ganzzahlen. Man sollte also die 
Konstanten ganzzahlig halten. Mit Festkommaarithmetik kommt man oft zum 
selben Ergebnis.

von spess53 (Gast)


Lesenswert?

Hi

Nachtrag:

>denn das eigentliche Problem ist, das der AVR Asembler mir bei
>der Konstante "MessInterval" die 1 hinter dem komma abschneidet. Das
>erzeugt dann natürlich die Fehlermeldung das nicht durch 0 geteilt
>werden kann.

Dann nehm doch:

.equ DrehzahlFaktor = 1/(((Drehzahl/60)/MessInterval)...)

mit einer ensprechenden Skalierung 2^n und mache eine Multiplikation.

MfG Spess

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das Probem Ganzzahlrechnung wird sich in allen deinen Berechnungen 
zeigen.

Gib doch MessInterval in Millisekunden statt in s an, d.h. verrechne es 
mit dem Faktor 1000

Ich würde die Formel auch umstellen insbesondere die Multiplikation mit 
500 am Anfang statt am Schluss machen.

.equ DrehzahlFaktor = (Drehzahl * 500) / (60 * ms_MessInterval)

von Иван S. (ivan)


Lesenswert?

Oberlehrermodus á la Falk B.:
Du suchst eigentlich 
http://www.mikrocontroller.net/articles/Festkommaarithmetik

von Multi K. (multikulti)


Lesenswert?

Also irgendwie ist mir das ganze noch immer Schleierhaft. Mit folgender 
Schreibweise hat es jetzt Funktioniert:

.equ Drehzahl = 100 ; Umdrehungen pro Minute
.equ MessInterval = 10 ; in Millisekunden
.equ DrehzahlFaktor = ((Drehzahl/60)*500)/(1000/MessInterval)
.equ CPUFrequenz = 8000000
.equ PWMFrequenz = CPUFrequenz/256

Während es mit folgender Schreibweise nicht funktionierte:

MessIntervall = 10 ; in Millisekunden
.equ DrehzahlFaktor = ((Drehzahl/60))/(1000/MessInterval)*500

In dem Fall wurde zwar keine Fehlermeldung produziert, aber die 
Konstante DrehzahlFaktor hat einfach den Wert 0.

Ich stehe aber schon wieder vor dem nächsten Problem: Ich brauche für 
einen P Regler einen Verstärkungsfaktor zwischen 1 und 2. Das heißt ich 
muss mit einer Kommazahl Multiplizieren. Das gedachte Komma ist nach dem 
6. Bit. Das heißt: 00,000000 Der Multiplikator wird dann nach dem 
bekannten Verfahren um 6 stellen nach links verschoben, multipliziert 
und wieder zurückgeschoben. Ich möchte den Wert für den 
Verstärkungsfaktor wieder per .equ Befehl vom Assembler errechnen 
lassen. Nur der kann ja nicht mit Kommazahlen umgehen und erst recht 
nicht mit welchen die ihre komastelle nach dem 6. bit haben. Hat jemand 
ne Idee?

von Oliver (Gast)


Lesenswert?

C

Oliver

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

Иван S. schrieb:
> Oberlehrermodus á la Falk B.:
> Du suchst eigentlich
> http://www.mikrocontroller.net/articles/Festkommaarithmetik

Nein, das sucht er eigentlich nicht. Das Prinzip ist zwar dasselbe, ihm 
geht es aber um den Preprozessor des AVR-Studios (also um Rechnen auf 
dem PC), während der Artikel vom Rechnen auf dem AVR ausgeht. Das sind 
zwei völlig verschiedene Baustellen.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Steffen P. schrieb:

> Mit folgender Schreibweise hat es jetzt Funktioniert:

Scheinbar...

> .equ Drehzahl = 100 ; Umdrehungen pro Minute
> .equ MessInterval = 10 ; in Millisekunden
> .equ DrehzahlFaktor = ((Drehzahl/60)*500)/(1000/MessInterval)
>
> Während es mit folgender Schreibweise nicht funktionierte:
> .equ Drehzahl = 100 ; Umdrehungen pro Minute
> .equ MessInterval = 10 ; in Millisekunden
> .equ DrehzahlFaktor = ((Drehzahl/60))/(1000/MessInterval)*500
>
> In dem Fall wurde zwar keine Fehlermeldung produziert, aber die
> Konstante DrehzahlFaktor hat einfach den Wert 0.

Fliesskommaergebnis:
(100/60)*500/(1000/10) = 8,33

Fall 1:
Teilausdruck 1a:
100/60 = 1,67 Ganzzahl: 1
*500   = 500

Teilausdruck 1b:
1000/10 = 100

Gesamtausdruck 1:
500 / 100 = 5
Fehler: -40%

Fall 2:
Teilausdruck 2a:
100/60 = 1,67 Ganzzahl: 1

Teilausdruck 2b:
1000/10 = 100

Gesamtausdruck 2:
1 / 100 = 0,01 Ganzzahl: 0
* 500   = 0
Fehler: -100%


Multipliziere früh mit 500
Beitrag "Re: AVR Studio, Rechnen mit Fließkommazahlen"

.equ DrehzahlFaktor = ((Drehzahl*500)/60)/(1000/MessInterval)

Fall 3:
Teilausdruck 3a:
100 * 500 = 50000
50000/60 = 833,33 Ganzzahl: 833

Teilausdruck 3b:
1000/10 = 100

Gesamtausdruck 3:
833 / 100 = 8,33 Ganzzahl: 8
Fehler: -4%

von Karl H. (kbuchegg)


Lesenswert?

Steffen P. schrieb:
> Also irgendwie ist mir das ganze noch immer Schleierhaft.

Weil du in guter alter Mathemanier davon ausgehst, dass dir auch bei 
Zwischenergebnissen alle Kommastellen erhalten bleiben. Besonders bei 
Divisionen ist das aber fatal, denn: Es gibt keine Kommastellen. Weder 
im Endergebnis noch in den Zwischenergebnissen.

  5 / 8        ergibt nun mal 0
und
  5 / 8 * 100  ergibt immer noch 0, denn 0 * 100 ist 0

aber
  5 * 100 / 8  ergibt 62, denn 500 / 8 ergibt 62

Fazit: Du willst Divisionen so spät wie möglich machen, weil dir dabei 
alle Kommastellen des Ergebnisses verlorengehen. Auch dann wenn mit dem 
Ergebnis der Division noch weiter gerechnet wird.

von Multi K. (multikulti)


Lesenswert?

Hm, okay das ergibt Sinn.
Ich frag mich nur, warum das avr studio nicht einfach komazahlen 
unterstützt. Das würde vieles einfacher machen^^
Nur wie mache ich das jetzt wenn vom Assembler eine Kommazahl 
ausgerechnet werden soll die dann im programm eingefügt werden soll. Es 
soll eine Kommazahl mit gedachtem komma nach dem 6. Bit sein. Die 
rechenroutine ist fertig und funktioniert auch. Da ich den wert aber 
praktisch ermitteln muss (es handelt sich ja um einen motorregler) muss 
ich ihn oft ändern und jedesmal neu ausrechnen und eintippen. Es währe 
viel einfacher wenn ich einfach einen Verstärkungsfaktor in Dezimal mit 
der .equ direktive eintippen könnte und der assembler mir dann den Wert 
mit der gedachten kommastelle errechnet und ins Programm einfügt.

von Karl H. (kbuchegg)


Lesenswert?

Steffen P. schrieb:

> Ich frag mich nur, warum das avr studio nicht einfach komazahlen
> unterstützt. Das würde vieles einfacher machen^^

Mit welchem Floating Point Schema soll denn gerechnet werden? Auf 
wieviele Nachkommastellen?

Die Thematik 'Floating Point Rechnen' ist wesentlich komplexer als du 
dir im Moment auch nur vorstellen kannst.

Wenn du genaueres wissen willst, empfehle ich dir die Lektüre:
http://docs.sun.com/source/806-3568/ncg_goldberg.html

Naives Benutzen von Floating Point führt oft zu Problemen, an die man im 
Vorfeld nicht gedacht hat.

> ich ihn oft ändern und jedesmal neu ausrechnen und eintippen. Es währe
> viel einfacher wenn ich einfach einen Verstärkungsfaktor in Dezimal mit
> der .equ direktive eintippen könnte und der assembler mir dann den Wert
> mit der gedachten kommastelle errechnet und ins Programm einfügt.

Du musst die Berechnung, die du mit dem Taschenrechner machst, so 
formulieren, dass dich das Problem nicht beisst.

Ja, so ist das nun mal in der Programmierung. Das ist keine Schema F 
Arbeit.

von spess53 (Gast)


Lesenswert?

Hi

> Es währe viel einfacher wenn ich einfach einen Verstärkungsfaktor in
>Dezimal mit der .equ direktive eintippen könnte und der assembler mir dann
> den Wert mit der gedachten kommastelle errechnet und ins Programm einfügt.

So sollte es gehen:

.equ float  = ((INT(2.567))<<6) + ((Q7(FRAC(2.567)))>>1)

MfG Spess

von Multi K. (multikulti)


Lesenswert?

Hm, das funktioniert tatsächlich. Aber ich denke der Assembler kann 
nicht mit kommazahlen umgehen. Wie ist das dann möglich?
Gibt es hier ein Tutorial zum Rechnen mit dem Assembler?

von spess53 (Gast)


Lesenswert?

Hi

>Gibt es hier ein Tutorial zum Rechnen mit dem Assembler?

Nicht das ich wüsste. Aber in der AVR-Studio-Hilfe zum Assembler unter
'User's Guide->Expressions' findest die notwendigen Infos.

MfG Spess

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

spess53 schrieb:
> Hi
>
>>Gibt es hier ein Tutorial zum Rechnen mit dem Assembler?
>
> Nicht das ich wüsste. Aber in der AVR-Studio-Hilfe zum Assembler unter
> 'User's Guide->Expressions' findest die notwendigen Infos.

Warum suchen viele Leute immer wieder Infos im Netz, die sie bereits auf 
der eigenen Festplatte haben?

>
> MfG Spess

von Multi K. (multikulti)


Lesenswert?

Auf die seite in der hilfe bin ich durchaus schon gestoßen. Damit das 
richtig sitzt ist ein Tutor aber nicht schlecht.

Naja, danke für die viele Hilfe! Ihr habt mir gut weitergeholfen.

von spess53 (Gast)


Lesenswert?

Hi

>Damit das richtig sitzt ist ein Tutor aber nicht schlecht.

Braucht ihr denn für jeden Sch... ein Tutorial? Einfach mal hinsetzen 
und selbst ausprobieren.

MfG Spess

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.