Forum: Mikrocontroller und Digitale Elektronik Zeitverzögerung in C


von mc t. (mct3)


Lesenswert?

Hallo.

Ich würde gerne wissen, wie viel Speicherplatz eine delay_ms_(__); 
verbraucht...
Ich habe mal ein Programm mit vielen solcher geschrieben, aber beim 
ATmega16 war irgendwann der Speicher alle...
Da ich für mein Programm warscheinlich ein paar (mehr) Verzögerungen 
brauche, habe ich Befürchtungen, dass nicht alle delays reinpassen.
Gibts sonst noch vergleichbare kleinere Zeitverzögerungen???
Wie viel Speicher verbraucht eine delay-funktion?

von Kali (Gast)


Lesenswert?

Das kannst Du im Assemblerlisting leicht selbst sehen.

von Karl H. (kbuchegg)


Lesenswert?

Probiers einfach aus.
Mach ein Programm, compilier es. Im AVR Studio wird dir danach der 
Speicherverbrauch angezeigt.
Dann machst du einen _delay_ms rein und compilierst wieder. Aus dem 
Vergleich der Zahlen von jetzt und vorher kannst du ermitteln wieviele 
Bytes durch den _delay_ms verbraucht wurden.

Aber ein einzelnder _delay_ms wird nicht viel Speicher verbrauchen. Aus 
dem Bauch heraus: vielleicht 10 Bytes Flash, +- ein paar Zerquetschte.

von Paul H. (powl)


Lesenswert?

naja teste es doch aus :) mach ein neues programm nur mit einem delay 
und schau um wie viel es größer ist als ein leeres programm. du kannst 
das delay ja auch in eine funktion packen, die du immer wieder aufrufst, 
oder du realisierst es mit nem timer. das dürfte dann fast gar keinen 
platz verbrauchen

von Paul H. (powl)


Lesenswert?

hehe da war karlheinz schneller als ich

von Klaus der 3. (Gast)


Lesenswert?

Oftmals ist/war(?) auch der Fehler eine Variable für die Delay-Funktion 
zu benutzen. Das darf/durfte(?) man nicht...das führte auch immer dazu 
dass der Code unheimlich groß wurde.

Grüße

von Klaus der 3. (Gast)


Lesenswert?

Wenn ich mal kurz ein Minimalprogramm mit einer _delay_ms(100) 
reinmache, dann sind es 214 Bytes.
Mach ich eine _delay_ms(i) (also über ne Variable) dann sind es 3876 
Bytes.

Grüße

von Thomas E. (thomase)


Lesenswert?

Klaus der 3. schrieb:
> Mach ich eine _delay_ms(i) (also über ne Variable) dann sind es 3876
> Bytes.

Das ist jetzt totaler Müll.

Die _delay_ms kann nicht mit einer Variablen aufgerufen werden.

Geht mit Variable nur so:

void Delay (char nDelay)
{
   (for char nInd = 0; nInd < nDelay; nInd++) _delay_ms(1);
}


mfg.

von Klaus der 3. (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> Das ist jetzt totaler Müll.

Les mal oben nach...nicht ich bin der Fragensteller!
Ich habe nur dieses Beispiel gebracht um es auszuschließen dass es so 
gemacht wird ;-)

von Klaus der 3. (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> (for char nInd = 0; nInd < nDelay; nInd++) _delay_ms(1);

Die Klammer der For-Schleife sitzt übrigens falsch.

von Thomas E. (thomase)


Lesenswert?

Klaus der 3. schrieb:
> Ich habe nur dieses Beispiel gebracht um es auszuschließen dass es so
> gemacht wird ;-)

Ach so.

Aber Müll ist es trotzdem.

Klaus der 3. schrieb:
> Die Klammer der For-Schleife sitzt übrigens falsch.

Mach' ich immer so, um die Aufmerksamkeit der anderen zu testen.

mfg.

