Hallo, es gibt ja in der <util/delay.h> die Zeitfunktion "_delay_ms(int)", weiß jemand wie genau man sich auf die verlassen kann? Bzw ist es wenn man es genau braucht sinnvoller das selbst über einen Timer oder so zu programmieren? und gibt es zu fällig auch eine Funktion für µ-Sekunden? Also irgendwas in der form "_delay_us(int)" oder so? vielen Dank schon einmal im Vorraus MFG Tom
" Bzw ist es wenn man es genau braucht sinnvoller das selbst über einen Timer oder so zu programmieren? " Es ist immer sinnvoller selbst zu programmieren, dann weiss man was das Programm macht. Dann kann man zB auch vorhersagen wie lange das Delay dauern wird. Du könntest mal den Simulator + Stopuhr befragen, wie lange das delay dauert.
@willivonbienemaya " Bzw ist es wenn man es genau braucht sinnvoller das selbst über einen Timer oder so zu programmieren? " >Es ist immer sinnvoller selbst zu programmieren, dann weiss man was das >Programm macht. Dann kann man zB auch vorhersagen wie lange das Delay Quark. Lesen bildet. In der Doku der libc vom AVR ist alles drin. MfG Falk
Du kannst doch einfach selbst eine Fkt definieren und die gewünschte Zeit selbst programmieren : void Delay(int del) { int d; for (d=0; d<=del; d++) { } } Die ist von deiner Taktfrequenz abhängig Viel Glück Mfg Andy
Wenn Du in die Dokumentation der AVR-libc geschaut hättest, dann wüsstest Du, dass es eine _delay_us()-Funktion gibt. Diese Funktionen sind aber nur dann sinnvoll einsetzbar, wenn konstante Werte (die zur Compile-Zeit bekannt sind) übergeben werden, da der Compiler (weitere Voraussetzung: Optimierung aktiviert!) die eigentlichen Zählschleifen direkt berechnen kann. Und in dem Falle sind diese Funktionen sehr genau, allerdings auch nur dann, wenn man im Makefile (oder im AVRStudio) die korrekte CPU-Taktfrequenz angegeben hat. Die _delay_xx()-Funktionen sind allerdings begrenzt, d.h. in Abhängigkeit von der CPU-Frequenz sind nur eingeschränkte Verzögerungszeiten möglich (bei _delay_ms() max. 262.14ms/F_CPU[MHz] und bei _delay_us() max. 768µs/F_CPU[MHz]). Die Funktionen sind nur sinnvoll einsetzbar, wenn es um kurze Verzögerungen geht. Bei längeren und flexiblen Zeiten ist ein Timer das einzig wahre.
@Andy:
Wenn meine lib Funktionen zur Verfügung stellt, die reproduzierbar und
ohne viel Rumprobiererei die erforderlichen Zeiten präzise erzeugen
können, dann werd ich sicher nicht mit irgendwelchen C-Zählschleifen
verwenden, die man erst mal durch experimentelles Rumprobieren mit
unterschiedlichen Zahlenwerten "einstellen" muss. Und das wäre bei
Deinem Vorschlag der Fall.
> Viel Glück
Das würde er dabei brauchen... Und auch viel Zeit.
Tach ich bräuchte ein mal 2000 ms ( wo es ja mit der _delay_ms() funktion eher düster aussieht) und einmal bräuchte ich 400 µs des müsste doch eigentlich recht problem los über "_delay_ms(0.4);" gehen oder?
@Tom >ich bräuchte ein mal 2000 ms ( wo es ja mit der _delay_ms() funktion >eher düster aussieht) und einmal bräuchte ich 400 µs des müsste doch >eigentlich recht problem los über "_delay_ms(0.4);" gehen oder? Ist es sooooschwer mal die Doku der libc zu lesen? MfG Falk
> void Delay(int del) { > int d; > for (d=0; d<=del; d++) { } > } > > Die ist von deiner Taktfrequenz abhängig Eher von der Intelligenz des Compilers, diesen Code komplett über Bord zu werfen, weil aus seiner Sicht völlig nutzlos.
Die Delay-Funktionen sind grundsätzlich ungenau. Sie dienen nur dazu, worst-case Zeiten einzuhalten, z.B. eine notwendige minimale Wartezeit. Jeder Interrupt verlängert natürlich das Delay um seine Ausführungszeit. Und der Code vor und nach dem Delay braucht ja auch Zeit für seine Ausführung. Nur mit einem der HW-Timer kann man genaue Zeiten erzielen. Peter
_delay_ms()?? was muß jetzt in der Klammer stehen um z.b. 5ms Verzögerung zu erhalten??? Gruß
Hallo Ulrich.. In der Lib. steht aber: max. 262.14ms/F_CPU[MHz] verstehe ich da etwas falsch ??????? Gruß
Wenn du einen freien Timer hast, dann programmier die Funtkion selbst. Vorallem weist du auch wie genau deine Funktion ist. z.B Takt 8MHz->Teiler Timer0=64
1 | void WAIT_ms(int ms) |
2 | {
|
3 | int i; |
4 | TCCR0B=4; |
5 | for(i=0;i<=ms;i++) |
6 | {
|
7 | TCN01=0; |
8 | while(TCNT0<125); |
9 | }
|
10 | TCCR0B=0; |
11 | }
|
> max. 262.14ms/F_CPU[MHz] Genau. > verstehe ich da etwas falsch ??????? Weiß nicht. Wie verstehst du es denn?
Na die maximale Wartezeit ist 262,14ms geteilt durch F_CPU in Megahertz. Bei einem Takt von 1Mhz kannst du mit der Funktion also maximal 262,14ms warten, bei 8Mhz nur noch 32,768ms.
Wie Peter D. oben schon schrieb sind die _delay-Funktionen ungenau wenn Interrupts aktiviert sind. Wenn du's genau haben willst musst du den globalen Interrupt (SREG &= ~_BV(I);) deaktivieren. Dann sind sie so genau wie deine Taktfrequenz. Allerdings wartet dann ALLES. Also längere Zeiten, wie oben erwähnt, über Timer-Interrupts realisieren!
Guten Tag... Ah, jetzt ja.... Bei 8MHz bis max. 32ms benutzen. Dann stimmt die Zahl in der Klammer mit der Verzögerungszeit überein. Habe das im Simulator von Studio4 mal laufenlassen. Alles darüber hinaus stimmt dann nicht. VIIIIIIIIIIIEEEEEEEEEEELEN Dank für die Hilfe. Klasse Forum Ein schönes Restwochenende gewünscht.
Sonic wrote: > OK, viele Wege führen nach Rom ... > cli(); macht auch nix anderes. Aber woll ! cli() braucht 4 Bytes weniger und garantiert, daß Interrupts sofort gesperrt sind. Bei IN+ANDI+OUT kann aber ein Interupt noch dahinter kommen, bevor das Löschen des Bits wirksam ist und schon isses wieder gesetzt. D.h. die Anweisung kann fehlschlagen. Außerdem ergibt I einen Compilerfehler, es muß SREG_I heißen. Peter
Jo, stimmt natürlich mit dem SREG_I. Genaugenommen sind's 2 Zyklen, die der cli(); weniger braucht, nämlich einen. SREG &= ~_BV(SREG_I); braucht drei.
Warum wird eigentlich für's SREG nicht derselbe Code wie bei den anderen I/O-Registern (sowas wie cbi SREG, SREG_I) erzeugt?
+0000005F: 94F8 CLI Global Interrupt Disable Das erzeugt er bei cli(); +00000060: B78F IN R24,0x3F In from I/O location +00000061: 778F ANDI R24,0x7F Logical AND with immediate +00000062: BF8F OUT 0x3F,R24 Out to I/O location und das bei SREG &= ~_BV(SREG_I); Ich schätze mal damit dem Programmierer etwas mehr Flexibilität bleibt, vielleicht will man das ja mal per SREG &= ~_BV(SREG_I); machen? Für cli(); muss auch die <avr/interrupt.h> eingebunden werden.
> sowas wie cbi SREG, SREG_I ... SREG ist im oberen Teil des I/O-Adressraums und kann daher nicht bitorientiert angesprochen werden. Damit das SREg trotzdem schnell manipuliert werden kann, enthält der ASM-Befehlssatz die Befehle SEx und CLx, wobei x für das Bit im SREG steht, beim Interrupt-Bit eben SEI und CLI, beim Carry SEC und CLC. Auch unter C könnte es nützlich sein, den ASM-Befehlssatz zu kennen, denn der AVR kann kein C, der kann nur ASM bzw. Maschinencode. Jedes C-Konstrukt muss also vom Compiler in ASM übersetzt werden. MfG
Der Fakt ist doch, egal wie man SREG_I löscht, nur mit CLI wird es 100%-ig gelöscht, sonst nicht !!! Deshalb muß man beim AVR CLI nehmen ! Es mag zwar selten sein, daß ein Interrupt währende des OUT zuschlägt, aber dadurch sind solche Fehler nur umso gefährlicher, da schwerer festzustellen. Es ist also müßig über andere Befehle zu palavern, sie wuppen es einfach nicht ! Peter P.S.: Beim 8051 hat man das anders gelöst: Jeder Zugriff zu den Interruptprioritätsbits oder den Interruptenablebits, verzögert die Interruptbehandlung um einen Befehl. Das dient genau dazu, alle Änderungen zu speichern, ehe der nächste Interrupt zuschlagen kann.
> SREG ist im oberen Teil des I/O-Adressraums und kann daher nicht > bitorientiert angesprochen werden. Ah richtig. cbi und sbi gehen nur bis 32, nicht bis 64, wie in und out. > Damit das SREg trotzdem schnell manipuliert werden kann, enthält der > ASM-Befehlssatz die Befehle SEx und CLx, wobei x für das Bit im SREG > steht, beim Interrupt-Bit eben SEI und CLI, beim Carry SEC und CLC. Oder allgemein auch als BSET/BCLR verfügbar. > Auch unter C könnte es nützlich sein, den ASM-Befehlssatz zu kennen, > denn der AVR kann kein C, der kann nur ASM bzw. Maschinencode. Jedes > C-Konstrukt muss also vom Compiler in ASM übersetzt werden. Das ist bei jedem Prozessor so. > Der Fakt ist doch, egal wie man SREG_I löscht, nur mit CLI wird es > 100%-ig gelöscht, sonst nicht !!! sbi/cbi wären auch atomar gewesen.
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.