Forum: Compiler & IDEs _delay_ms () -> indirekte Zeitübergabe > Programm riesig


von Michael J. (jogibaer)


Angehängte Dateien:

Lesenswert?

Hallo,

als so ein Problem habe ich auch noch nicht gehabt.

in kurzer Version:

main.c -> Zeile 153

Wenn ich die Funktion so Aufrufe,
erhalte ich eine Programmgröße von 2602 Bytes

_delay_ms(1);

Lade ich mir hingegen die Zeit aus einem Array heraus,
habe ich plötzlich eine Programmgröße von 6088 Bytes

_delay_ms(message_array[2]);

Also ist das gesamte Programm ca 2,3 mal so groß.
Könnte mich mal bitte jemand über die Ursache aufklären ?

( Bitte nicht lachen oder stöhnen, das Programm ist noch seeeeeeeeeehr
im Entwurfsstadium)


Jogibär

von Johannes M. (johnny-m)


Lesenswert?

Die _delay_XX-Funktionen funktionieren nur dann korrekt, wenn sie (1) 
konstante Parameter übergeben bekommen und (2) die Optimierung 
eingeschaltet ist. Das sind inline-Assembler-Funktionen, die mit 
double-Parametern arbeiten. Und das ist sehr aufwändig und klappt nur 
dann, wenn die Berechnung nicht zur Programmlaufzeit durchgeführt werden 
muss, sondern der Compiler das übernehmen kann. Wenn man nicht-konstante 
Parameter übergibt, wird zudem die komplette float-lib eingebunden und 
bläht den Code auf, auch wenn ansonsten überhaupt keine 
Gleitkommageschichten im Programm verwendet werden. Steht aber auch in 
der AVR-libc-Doku (Zitat):
"In order for these functions to work as intended, compiler 
optimizations must be enabled, and the delay time must be an expression 
that is a known constant at compile-time. If these requirements are not 
met, the resulting delay will be much longer (and basically 
unpredictable), and applications that otherwise do not use 
floating-point calculations will experience severe code bloat by the 
floating-point library routines linked into the application."

von Simon K. (simon) Benutzerseite


Lesenswert?

Das liegt daran, dass _delay_xx Funktionen mit Floating-Point Zahlen als 
Parameter arbeiten. Wenn du also die Verzögerung zur Laufzeit berechnen 
willst, muss sichergestellt sein, dass der Mikrocontroller während 
seiner Laufzeit auch mit Floating-Point-Zahlen umgehen kann. Und genau 
dies tut er, indem er die große und langsame float-lib mit hinzulinkt.

Wenn man _delay_xx Funktionen mit zur Kompilierzeit konstanten Werten 
aufruft, ist es nicht nötig eine Floating-Point Implementierung 
beizugeben, da der Compiler es im Voraus berechnen kann.

Was möchtest du denn genau machen? Hört sich für mich eher nach einer 
Aufgabe für einen Timer an.

von Michael J. (jogibaer)


Lesenswert?

Hallo,

einfach nur ein wenig warten.

Das mit float habe ich schon fast vermutet,da
im Assemblercode auf einmal Funktionen aufgetaucht sind,

die float was weiß ich hießen.

Aber daß das gleich so einschlägt.

Dann muß wohl eine eigene Wartefunktion schreiben.
Die Wartezeiten werden mir per Protokoll übergeben.


Jogibär

von Simon K. (simon) Benutzerseite


Lesenswert?

Nein, du musst lernen dich mit den Timern auseinander zu setzen, da 
diese vermutlich für genau deinen Zweck gemacht sind.

(längere) Warteschleifen sind Mist, da der Prozessor währenddessen 
nichts anderes machen kann.

von yalu (Gast)


Lesenswert?

Ersetze mal
1
_delay_ms(message_array[2]);
durch
1
for(i=message_array[2]; i; i--)
2
  _delay_ms(1);

von Johannes M. (johnny-m)


Lesenswert?

Michael Jogwich wrote:
> Aber daß das gleich so einschlägt.
Was meinst Du, was eine Festpunkt-CPU für Verrenkungen machen muss, um 
Gleitkomma-Operationen durchführen zu können? Gerade aufgrund der 
Laufzeit- und Code-Intensität dieser Operationen auf solchen Rechnern 
versucht man doch krampfhaft, alles in Festpunkt zu erledigen (was auch 
in >90% der Fälle problemlos machbar ist).

> Dann muß wohl eine eigene Wartefunktion schreiben.
> Die Wartezeiten werden mir per Protokoll übergeben.
Die einfachste Methode (wenn es unbedingt mit den Busy-wait-Funktionen 
sein soll, andernfalls siehe Simons zweites Posting in Sachen Timer) 
ist, einfach z.B. ein _delay_ms(1) in einer Schleife aufzurufen (Bsp. 
siehe yalus Posting). Dann kannste in ms-Schritten alle möglichen 
Wartezeiten realisieren. Wenn allerdings ein Interrupt dazwischenhaut, 
ist Essig mit Genauigkeit. Wie auch in der Doku steht: Die 
_delay_XX-Funktionen sind nicht für den allgemeinen Bedarf v.a. an 
längeren Wartezeiten gedacht.

von Michael J. (jogibaer)


Lesenswert?

yalu wrote:
> Ersetze mal
>
1
> _delay_ms(message_array[2]);
2
>
> durch
>
1
> for(i=message_array[2]; i; i--)
2
>   _delay_ms(1);
3
>

Hallo,

klar das ist eine gute Idee.

Simon:

Ich weiß schon, wie ich Timer benutze.
Den hätte ich ja dann auch verwendet.
Dann lasse ich sowas immer im Hintergrund laufen.


Außerdem genügt eine Wartefunktion für diesen Zweck,
da die CPU  sowiso nichts anderes tun muß.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Michael Jogwich wrote:

> Außerdem genügt eine Wartefunktion für diesen Zweck,
> da die CPU  sowiso nichts anderes tun muß.

Dann kannst du sie mit einem Timer schlafen legen und Strom sparen. ;-)

Du hast ansonsten immer noch die Basisfunktionen, die _delay_ms()
und _delay_us() zu Grunde liegen, die heißen _delay_loop_1() und
_delay_loop_2().  Diesen übergibst du nur die Anzahl der Durchläufe
der Schleifen, die Rechnung, wie lange es dauert, musst du dann zu
Fuß machen.  Die _delay_*s-Funktionen sind ``convenience functions'',
die darauf aufsetzen und halt für die typischen Anwedungsfälle dem
Programmierer das Rechnen abnehmen und dieses in den Compiler
verlagern.

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.