von Micha (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> Die _delay_ms kann nicht mit einer Variablen aufgerufen werden.
Warum nicht?

> Geht mit Variable nur so:
> void Delay (char nDelay)
> {
>    (for char nInd = 0; nInd < nDelay; nInd++) _delay_ms(1);
> }
Wie genau ist die Zeit dann noch?

von Micha (Gast)


Lesenswert?

Vergesst die erste Frage: 
Beitrag "Re: _delay_ms"

Die zweite stellt sich aber trotzdem.

von Klaus der 3. (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> Ach so.
> Aber Müll ist es trotzdem.

Deshalb hab ich es ja auch als Beispiel gebracht ;-)
Ist ein altbekannter Fehler der gemacht wird.


Thomas Eckmann schrieb:
> Mach' ich immer so, um die Aufmerksamkeit der anderen zu testen.

Coole Methode...allerdings sollte man dann auch so "Aufmerksam" sein und 
2 nebeneinander liegende Posts lesen!


Grüße

von Klaus der 3. (Gast)


Lesenswert?

Micha schrieb:
> Wie genau ist die Zeit dann noch?

Man könnte sie vielleicht noch als inline definieren, dann könnte man 
sich die Zeit für den Funktionseinsprung/Registersicherung usw. sparen.

von Thomas E. (thomase)


Lesenswert?

Micha schrieb:
> Warum nicht?

Weil das keine Funktion, sondern ein Makro ist.

Micha schrieb:
> Wie genau ist die Zeit dann noch?

Ich weiss jetzt nicht wieviele Takte eine For-Schleife pro "Umdrehung" 
genau verbraucht.

Aber ein Inkrement und ein Compare/Jump sind nur ein paar Takte.

mfg.

von Michael A. (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> Die _delay_ms kann nicht mit einer Variablen aufgerufen werden.

Da irrst du. Oder welche Delay-Bibliothek benutzt du?

Thomas Eckmann schrieb:
> Mach' ich immer so, um die Aufmerksamkeit der anderen zu testen.

Bist du Lehrer?

von Thomas E. (thomase)


Lesenswert?

Michael A. schrieb:
> Da irrst du.

Michael A. schrieb:
> Bist du Lehrer?

Weder das eine noch das andere.
Das war auch meine erste For-Schleife. Kann ja mal vorkommen.

>Oder welche Delay-Bibliothek benutzt du?

util/delay.h

mfg.

von Dominik Honnef (Gast)


Lesenswert?

> \note In order for these functions to work as intended, compiler
>     optimizations <em>must</em> be enabled, and the delay time
>     <em>must</em> 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.

Und daher keine variablen _delay_* :)

von a no nym (Gast)


Lesenswert?

Weil es reinpasst und ich mir die Frage schon länger stelle: Warum hat 
man nicht die eigentliche Delayfunktion in einer Hilfsfunktion mit 
for-Schleife gekapselt um die Verwendung von Variablen zu ermöglichen?

Also statt der aktuellen Funktion (bzw. dem Makro, kompliziertes Zeug) 
sowas
1
#define _internal_delay_ms (...irgendwas...) //don't use this directly. delay must be a constant
2
3
void delay_ms (int delay) //use this in your program
4
{
5
for(;int;int--)
6
  _internal_delay_ms(1);
7
}

Eventuell noch attribute always_inline um den Overhead vom Aufruf zu 
vermeiden.

von a no nym (Gast)


Lesenswert?

Grmpf. Es ist schon spät.

-for(;int;int--)
+for(;delay;delay--)

Gute Nacht.

von MaWin (Gast)


Lesenswert?

Daher gibt's nur eins: Vergesst das leidige delay.
Ihr könnte in dem Programm zu der Zeit sowieso nichts anderes machen, 
lange Delays sind also sowieso ein Problem.

Der vernünftige Weg ist es, an bestimmten Stellen (eigentlich an einer, 
in der Hauptscheife des Programms (alternativ: In einer 
Interrupt-Routine die von eben so einem Timer regelmässig aufgerufen 
wird)) den Timer abzufragen, und zu prüfen, ob es "schon Zeit ist".

Dadurch kann man Programmieren ohne Instruktionen zählen zu müssen, es 
gibt eine Hardwarezeitbasis nach der man sich richten kann, und es 
entsteht ein reaktives Programm, weil es eben nicht an einer Stelle 
hängt, sondern "wenn noch nicht Zeit ist" sich um alles andere kümmern 
kann.

Der Vorteil ist, daß man sich nicht um Unzerbrechungen im Codedurchlauf 
Gedanken machen muß (wenn man nicht anderswo Interrupts verwendet).

von Oliver J. (skriptkiddy)


Lesenswert?

Thomas Eckmann schrieb:
> Die _delay_ms kann nicht mit einer Variablen aufgerufen werden.
Versuchs mal. Und du wirst merken, dass es nämlich doch geht. Allerdings 
zu dem Preis, dass die Codegröße ins Unermessliche anwächst.

Gruß Skriptkiddy

von Karl H. (kbuchegg)


Lesenswert?

Skript Kiddy schrieb:
> Thomas Eckmann schrieb:
>> Die _delay_ms kann nicht mit einer Variablen aufgerufen werden.
> Versuchs mal. Und du wirst merken, dass es nämlich doch geht. Allerdings
> zu dem Preis, dass die Codegröße ins Unermessliche anwächst.

Nun ja. Das wär noch gar nicht mal so schlimm.
Das eigentliche Problem ist allerdings: Die Zeiten stimmen hinten und 
vorne nicht. Und dieses Problem ist schwerwiegend: Denn das 'Setup' 
welches berechnet, wieviele Durchgänge durch die Verzögerungsschleife 
notwendig ist, braucht selber Zeit die leider nicht konstant ist. D.h. 
man hat eine relativ hohe Untergrenze, unter die man prinzipiell bei der 
Verzögerung nicht kommen kann und der Jitter in der tatsächlichen 
Wartezeit ist hoch.

_delay_ms bzw _delay_us funktionieren nun mal nur dann 
zufriedenstellend, wenn der Compiler schon während des Übersetzens 
ausrechnen kann, wieviele Wiederholungen der zentralen Warteschleife 
notwenig sind und dieses Ergebnis dann auch direkt in Code umsetzt.

von Karl H. (kbuchegg)


Lesenswert?

a no nym schrieb:
> Weil es reinpasst und ich mir die Frage schon länger stelle: Warum hat
> man nicht die eigentliche Delayfunktion in einer Hilfsfunktion mit
> for-Schleife gekapselt um die Verwendung von Variablen zu ermöglichen?

Weil dein präsentierter Code impliziert, dass du niemals bei _delay_ms 
eine feinere Auflösung als 1 Millisekunde brauchst.

Den Zeitbedarf, den das Schleifenkonstrukt selber verbraucht hätte man 
noch berücksichtigen können. Allerdings impliziert diese nicht-0-Zeit 
auch, dass es eine Untergrenze gibt, unter die du dann zb mit _delay_ms 
nicht mehr kommen kannst, während _delay_ms(0.9) absolut legal ist und 
auch sinnvollen Code produziert.

von Klaus W. (mfgkw)


Lesenswert?

Die Genauigkeit von _delay_ms() kann man aber sowieso nicht unbedingt 
ernst nehmen, weil sie mehr oder weniger geschickt eine bestimmte Anzahl 
an Takten verbrät.

Das kann einer gewünschten Zeit entsprechen, muß aber nicht.
Und zwar aus dem Grund, daß die Funktion nicht merkt, wenn sie 
unterbrochen wird.
Sie ist so kalibriert, daß es ohne Interrupts passt. Hat man aber 
Interrupts, die (beispielsweise und meist hoffentlich übertrieben) 50% 
Last erzeugen, dauert ein _delay_ms(1) auch mal 2 Millisekunden.
Bei 90% Last in den ISR dann entsprechend 10 Millisekunden...

von a no nym (Gast)


Lesenswert?

MaWin schrieb:
> Der vernünftige Weg ist es, an bestimmten Stellen (eigentlich an einer,
> in der Hauptscheife des Programms (alternativ: In einer
> Interrupt-Routine die von eben so einem Timer regelmässig aufgerufen
> wird)) den Timer abzufragen, und zu prüfen, ob es "schon Zeit ist".
Jain. Wenn man bzw. der µP sowieso nichts anderes zu tun hat (das soll 
bei einfachen Programmen vorkommen) kann man auch delay verwenden. Ich 
hatte mal einen Prof der auch krampfhaft (oder krankhaft?) auf die 
Verwendung von Timern bestand, macht einfache Programme nur unnötig 
kompliziert und ist sinnloser Aufwand. Bei komplexeren Sachen ist ein 
Timer natürlich notwendig.

Karl Heinz Buchegger schrieb:
> a no nym schrieb:
>> Weil es reinpasst und ich mir die Frage schon länger stelle: Warum hat
>> man nicht die eigentliche Delayfunktion in einer Hilfsfunktion mit
>> for-Schleife gekapselt um die Verwendung von Variablen zu ermöglichen?
>
> Weil dein präsentierter Code impliziert, dass du niemals bei _delay_ms
> eine feinere Auflösung als 1 Millisekunde brauchst.
>
> Den Zeitbedarf, den das Schleifenkonstrukt selber verbraucht hätte man
> noch berücksichtigen können. Allerdings impliziert diese nicht-0-Zeit
> auch, dass es eine Untergrenze gibt, unter die du dann zb mit _delay_ms
> nicht mehr kommen kannst, während _delay_ms(0.9) absolut legal ist und
> auch sinnvollen Code produziert.

Gut, ich hatte jetzt vergessen bzw. war mir nicht im klaren dass 
_delay_ms mit float zurechtkommt. Für feinere Auflösungen gibt es doch 
aber _delay_µs oder? Demnach könnte man für einfache Zwecke die 
(vielleicht nicht ganz genaue) Funktion delay verwenden welche auch 
Variablen akzeptiert und für genauere Auflösung/Genauigkeit wie bisher 
auf die Makros zurückgreifen welche nur mit Konstanten funktionieren.

Eigentlich ist die Diskussion ja überflüssig (eine for-Schleife kann man 
sich bei Bedarf selber einbauen), aber wenn ich sehe wie oft diese 
Frage hier kommt...

Klaus Wachtler schrieb:
> (Interruptproblem bei delay)
Das ist wohl wahr.

von Rolf Magnus (Gast)


Lesenswert?

a no nym schrieb:
> Wenn man bzw. der µP sowieso nichts anderes zu tun hat (das soll
> bei einfachen Programmen vorkommen) kann man auch delay verwenden.

Sofern eben die Genauigkeit keine so große Rolle spielt.

> Ich hatte mal einen Prof der auch krampfhaft (oder krankhaft?) auf die
> Verwendung von Timern bestand, macht einfache Programme nur unnötig
> kompliziert und ist sinnloser Aufwand. Bei komplexeren Sachen ist ein
> Timer natürlich notwendig.

Naja, eine Timer-ISR, die ein Flag setzt, ist ja nun auch nicht gerade 
schwarze Magie.

von Michael A. (Gast)


Lesenswert?

Dominik Honnef schrieb:
> Und daher keine variablen _delay_* :)

