Forum: Mikrocontroller und Digitale Elektronik Wartefunktion aus delay.h funktioniert nicht (ATMega16)


von Jan M. (gallig)


Lesenswert?

Hallo und erstmal Danke für dieses hilfreiche Forum, hat mir schon oft 
weitergeholfen. :)

Ich habe nun folgendes Problem, ich möchte die Wartefunktion aus der 
delay.h nutzen jedoch wartet diese Funktion nicht wirklich. Egal welchen 
Wert ich übergebe. Meine Wartefunktion sieht folgendermaßen aus:
1
#define F_CPU 3686400UL
2
3
#include <util/delay.h>
4
5
void wait_ms(int miliSec){
6
   _delay_loop_2( ((F_CPU/250)* miliSec));
7
}

Die Optimierungen sind aktiviert und ich nutze AVR-Studio mit WinAVR für 
einen ATMega16.

Also bei einem vorigen Programm hatte die Funktion funktioniert, jedoch 
habe ich dort noch einen ATMega8 genutzt. Vielleicht sollte ich noch 
erwähnen das ich in dem Programm noch die TWI-Bibliothek von P.Fleury 
nutze falls das Probleme machen könnte.

Ich bin für jeden Hinweis dankbar und hoffe das ich alle nötigen 
Informationen erwähnt habe.

MfG
Jan

von Patrick (Gast)


Lesenswert?

Hast Du es schon mal mit dem Code vom Tutorial versucht?
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Warteschleifen_.28delay.h.29

von Rolf Magnus (Gast)


Lesenswert?

Vielleicht liegt es ja daran, daß deine Berechnung nicht stimmt. 
Versuch's mal mit:
1
_delay_loop_2( ((F_CPU/4000)* miliSec));

von Falk B. (falk)


Lesenswert?

@ Rolf Magnus (Gast)

>_delay_loop_2( ((F_CPU/4000)* miliSec));

Und was soll der Unsinn? Schon mal _delay_ms() benutzt?

MfG
Falk

von Rolf Magnus (Gast)


Lesenswert?

> Und was soll der Unsinn?

Was blökst du mich deswegen an? Ich habe das vom Ursprungsposter 
übernommen und nur den fehlerhaften Faktor korrigiert.

> Schon mal _delay_ms() benutzt?

Schon mal _delay_ms() mit einem Parameter benutzt, der nicht zur 
Compilezeit bekannt ist?

von Niels H. (monarch35)


Lesenswert?

Rolf Magnus wrote:

> Schon mal _delay_ms() mit einem Parameter benutzt, der nicht zur
> Compilezeit bekannt ist?

Welcher Parameter soll das sein? F_CPU? Der sollte eigentlich gerade in 
der Compilezeit gesetzt sein. Oder vestehe ich was falsch?

Zu beachten ist bei _delay_ms(), daß abhängig von der CPU-Frequenz die 
maximale Verzögerungszeit begrenzt ist. Beispielsweise waren es bei 8Mhz 
knapp 30ms. Das Ganze ist in der avr-libc dokumentiert.

von Falk B. (falk)


Lesenswert?

@ Rolf Magnus (Gast)

>Was blökst du mich deswegen an?

Im locker bleiben, das war nicht so gemeint.

>Schon mal _delay_ms() mit einem Parameter benutzt, der nicht zur
>Compilezeit bekannt ist?

Ja, z.B. so
1
void long_delay(uint16_t ms) {
2
   for(; ms>0; ms--) _delay_ms(1);
3
}

MFG
Falk

von Rolf Magnus (Gast)


Lesenswert?

>> Schon mal _delay_ms() mit einem Parameter benutzt, der nicht zur
>> Compilezeit bekannt ist?
>
> Welcher Parameter soll das sein?

Na der eine Parameter, der an die Funktion übergeben wird. Die 
Wartezeit. Wenn der bei _delay_ms keine Compilezeitkonstante ist, wird 
die Wartezeit deutlich länger und der Code ein paar Kilobytes größer, 
weil zur Laufzeit Fließkomma-Berechnungen nötig sind.

>> Was blökst du mich deswegen an?
>
> Im locker bleiben, das war nicht so gemeint.

Wie man in den Wald hineinruft... ;-)

> void long_delay(uint16_t ms) {
>   for(; ms>0; ms--) _delay_ms(1);
> }

Ja, das ist die häufiger anzutreffende Variante. Die hat auch den 
Vorteil, daß man länger damit warten kann und daß sie vermutlich einen 
Tick genauer ist. Aber Jans Version solle ja eigentlich auch 
funktioneren.

von Niels H. (monarch35)


Lesenswert?

Rolf Magnus wrote:

>> void long_delay(uint16_t ms) {
>>   for(; ms>0; ms--) _delay_ms(1);
>> }
>
> Ja, das ist die häufiger anzutreffende Variante. Die hat auch den
> Vorteil, daß man länger damit warten kann und daß sie vermutlich einen
> Tick genauer ist. Aber Jans Version solle ja eigentlich auch
> funktioneren.

Glaub ich nicht, es sei denn, ein uint16_t kann negativ werden....was 
ich aber stark bezweifele.

von Rolf Magnus (Gast)


Lesenswert?

Ich verstehe im Moment nicht, worauf du hinaus willst. Was glaubst du 
nicht?

von Niels H. (monarch35)


