Auf die Schnelle habe ich mir ein Programm geschrieben, was die ADCs des
ATmega48 liest und die PWMs steuert. Im Prinzip keine große Sache und
auch nicht wirklich viel Programmtext. Nur leider scheint das für den
ATmega48 doch zu viel zu sein. Dieser hat nur 4 kBytes
Programmierspeicher. Und das AVR-Studio sagt, dass der Programmspeicher
zu 120% voll ist.
Nun meine Frage: Habe ich in meinen Programm irgendein Fehler verbockt
oder unnötig Speicherplatz verbraucht?
Ich kann mir nicht vorstellen, dass man so schnell ein µC voll bekommt.
Oder habe ich vielleicht falsche Einstellung beim AVR-Studio, so dass
dieser das Programm falsch kompiliert?
Bootloader verwende ich auch nicht.
Danke schon Mal im Voraus.
Danke für die schnelle Antwort.
Conny G. schrieb:> Baue es um, das zu vermeiden und es sind nur noch 200 Bytes :-)
Aber wie meinst du das genau?
Soll ich statt float lieber short int verwenden, weil ADCW auch nur 2
Byte groß ist?
Muss ich dann noch die float-Library ausbinden?
Wenn es das ist was du meinst, macht das den so ein großen Unterschied,
wenn ich statt float (4 Byte) besser short int(2 Byte) nutze?
Kai S. schrieb:> Wenn es das ist was du meinst, macht das den so ein großen Unterschied,> wenn ich statt float (4 Byte) besser short int(2 Byte) nutze?
nein, die zwei Bytes sind dem avr egal. Der Unterschied besteht darin,
dass float ein komplexer Datentyp ist und der avr nur über große Umwege
damit rechnen kann.
>Soll ich statt float lieber short int verwenden, weil ADCW auch nur 2>Byte groß ist?
Es lebe der Extremismus.
Im Grunde geht es nicht um die Größe (in Bytes) der Variablen sondern um
eine riesige Bibliothek, die hinzugelinkt wird.
Wenn Du glaubst zu Ungenau zu werden, so nimm Doppelworte, schiebe deine
Basiswerte um 8 bis 16 Bit nach rechts, mach Dein Ding und schiebe den
Kram kurz vor der Übergabe wieder um die 8 bis 16 Bit zurück.
Die verwendeten Multiplikations- und Divisionsroutinen brauchen nicht
viel Platz.
Tust Du nur die Kern- oder Rechenvariablen auf ein größeres Format
erweitern, flippt Dir auch die Speicherverwaltung nicht aus.
Kai S. schrieb:> Danke für die schnelle Antwort.>> Conny G. schrieb:>> Baue es um, das zu vermeiden und es sind nur noch 200 Bytes :-)>> Aber wie meinst du das genau?> Soll ich statt float lieber short int verwenden, weil ADCW auch nur 2> Byte groß ist?> Muss ich dann noch die float-Library ausbinden?>> Wenn es das ist was du meinst, macht das den so ein großen Unterschied,> wenn ich statt float (4 Byte) besser short int(2 Byte) nutze?
Am besten Du stellst auf Festkomma-Arithmetik um.
Also Du lässt den ADC-Wert so wie er ist:
1
// Die Spannung am Eingang mit der Nummer (chan) messen:
2
floatADC_Read(uint8_tchan){//Kanal 0 bis 7
3
4
staticuint8_tmux;
5
6
if(mux==chan){// Normalerweise kein Kanalwechsel
7
ADCSRA|=(1<<ADSC);// eine ADC-Wandlung starten
8
while(ADCSRA&(1<<ADSC));// auf Abschluss warten
9
10
returnADCW;//!! der ist jetzt 1024 = 10 bits nach links verschoben
OCR2B=(unsignedchar)(102*((poti-0.1)/0.9)+153);//Lüfter von Poti steuern
3
}
so ab, dass deine Bits rechts die Nachkommastellen sind und Du nur mit
Ganzzahlen rechnest.
Müssen auch nicht alle 10 Bits sein, kann auch weniger sein.
Hier gibt's mehr Info:
http://www.mikrocontroller.net/articles/Festkommaarithmetik
So ein kleiner uC kann keine Flieskommarechnung von der CPU aus, wenn
man das tut, dann bindet der Compiler automatisch Bibliotheken ein, die
die Fliesskommarechnungen mit einem Heidenaufwand durchführen.
Und wie Du merktest ist der Aufwand größer als ein uC ihn leisten kann.
Deshalb muss man hier eine andere Taktik fahren um dem Generell aus dem
Weg zu gehen.
Sobald Du den Compiler nicht mehr zu Zahlen mit Nachkommastellen
zwingst, braucht er auch die Lib dafür nicht mehr und lässt sie weg.
Kai S. schrieb:> Und das AVR-Studio sagt, dass der Programmspeicher> zu 120% voll ist.
Dann hast Du die falsch Math-Lib gelinkt oder Optimierung aus.
Ich komme mit WINAVR auf:
1
4.3.3
2
AVR Memory Usage
3
----------------
4
Device: atmega48
5
6
Program: 2024 bytes (49.4% Full)
7
(.text + .data + .bootloader)
8
9
Data: 1 bytes (0.2% Full)
10
(.data + .bss + .noinit)
Die float Lib belegt einmalig 1kB, man muß vor float also keine Angst
haben.
Früher mag das anders gewesen sein, daher haben viele immer noch
Vorbehalte.
Erst mal ein großes Dankeschön an alle für eure nützlichen Tipps.
Nun habe ich alle Kommarechnungen raus genommen und siehe da, das
Programm ist mal gerade 776 Bytes groß. Was für ein Wunder! Wenn man
zuvor mit so etwas noch nie Probleme hatte ist das schon sehr
überraschend.
Peter Dannegger schrieb:> Dann hast Du die falsch Math-Lib gelinkt oder Optimierung aus.
Das bei dir nur 49.4% belegt sind ist sehr wunderlich. Wie kann ich den
überprüfen welche Math-Lib ich gelinkt habe bzw. wie kann ich sie dann
ändern?
Mit der Optimierung habe ich auch schon rumgespielt. Brachte aber kaum
Erfolg. Daran kann es nicht liegen.
Uwe S. schrieb:> Kai S. ,>> zeige uns doch bitte Dein Makefile, das steht alles drin..
Wo soll der herkommen bei Atmel Studio? Da gibts keinen makefile. Was
soll diese Frage? Er hat die Math Lib nicht gelinkt, fertig. Da muss man
keinen makefile zu sehen.
@Kai:
Die Mathe lib heißt eigentlich "libm.a". Bei den Linkeroptionen trägt
man lediglich "m" ein, da das "lib" und die Endung bereits vom linker so
erwartet werden. Wo man genau im Atmel Studio weitere libs für den
Linker angibt, weiß ich leider nicht, da ich Eclipse nutze.
gruß cyblord
Peter Dannegger schrieb:> Die float Lib belegt einmalig 1kB, man muß vor float also keine Angst> haben.> Früher mag das anders gewesen sein, daher haben viele immer noch> Vorbehalte.
Das kann ich voll bestätigen. Und float auf dem AVR ist recht schnell!
Ich habe eher den Verdacht, dass delay_ms(5000) zumindest gefühlt allein
schon 5kB braucht :-)
m.n. schrieb:> Peter Dannegger schrieb:>> Die float Lib belegt einmalig 1kB, man muß vor float also keine Angst>> haben.>> Früher mag das anders gewesen sein, daher haben viele immer noch>> Vorbehalte.>> Das kann ich voll bestätigen. Und float auf dem AVR ist recht schnell!
Ich geb dir in der Sache recht.
Aber bei ihm ist es auch kein Beinbruch, wenn er in der ADC_Read
Funktion dann eben nicht Floating Point durch 1024 dividiert und dafür
hier in der Verwendung
1
poti=ADC_Read(0);//prozentuiere die Spannung an ADC0
2
if(poti<0.1){//Bei unter 10% des Potis
3
...
4
}else{//Bei größer gleich 10% des Potis
5
...
6
OCR0A=(unsignedchar)(102*((poti-0.1)/0.9)+153);//Lüfter von Poti steuern
an 2 Stellen ein wenig umstellt. Und um mehr geht es in diesem Programm
nicht.
Wo du natürlich recht hast: Für nicht benutzten Flash gibt es kein Geld
zurück und in dieser Applikation ist die Laufzeit auch nicht das
Problem.
Trotzdem würde mich interessieren, was er gemacht hat, damit er den
Flash angefüllt hat. Selbst mit der Floating Lib sollte das doch alles
locker rein passen.
cyblord ---- schrieb:> Wo soll der herkommen bei Atmel Studio? Da gibts keinen makefile. Was> soll diese Frage?
Selbstverständlich gibt es da ein makefile. Das Studion ompiliert nicht
selber, das ruft auch nur make auf. Das makeflie dafür wird vom Studio
automatisch erzeugt, und ist leicht zu finden.
Oliver
Karl Heinz schrieb:> Trotzdem würde mich interessieren, was er gemacht hat, damit er den> Flash angefüllt hat. Selbst mit der Floating Lib sollte das doch alles> locker rein passen.
Wenn er das Listing vom Linker zeigen würde, könnte man es sofort sehen,
ohne lange auf Irrwegen (Abblockkondensatoren, usw.... :-)
herumzulaufen.
m.n. schrieb:> Karl Heinz schrieb:>> Trotzdem würde mich interessieren, was er gemacht hat, damit er den>> Flash angefüllt hat. Selbst mit der Floating Lib sollte das doch alles>> locker rein passen.>> Wenn er das Listing vom Linker zeigen würde, könnte man es sofort sehen,> ohne lange auf Irrwegen (Abblockkondensatoren, usw.... :-)> herumzulaufen.
Ich hab noch so dunkel in Erinnerung, dass im 4-er Studio die -lm nicht
standardmässig angegeben war und dann die generischen Floating Routinen
eingebunden wurden, die größer sein sollen.
Karl Heinz schrieb:> m.n. schrieb:>> Karl Heinz schrieb:>>> Trotzdem würde mich interessieren, was er gemacht hat, damit er den>>> Flash angefüllt hat. Selbst mit der Floating Lib sollte das doch alles>>> locker rein passen.>>>> Wenn er das Listing vom Linker zeigen würde, könnte man es sofort sehen,>> ohne lange auf Irrwegen (Abblockkondensatoren, usw.... :-)>> herumzulaufen.>> Ich hab noch so dunkel in Erinnerung, dass im 4-er Studio die -lm nicht> standardmässig angegeben war und dann die generischen Floating Routinen> eingebunden wurden, die größer sein sollen.
Yep. Das scheint es zu sein.
Mach ich ein Testprojekt für den M48 und geb keine libm.a in den
Linkeroptionen an, dann binn ich trotz -Os bei 113%
Mit libm.a geht es runter auf 49%
Karl Heinz schrieb:> Ich hab noch so dunkel in Erinnerung, dass im 4-er Studio die -lm nicht> standardmässig angegeben war und dann die generischen Floating Routinen> eingebunden wurden, die größer sein sollen.
Das ist richtig; die waren übel groß. Beim 4.19 Studio muß ich dem
Linker auch immer noch explizit Bescheid geben. Aber dann geht's los!
Vielleicht sollten wir abwarten, bis der TO aufgestanden ist und
gefrühstückt hat.
Guten morgen. Oder eher Mittag!
Danke für das Warten ...
m.n. schrieb:> bis der TO aufgestanden ist und> gefrühstückt hat.
Hier hat sich ja einiges getan. Ich habe nun auch beim AVR-Studio 4.18
(- AVR Studio was den AT90USB1287 noch simuliert und ein Studio was ich
überhaupt auf meinen Rechner zum Laufen bekommen hab ... bisher) libm.a
eingefügt und siehe da. Das Programm ist trotz float und
Gleitkommarechnung nur 49.4% groß. Was für ein Wunder. Und schon wider
überrascht es mich, weil ich mit so einem Problem bisher noch nichts zu
tun hatte. Geschweige denn, dass ich bei den Linkeroptionen etwas
zufügen musste.
Wenn ich es jetzt richtig verstehe, kann ich ob unnötig oder nicht mit
float und Gleitkommarechnungen programmieren, da dank der libm.a dies
keine großen Auswirkungen hat? Oder sollte ich mir nun doch angewöhnen
möglichst ohne float und auf jeden Fall ohne Gleitkommazahlen zu
rechnen?
Wenn bei meinen AVR-Studio schon libm.a fehlt, kann es sein, dass mir
auch noch andere wichtige Linkeroptionen fehlen?
Uwe S. schrieb:> zeige uns doch bitte Dein Makefile, das steht alles drin..
Da das Problem gefunden wurden ist, hat sich das erledigt.
m.n. schrieb:> Ich habe eher den Verdacht, dass delay_ms(5000) zumindest gefühlt allein> schon 5kB braucht :-)
Das hatte ich auch als erstes im Verdacht. Aber selbst wenn ich delay
entfernt hatte, war das Programm noch zu groß.
Kai S. schrieb:> Wenn ich es jetzt richtig verstehe, kann ich ob unnötig oder nicht mit> float und Gleitkommarechnungen programmieren, da dank der libm.a dies> keine großen Auswirkungen hat? Oder sollte ich mir nun doch angewöhnen> möglichst ohne float und auf jeden Fall ohne Gleitkommazahlen zu> rechnen?
In der Allgemeinheit ist so eine Frage schwierig zu beantworten. Wenn es
dein Programm einfach macht, dann benutze Floating Point.
Aber sei gewarnt: Floating Point ist auch nicht die Lösung aller
Probleme.
In deinem konkretem Programm würde ich mir die Frage stellen, ob es
tatsächlich und wirklich notwendig ist, die gemessene Spannung
tatsächlich in Form von Volt zur Verfügung zu haben. Bringt mir das was,
wird dadurch irgendetwas klarer?
IMHO nein. Der ADC stellt einen Wert fest. Ob der jetzt von 0.0 bis 5.0
läuft oder von 0 bis 1023, das ist nur ein anderer Zahlenwert.
Entscheidend ist doch: je weiter verdreht das Poti ist, desto größer ist
der Wert. Rechnen kann ich mit dem einen genausogut wie mit dem anderen.
Zumal es mir dann auch bewusst macht, dass ich mit
1
if(adc_wert_integer<50)
eben sowieso nicht EXAKT 0.1V als Grenze haben werde, selbst dann nicht
wenn ich Floating Point anwende und der Vergleich
1
if(adc_wert_float<0.1)
hier etwas suggeriert, das nicht vorhanden ist, weil ja der float Wert
eben nicht kontuinuierlich alle Zahlenwerte annehmen kann, sondern da ja
immer noch die Diskretisierung auf 1024 mögliche Werte durch den ADC
drinnen steckt.
Die Umrechnung in den OCR Wert gestaltet sich dann eben so, dass nicht
mehr der Bereich 0.0-5.0 auf den gewünschten OCR Bereich umgemappt wird,
sondern ein Bereich 0-1023. Das heißt, das ist Jacke wie Hose, ein
Zahlenbereich wird linear in einen anderen Zahlenbereich transformiert.
Man hätte genausogut die ADC Werte nicht in eine Spannung sondern in
einen Winkel von 0 bis 360 umrechnen können und mit dem dann weiter
rechnen können. Das alles sind nur andere Zahlenwerte, ändert aber am
Prinzip nichts.
D.h. ich brauch hier in Wirklichkeit die Spannung an sich ja gar nicht.
D.h ich könnte mir diese ganze Flaoting Point Rechnerei auch sparen.
Daher würde ich hier kein Floating Point benutzen. Ich seh da keinen
Vorteil drinnen, sie zu haben. Denn eigentlich interessiert mich ja die
Spannung nicht. Was mich interessiert ist der Verdrehwinkel des Potis.
Der wird nicht besser oder schlechter dadurch ausgedrückt, dass ich ihn
in Volt ausdrücke als durch einen fiktiven Wert, der von 0 bis 1023
geht.
Was anderes wäre es, wenn man zb mittels GPS Koordinaten Arithmetik am
Grosskreis betreibt. Da wäre man "verrückt", wenn man das ohne Floating
Point rechnen will.
Muss mich entschuldigen.
Du rechnest dir ja die Spannung gar nicht explizit aus, sondern
normierst den ADC Bereich auf 0.0 bis 1.0. Jetzt weiß ich auch wieder,
warum mir die ganze Zeit 10% im Kopf rumgespukt sind. Das sieht man
nämlich auch hier recht oft, dass das Ergebnis vom ADC auf Biegen und
Brechen erst mal in eine SPannung umgerechnet wird, nur um dann mit
einer weiteren Umrechnung die Spannung wieder in einen anderen Wert
umzurechnen.
Ist aber vom Prinzip her egal. Letzten Endes ist es einfach nur ein
Skalierfaktor, mit dem du das ADC Ergebnis beaufschlagst und der dich
dazu zwingt Floating Point zu benutzen. Kann man machen, muss man nicht
machen, für nicht verbrauchten Flash und eingesparte Laufzeit kriegt man
kein Geld zurück.
Ich verwende möglichst kein Float, denn Prigramme werden von alleine
immer größer und dann hat man mal von vorne herein 1k mehr.
In den meisten Fällen kommt man um float auch einfach herum, warum dann
1k und Rechenzeit verschwenden?
Da verwendest mal unbedacht in einem Timer INT ein float und wunderst
dich, dass es seltsame Timing Probleme gibt etc.
Float ist einfach relativ teuer und hat m.E. In einem 4k, paar MHz uC
nichts verloren.
Conny G. schrieb:> und Rechenzeit verschwenden?
Das verstehe ich nicht. Von welcher Rechenzeit reden wir denn hier -
10µs oder 10ms?
Kannst Du konkrete Beispiele liefern?
m.n. schrieb:> Conny G. schrieb:>> und Rechenzeit verschwenden?>> Das verstehe ich nicht. Von welcher Rechenzeit reden wir denn hier -> 10µs oder 10ms?> Kannst Du konkrete Beispiele liefern?
Nein und ich will hier keinen Glaubenskrieg anfangen - ich mag das halt
nicht und mach das so.
Wer meint, er muss auf den Minigurken unbedingt mit Float rechnen, der
soll es halt machen :-)
Conny G. schrieb:> Nein und ich will hier keinen Glaubenskrieg anfangen - ich mag das halt> nicht und mach das so.> Wer meint, er muss auf den Minigurken unbedingt mit Float rechnen, der> soll es halt machen :-)
Na schön; es hätte mich auch gewundert, wenn Du für Deine vorlauten
Behauptungen irgendwelche Beweise gehabt hättest.
Es spricht nichts gegen float, aber man sollte wissen was man tut. Ist
man sich der Probleme bewusst, ist alles ok. Es ist nur schlecht, wenn
man völlig unreflektiert floats in ein Programm reinschmeißt, so als
säße man an einer 3 GHz Kiste mit 8 GB Ram.
Man sollte sich eben klar machen dass float eben empfindlich flash
kostet (1kb ist viel, manche avr haben nicht gar nicht mehr), und
natürlich auch zusätzliche Takte bei der Berechnung.
Bewusster Umgang, dann ist alles ok.
gruß cyblord
Für ein Uni-Projekt (Roboter mit ARM7) gab mir der Dozent den Tipp,
double für alle Koordinaten zu verwenden. Das war das beste, was er
hätte tun können. Die Bewegungsformeln brauchte ich dann nur noch
hinschreiben und es tat schnell genug, was es sollte. Außerdem konnte
ich die meisten internen Werte fürs Debugging gleich auf eine reale
Größe beziehen.
Wenn man nicht mit komplizierten Formeln zu tun hat, tut es
Festkommaarithmetik aber besser. Vor allem erspart man sich damit auch
Probleme mit der numerischen Stabilität.
m.n. schrieb:> Conny G. schrieb:>> Nein und ich will hier keinen Glaubenskrieg anfangen - ich mag das halt>> nicht und mach das so.>> Wer meint, er muss auf den Minigurken unbedingt mit Float rechnen, der>> soll es halt machen :-)>> Na schön; es hätte mich auch gewundert, wenn Du für Deine vorlauten> Behauptungen irgendwelche Beweise gehabt hättest.
Wahnsinn, dass hier immer gleich rumgepöbelt werden muss. Schade.
Würdest Du doch im echten Leben auch nicht machen.
Conny G. schrieb:> Wahnsinn, dass hier immer gleich rumgepöbelt werden muss. Schade.> Würdest Du doch im echten Leben auch nicht machen.
Wenn ich herumgepöbelt hätte, hättest Du Dich nicht mehr gemeldet.
Wir sind hier in einem Technikforum, und nicht bei der dt.
Bischofskonferenz in Münster. Für Glaubensfragen bist Du dort sicher
besser aufgehoben, wenn es darum geht, gläubige Anhänger zu finden.
Hier muß man seine Behauptungen belegen; und dem verweigerst Du Dich.
Die Tage hat es mich sehr gefreut, dass ein sich ein TO trotz seiner
anfänglichen Skepsis einmal die Zeit genommen hat, um seine float bzw.
integer Berechnungen zu vergleichen. In der Ausführungszeit gab es
keinen signifikanten Unterschied.
Mam Man Man ... richtiger Popcorn tread.
Wundert mich dass hier noch kein ASM vs C krieg angefangen hat, vonwegen
Leute die ASM kennen würden wissen was Float berechnungen in einem
Controller anstellen.
m.n. schrieb:> Conny G. schrieb:>> Wahnsinn, dass hier immer gleich rumgepöbelt werden muss. Schade.>> Würdest Du doch im echten Leben auch nicht machen.>> Wenn ich herumgepöbelt hätte, hättest Du Dich nicht mehr gemeldet.> Wir sind hier in einem Technikforum, und nicht bei der dt.> Bischofskonferenz in Münster. Für Glaubensfragen bist Du dort sicher> besser aufgehoben, wenn es darum geht, gläubige Anhänger zu finden.>> Hier muß man seine Behauptungen belegen; und dem verweigerst Du Dich.>> Die Tage hat es mich sehr gefreut, dass ein sich ein TO trotz seiner> anfänglichen Skepsis einmal die Zeit genommen hat, um seine float bzw.> integer Berechnungen zu vergleichen. In der Ausführungszeit gab es> keinen signifikanten Unterschied.
Ich führte aber auch keine wissenschaftliche Diskussion, ich stellte
keine Behauptung auf, sondern äusserte eine Meinung, dass ich float auf
uC nicht präferiere, wenn ich es vermeiden kann. So, Ende jetzt.
San Lue schrieb:> Mam Man Man ... richtiger Popcorn tread.
Halte Dich zurück, dann wird es auch keiner.
Svenska schrieb:> Für ein Uni-Projekt (Roboter mit ARM7) gab mir der Dozent den Tipp,> double für alle Koordinaten zu verwenden. Das war das beste, was er> hätte tun können. Die Bewegungsformeln brauchte ich dann nur noch> hinschreiben und es tat schnell genug, was es sollte. Außerdem konnte> ich die meisten internen Werte fürs Debugging gleich auf eine reale> Größe beziehen.
Dein Fazit: es war sinnvoll und richtig mit double zu rechnen. Soweit,
so gut. Lieben Gruß an Deinen Dozenten :-)
> Wenn man nicht mit komplizierten Formeln zu tun hat, tut es> Festkommaarithmetik aber besser. Vor allem erspart man sich damit auch> Probleme mit der numerischen Stabilität.
Und jetzt auf einmal: doch besser nicht.
Dabei gehe ich davon aus, dass Du keine Probleme mit "numerischer
Stabilität" hattest, sondern diese nur als "vages Gefühl" äusserst.
Wie, bitte schön, hättest Du denn Deine double-Berechnungen mit long
oder longlong erschlagen können?
Ich gehe davon aus, dass dann die "numerische Stabilität" ein Problem
gewesen wäre.
m.n. schrieb:> Die Tage hat es mich sehr gefreut, dass ein sich ein TO trotz seiner> anfänglichen Skepsis einmal die Zeit genommen hat, um seine float bzw.> integer Berechnungen zu vergleichen. In der Ausführungszeit gab es> keinen signifikanten Unterschied.
Da verwechselst du wohl signifikant mit relevant.
Oliver
m.n. schrieb:> Dabei gehe ich davon aus, dass Du keine Probleme mit "numerischer> Stabilität" hattest, sondern diese nur als "vages Gefühl" äusserst.
Ich geh davon aus, dass er von seiner Roboter-Anwendung gesprochen hat.
In dem Moment, in dem sich Berechnungen über mehrere Formeln hinziehen
und vor allen Dingen iterativ Werte mitgeführt werden, wie das bei
Roboter-Anwendungen schon vorkommt, ist numerische Stabilität ein Thema.
Hatte ich auch schon, das sich in einer Roboter-Simulation nach der
20-ten Matrixmultiplikation die Matrix immer mehr denormalisiert hat.
Und ja, das ist ein echtes Problem. 1000 Stück aufsummierte 0.001
ergeben nun mal nicht 1.0. Und nach 360 mal sich um 1° weiterdrehen
(ausgedrückt als Matrixmultiplikation) hat man sich eben nicht exakt 1
mal im Kreis gedreht. Danach hat noch nicht mal der Einheitskreis mehr
einen Radius von 1.0
Den Tip mit double kann man verallgemeinern: Auf einem PC bzw. auf einem
ARM aufwärts, gibt es kaum einen Grund float zu verwenden.
Aber:
Das alles ist hier in diesem Beispiel kein Thema. Hier geht es um eine
Normalisierung und daraus abgeleitet einen int-Wert zu berechnen.
Numerische Stabilität ist da sicherlich kein Thema.
Das Fazit kann nur lauten: Man muss im jeweiligen Fall abwägen. So etwas
wie 'one size fits all' gibt es nun mal in der Programmierung nur höchst
selten. Genauso falsch ist es allerdings auch, generell einen
Persil-Schein für Floating Point auszustellen. Speziell dann, wenn man
nur 4 Byte float zur Verfügung hat.
Conny G. schrieb:> So, Ende jetzt.
Ich habe dann doch noch eine Frage:
Wie sieht es mit RAM-Verbrauch aus? Und Stack-Größe? Ich könnte mir
vorstellen, dass man von beidem mehr benötigt. Und da ich hier auch
schon an der Grenze war (in dem Fall 1 kB), sollte man das auch
berücksichtigen.
Hallo,
> Wie, bitte schön, hättest Du denn Deine double-Berechnungen mit long> oder longlong erschlagen können?> Ich gehe davon aus, dass dann die "numerische Stabilität" ein Problem> gewesen wäre.
sämtliche höheren Funktionen wurden mit Matlab verarbeitet (nicht meine
Baustelle), und dort war die Basiseinheit ein Millimeter, keine
Nachkommastellen. Das hätte ich auf dem Roboter auch machen können.
Was die numerische Stabilität angeht: Wenn da erstmal ein NaN drin
steht, kriegt man das so schnell nicht mehr raus. Sanity checks hatte
ich überall drin, aber das kam dann doch sehr überraschend (v.a. weil
alle Befehle relativ waren, um Funklatenzen auszugleichen).
Gruß,
Svenska
Beim TO wird diese Bilanz sogar noch schlimmer ausfallen. Denn wenn er
auf Floating Point verzichtet, fallen ihm einige Teile weg.
aus
1
floatADC_Read(..)
2
...
3
returnADCW/1024.0;
4
5
...
6
7
res=ADC_Read(0);
8
9
if(res<0.1)
10
...
wird
1
uint16_tADC_Read(..)
2
...
3
returnADCW;
4
5
res=ADC_Read(0);
6
7
if(res<102)
8
...
wodurch die komplette Konvertierung in float samt Division wegfällt und
der Vergleich zum Pipifax für den µC wird.
Aber darum gehts doch gar nicht.
Er hat den Speicher und er hat die Laufzeit.
Bitte, bitte, bitte. Lasst ab von diesen Dogmen. Floating Point hat
seine Berechtigung. Und trotzdem ist es gut, wenn man in der Lage ist,
sich davon zu lösen falls man mal den Speicher und/oder die Laufzeit
braucht.
Das hast du aber nicht mit -Os kompiliert.
Das übliche Problem solcher Tivial-Testprogramme ist, daß sich das alles
zur Compilezeit berechnen lässt. Was der Compiler auch in diesem Fall
gnadelos tut. Das erzeugte Programm besteht nur noch aus ldi- und
sts-Befehlen (die er allerdinga auch noch komplett hätte wegoptimieren
können. War ihm wahrscheinlich nur zu blöd)
Size after:
AVR Memory Usage
----------------
Device: atmega16
Program: 262 bytes (1.6% Full)
(.text + .data + .bootloader)
Data: 24 bytes (2.3% Full)
(.data + .bss + .noinit)
Oliver
>Bitte, bitte, bitte. Lasst ab von diesen Dogmen. Floating Point hat>seine Berechtigung.
@Karl Heinz
Um Himmels Wilhelm!
Natürlich hat die Fließkommaarithmetik ihre Daseinsberechtigung.
Ich wollte nur mal die Verhältnisse aufzeigen.
108/24 Takte ist ganz schön ziemlich. Vor allem wenn es, in Schleifen,
rund geht.
>Das hast du aber nicht mit -Os kompiliert.
@Oliver
Stimmt, mit Os hat er gemerkt, dass er den ganzen Code auf den Müll
schmeißen kann. Da lässt es sich schlecht testen.
Amateur schrieb:> Ich wollte nur mal die Verhältnisse aufzeigen.
Da Du das Rahmenprogramm schon hast, rechne doch bitte einmal mit
6-stell. Auflösung: 95107*900113/773115
einmal mit int32_t und einmal mit float und zähle dafür die Takte.
>Da Du das Rahmenprogramm schon hast, rechne doch bitte einmal mit>6-stell.
@m.n.
Ganz sicher nicht.
Markieren und einfügen. Ich schätze mal dass Du dann den gleichen Code
hast.
Das einzige, was Dir dann noch fehlt sind die Includes am Anfang und die
abschließende Klammer am Ende. Müsste sich eigentlich machen lassen.
doppelschwarz schrieb:> Ich habe dann doch noch eine Frage:> Wie sieht es mit RAM-Verbrauch aus? Und Stack-Größe? Ich könnte mir> vorstellen, dass man von beidem mehr benötigt. Und da ich hier auch> schon an der Grenze war (in dem Fall 1 kB), sollte man das auch> berücksichtigen.
Um ne Hausnummer zu nennen:
1
Some software metrics for the AVR binary compiled as above:
2
3
Program Size: Less than 2000 of 2048 bytes
4
5
RAM Usage:
6
Static storage : 0 bytes
7
Static stack usage : ~ 50 bytes
8
Dynamic : 0 bytes
9
Total : 40% of 128 bytes
Das ist aus folgendem Projekt:
4000 Stellen von Pi mit ATtiny2313
und verwendet folgende float-Routinen:
Addition, Subtraktion, Multiplikation, Division, lrintf, Vergleiche (<=,
>=) sowie int <--> float Konvertierungen.
Gerade der Stack-Verbrauch hängt aber auch nicht unwesentlich von der
Verschachtelungstiefe der Funktionen ab. Und natürlich auch was ISRs
schlucken (die obiges Projekt nicht verwendet).
Aber immerhin hat der ATtiny2313 gerade mal 128 Bytes an RAM.
Das Demo-Projekt zeigt also schon ganz klar, daß float kein Teufelswerk
ist.
Bei dem Code vom OP würde ich aber nicht auf float zurückgreifen, das
ist dann doch zu viel Kanonen auf arme Spatzen geschossen. Und außer
bei dem "4000 Stellen von Pi" hab ich noch nie float auf nem AVR
verwendet. Ich war selbst überrscht was geht and hatte viel mehr
Vorbehalte.
Im Rahmen der fixed-point Implementierung im avr-gcc ab 4.8 (IEC ISO/DTR
18037 aka. "Embedded C") hab ich mich etwas näher mit der Umsetzung
transzendenter Funktionen auseinandergesetzt wie z.B. sin oder arcsin.
Man muß schon höllisch auf Bereichsüberläufe aufpassen, einfach eine
Taylor-Entwicklung hinschreiben ist nicht. Taylor ist da eh komplett
unbrauchbar.
Eine fixed-point Implementierung erreicht also rasch ihre Grenzen, und
saturierte Operationen sind auch nicht wirklich hilfreich. Vielleicht
für Regler-Implementierungen, aber bei komlexeren Sachen ist's einfach
fies, wenn Addition nicht nichmal mehr assoziativ ist.
Und von Rundungsfehlern bei verschachtelten Funktionsaufrufen will ich
garnicht reden.
Manchmal sieht man auch hausbackene fixed-point Implementierungen, die
den Code mit einem Schwall von Makros überziehen. Wirklich gut wartbar
ist das auch nicht... Das sind dann eher Insel-Lösungen mit von Fall zu
Fall angepasster Genauigkeit, Stelle des Dezimalpunkts, etc.
Ist hier also wie bei vielen Sachen: 'nen Königsweg gibt's nicht, und
jeder wird nach eigener Facon glücklich -- oder unglücklich.
Amateur schrieb:>>Da Du das Rahmenprogramm schon hast, rechne doch bitte einmal mit>>6-stell.>> @m.n.> Ganz sicher nicht.Amateur schrieb:> Ich denke, abseits von allen Glaubensrichtungen ist dies, ein recht> eindeutiges Ergebnis.
Ach so!
Johann L. schrieb:> Ich war selbst überrscht was geht and hatte viel mehr Vorbehalte.
Das ist der Punkt, um den es mir geht. Aber dazu muß man erst die
Vorurteile überwinden und kann dann je nach Aufgabe sachgerecht
entscheiden.
Erst, wenn man weiß, dass in der Hölle immer gut geheizt ist, verliert
sie ihren Schrecken :-)