Dann lies mal genauer. Bei variablem Delay wird die Floatingpoint 
Bibliothek eingebunden und die Vorlaufzeit durch die Berechnung der 
Float Variablen, d.h. bevor die eigentliche Delay-Schleife läuft, wird 
nicht kompensiert. Das führt zu einem Delay entsprechend der Rechenzeit.
Man kann sogar die Rechenzeit bestimmen und beim Aufruf die im Parameter 
angegeben Delayzeit entsprechend korrigieren ;-)

Pauschalaussagen wie "geht nicht" sind einfach Unfug.

von Rolf Magnus (Gast)


Lesenswert?

Michael A. schrieb:
> Man kann sogar die Rechenzeit bestimmen und beim Aufruf die im Parameter
> angegeben Delayzeit entsprechend korrigieren ;-)

Da die aber stark vom übergebenen Wert abhängt, wird es schwierig, das 
zu bestimmen. Man könnte aber natürlich mit einem Timer...

von Klaus W. (mfgkw)


Lesenswert?

Rolf Magnus schrieb:
> Man könnte aber natürlich mit einem Timer...

Spalter!

von a no nym (Gast)


Lesenswert?

Rolf Magnus schrieb:
> a no nym schrieb:
>> Wenn man bzw. der µP sowieso nichts anderes zu tun hat (das soll
>> bei einfachen Programmen vorkommen) kann man auch delay verwenden.
>
> Sofern eben die Genauigkeit keine so große Rolle spielt.
Wieso? Man kann delays durchaus auf einen Takt genau berechnen bzw. 
programmieren (Interruptproblematik mal außer acht gelassen, simples 
Programm ohne Interrupts z.B.), ob die C-Bibliotheken das können ist 
dann eine andere Frage.
>
>> Ich hatte mal einen Prof der auch krampfhaft (oder krankhaft?) auf die
>> Verwendung von Timern bestand, macht einfache Programme nur unnötig
>> kompliziert und ist sinnloser Aufwand. Bei komplexeren Sachen ist ein
>> Timer natürlich notwendig.
>
> Naja, eine Timer-ISR, die ein Flag setzt, ist ja nun auch nicht gerade
> schwarze Magie.
Nun, für Programmier- und "µC-Anfänger" wie man sie z.B. an der Uni 
findet ist anfänglich alles was mit/in/ um einen µC passiert schwarze 
Magie, da sind Timer für den Anfang nur unnötig kompliziert.

