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.
Deine ganzen FLOAT Berechnungen blähen deinen Code auf. Vergiss Float und mach direkt Festkomma mit Ints. gruß cyblord
Die float-Library ist riesig:
1 | return (((float) ADCW)/1024); // auf 5 Volt normieren |
Baue es um, das zu vermeiden und es sind nur noch 200 Bytes :-)
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 | float ADC_Read(uint8_t chan){ //Kanal 0 bis 7 |
3 | |
4 | static uint8_t mux; |
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 | return ADCW; //!! der ist jetzt 1024 = 10 bits nach links verschoben |
11 | |
12 | }else{ |
13 | mux = chan & 0x07; // Beim Kanalwechsel: |
14 | ADMUX = ( ADMUX & 0b11111000) | mux; // Kanal neu |
15 | ADC_Read(mux); // 1 Dummy-Readout |
16 | return (ADC_Read(mux)); // gültige Messung durchführen |
17 | }
|
18 | }
|
und änderst dann alle Rechnungen
1 | }else{ |
2 | OCR2B = (unsigned char)(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.
:
Bearbeitet durch User
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.
Kai S. , zeige uns doch bitte Dein Makefile, das steht alles drin..
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
:
Bearbeitet durch User
Welches AVR-Studio benutzt Du denn? In den Compileroptionen muß ein -lm stehen. Die Optimierung sollte -Os sein.
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 = (unsigned char)(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.
:
Bearbeitet durch User
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.
Machs in Asm... Macht die Sache deutlich kleiner, schneller, einfacher. Irgendwelche Compileroptionen gibts auch nicht zu beachten.
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.
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
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
Ich habe mal das alte Studio 4 angeworfen und folgendes Codestückchen durchlaufen lassen. Settings: Für ATMega16; Os; libm
1 | uint32_t IRes; |
2 | uint32_t IAccu; |
3 | uint32_t IAdd; |
4 | double FRes; |
5 | double FAccu; |
6 | double FAdd; |
7 | |
8 | int main ( void ) { |
9 | IAccu = 1000; |
10 | IAdd = 1000; |
11 | FAccu = 1000.0; |
12 | FAdd = 1000.0; |
13 | // Cycle Counter |
14 | IRes = IAccu + IAdd; // Bei Bearbeitung dieser Zeile 24 Takte |
15 | FRes = FAccu + FAdd; // Bei Bearbeitung dieser Zeile 108 Takte |
16 | |
17 | if ( IRes == 12 ) IAccu = 0; // Damit Os nicht |
18 | if ( FRes == 12.0 )FAccu = 0.0; // alles herausschmeißt |
19 | |
20 | IRes += IAccu; // Damit Os nicht |
21 | FRes += FAccu; // alles herausschmeißt |
Ich denke, abseits von allen Glaubensrichtungen ist dies, ein recht eindeutiges Ergebnis. Dieses "Nichts" belegt ca. 1024 Bytes...
:
Bearbeitet durch User
Beim TO wird diese Bilanz sogar noch schlimmer ausfallen. Denn wenn er auf Floating Point verzichtet, fallen ihm einige Teile weg. aus
1 | float ADC_Read( .. ) |
2 | ...
|
3 | return ADCW / 1024.0; |
4 | |
5 | ...
|
6 | |
7 | res = ADC_Read(0); |
8 | |
9 | if( res < 0.1 ) |
10 | ...
|
wird
1 | uint16_t ADC_Read( .. ) |
2 | ...
|
3 | return ADCW; |
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.
:
Bearbeitet durch User
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
:
Bearbeitet durch User
>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 :-)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.