Lesenswert?

ich glaube nicht, das das so funktioniert. ms ist als uint16_t definiert 
und die Bedingung in der for-schleife lautet "ms>0", d.h. er kann erst 
false werden, wenn ms negativ wird.

uint16_t ist IMO ein unsigned type (also vorzeichenlos). ms kann nicht 
negativ werden. Das oben aufgeführte Konstrukt ist meiner Meinung nach 
eine Endlosschleife.

von Patrick (Gast)


Lesenswert?

>er kann erst false werden, wenn ms negativ wird.
Und was ist mit ms == 0 ? ist das negativ?

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


Lesenswert?

Ansonsten: Standardantwort.  Nimm einen Timer.  Die werden dafür
bezahlt, sich mit Zeiten auszukennen...

von Niels H. (monarch35)


Lesenswert?

Patrick wrote:

> Und was ist mit ms == 0 ? ist das negativ?

ich glaube nicht schäm

von ozo (Gast)


Lesenswert?

ms>=0 wäre eine Endlosschleife.

von Jan M. (gallig)


Lesenswert?

Erstmal viel dank für die vielen Antworten.
Die Funktion delay_ms(int) habe ich auch schon ausprobiert, bei den 
genutzten 3,6MHz komme ich mit Int auf eine max. Wartezeit von ca. 70ms 
daher hatte ich die Funktion ähnlich wie oben beschrieben in einer 
for-Schleife mehrmals aufgerufen aber leider ohne Erfolg.

Im Debugger von AVR-Studio habe ich die ganze Sache mal simuliert und es 
funktionierte Problemlos (musste nur die TWI-Funktionen auskommentieren 
da das Programm sonst auf Antworten wartet, welche es nicht bekommen 
kann) aber auf dem µC selber scheint es so als würde die Wartefunktion 
komplett übersprungen.

Inzwischen habe ich aber alle Pausen per Timer realisiert, da ich den 
Timer0 sowieso zum auswerten von Tastatureigaben nutze und jetzt einfach 
einen Zähler inkrementieren lasse. Habe das Problem also einfach 
umgangen, dennoch wundert es mich das diese Funktion nicht 
erwartungsgemäß arbeitet.

MfG
Jan

von Karl H. (kbuchegg)


Lesenswert?

Jan Masak wrote:

> einen Zähler inkrementieren lasse. Habe das Problem also einfach
> umgangen, dennoch wundert es mich das diese Funktion nicht
> erwartungsgemäß arbeitet.

Wenn die delay Funktionen nicht erwartungsgemäss funktionieren,
dann gibt es dafür 4 Gründe
* die angegebene Zeit ist zu gross und fällt ueber das vorgebenen
  Limit
* die tatsächliche Taktfrequenz des µC stimmt nicht mit der im
  Pgm angegebenen überein. Häufiger Fehler: Der µC läuft immer
  noch auf internem Oszillator und nicht auf externem Quarz.
  Das Stichwort dazu lautet: Fusebits
* Der Optimizer im Compiler ist nicht eingeschaltet.
* die _delay_xx Funktionen werden durch Fehler in der Programm-
  logik nicht aufgerufen

Wenn diese 4 Fehlerquellen ausgeschlossen werden, dann funktionieren
die Aufrufe einwandfrei

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


Lesenswert?

Jan Masak wrote:

> daher hatte ich die Funktion ähnlich wie oben beschrieben in einer
> for-Schleife mehrmals aufgerufen aber leider ohne Erfolg.

Dann musst du schon den Code posten, der nicht geht.  Ich habe auf
jeden Fall auf so'ne Weise schon LED-Blinker zum Ausprobieren
gehackt.

von Niels H. (monarch35)


Lesenswert?

Jan Masak wrote:

> Erstmal viel dank für die vielen Antworten.
> Die Funktion delay_ms(int) habe ich auch schon ausprobiert, bei den

Auf die Gefahr hin, noch einen unnötigen Kommentar abzugeben: wir 
sprachen von "_delay_ms()", nicht "delay_ms()".

Ich habe diese Funktion bereits auf verschiedenen Plattformen (atm8, 
atm128, atm64) bei verschiedenen Taktfrequenzen bisher problemlos 
einsetzen können. In der avr-libc ist diese Funktion nichts weiter als 
ein Makro, die zwei verschachtelte Schleifen (auf basis von 
_delay_loop_2()) implementiert. Das einzige, was hier schiefgehen kann, 
ist entweder daß die maximale Verzögerung überschritten wird, oder der 
optimizer im compiler erkennt, daß es sich hier um scheinbar unnötige 
Schleifen handelt, in denen nichts passiert und optimiert sie raus.

Wenn du beides Ausschliessen kannst (dürfte im lst-file leicht zu 
erkennen sein) liegt dein Fehler vermutlich GANZ woanders.

von Rolf Magnus (Gast)


Lesenswert?

> In der avr-libc ist diese Funktion nichts weiter als ein Makro,

Nein, es ist tatsächlich eine Funktion.

> oder der optimizer im compiler erkennt,daß es sich hier um scheinbar
> unnötige Schleifen handelt, in denen nichts passiert und optimiert sie
> raus.

Die Funktion ist so implementiert, daß das nicht passieren kann. Sie ist 
sogar auf den Optimizer angewiesen, um korrekt zu funktionieren.

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.