von Rolf Magnus (Gast)


Lesenswert?

a no nym schrieb:
> Rolf Magnus schrieb:
>> a no nym schrieb:
>>> Wenn man bzw. der µP sowieso nichts anderes zu tun hat (das soll
>>> bei einfachen Programmen vorkommen) kann man auch delay verwenden.
>>
>> Sofern eben die Genauigkeit keine so große Rolle spielt.
> Wieso? Man kann delays durchaus auf einen Takt genau berechnen bzw.
> programmieren (Interruptproblematik mal außer acht gelassen, simples
> Programm ohne Interrupts z.B.), ob die C-Bibliotheken das können ist
> dann eine andere Frage.

Ich dachte da mehr an periodische Vorgänge. Da zum Delay immer auch noch 
die Zeit für den eigentlichen Algorithmus dazugerechnet werden muß, paßt 
es da nie. Denk z.B. mal an eine Uhr.

>>> Ich hatte mal einen Prof der auch krampfhaft (oder krankhaft?) auf die
>>> Verwendung von Timern bestand, macht einfache Programme nur unnötig
>>> kompliziert und ist sinnloser Aufwand. Bei komplexeren Sachen ist ein
>>> Timer natürlich notwendig.
>>
>> Naja, eine Timer-ISR, die ein Flag setzt, ist ja nun auch nicht gerade
>> schwarze Magie.
> Nun, für Programmier- und "µC-Anfänger" wie man sie z.B. an der Uni
> findet ist anfänglich alles was mit/in/ um einen µC passiert schwarze
> Magie, da sind Timer für den Anfang nur unnötig kompliziert.

Klar, für den blutigen Anfänger. Aber wenn der mal ein paar Ports 
getoggelt und den ADC eingelesent hat, dann ist es bald auch Zeit, sich 
mal mit Interrupts zu beschäftigen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

a no nym schrieb:
> Nun, für Programmier- und "µC-Anfänger" wie man sie z.B. an der Uni
> findet ist anfänglich alles was mit/in/ um einen µC passiert schwarze
> Magie, da sind Timer für den Anfang nur unnötig kompliziert.

Lies mal die Quellen und das Kleingedruckte von _delay_*.
Ist das Einfach?

Und seit wann ist "an der Uni" sein eine Ausrede vor komplizierten 
Dingen???

von a no nym (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Ich dachte da mehr an periodische Vorgänge. Da zum Delay immer auch noch
> die Zeit für den eigentlichen Algorithmus dazugerechnet werden muß, paßt
> es da nie. Denk z.B. mal an eine Uhr.
Ach ok, so war das gemeint. Da hast du wohl recht. Wobei wohl kaum 
jemand eine Uhr mit delays (und ohne Timer) basteln würde...


> Klar, für den blutigen Anfänger. Aber wenn der mal ein paar Ports
> getoggelt und den ADC eingelesent hat, dann ist es bald auch Zeit, sich
> mal mit Interrupts zu beschäftigen.
Stimmt. Trotzdem, für irgendwelches "Kleinzeug". z.B. einen tiny der 
eine Fernbedienung simuliert bei der immer die gleichen Tasten gedrückt 
werden (anschalten, Quellenauswahl, ...) kann man imho beruhigt delays 
nehmen. Was natürlich kein Vorwand ist sich nicht mit Timern zu 
befassen!

von a no nym (Gast)


Lesenswert?

Johann L. schrieb:
> a no nym schrieb:
>> Nun, für Programmier- und "µC-Anfänger" wie man sie z.B. an der Uni
>> findet ist anfänglich alles was mit/in/ um einen µC passiert schwarze
>> Magie, da sind Timer für den Anfang nur unnötig kompliziert.
>
> Lies mal die Quellen und das Kleingedruckte von _delay_*.
> Ist das Einfach?
Es sollte es imho sein... ;-)

> Und seit wann ist "an der Uni" sein eine Ausrede vor komplizierten
> Dingen???
Natürlich muss man sich auch mit Timern befassen, aber vielleicht nicht 
sofort. Für das erste "Hallo Welt" = blinkende LED tut es auch ein 
delay, ggf. mit Hinweis(en) vom Prof was man da beachten muss, denn da 
hat man schon genug mit DDR und PORT und Bit setzen usw. zu tun. Später 
kommen natürlich Timer usw.

von a no nym (Gast)


Lesenswert?

(Ich kann übrigens mit Timern umgehen, nicht das einer so rum denkt. Ein 
Datenblatt muss aber sein, auswendig kenne ich die Register vom AVR 
nicht.)

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.