mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Pause in AVR-Studio mit variable?


Autor: Lukas H (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi, wie kann ich ne pause in AVR studio machen, mit einer variable?

mann kann ja einfach "delay50ms:" schreiben, ich möchte aber, das die
pause so viele millisekunden lang ist, wie es in z.B. r16 steht.

help please! thx

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ASM oder C ?

Timer für 1ms (Vorwert berechnen)einrichten,
x-mal Überlauf = x-mal ms. (im Timeroverflowimterrupt r16
decrementieren)
Wenn r16 == 0, Dann Timer stoppen. (Prescaller off)

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> mann kann ja einfach "delay50ms:" schreiben,...

Türlich kann Mann das. Ich glaub Frau kanns u.U. sogar auch;-) Ob es
das tut, was Du willst, weiß ich nicht.

Da musst Du Dir halt ne Zählschleife programmieren, die bei dem Takt,
mir dem Dein µC läuft, genau eine ms braucht und dann Deine Variable
runterzählen. Zu dem Thema ('wie berechne ich ne Zählschleife') gibt
hier ca. 1357,4 Threads. Kannst ja mal suchen. Aber vielleicht bringt
es mehr, wenn Du selber überlegst, wie es geht. Schau mal ins
Instruction Set Manual. Da steht drin, wie viele Taktzyklen die
einzelnen Befehle brauchen (für Dich kämen da am eheseten dekrement-
und Sprungbefehle in Frage...). Dann alles zusammenpuzzeln und
irgendwann läufts vielleicht sogar richtig.

Autor: Lukas H (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mit asm

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...

.def  pause_counter  = r25

...

rcall pause

...

;********Unterprogramme**********
pause:
 ldi pause_counter, 0xFF
 pause_loop:
  dec pause_counter
  nop
 brne pause_loop
 ret

Je nach MHz und dem Wert im counter, ändert sich die Verweildauer.
Also nachschauen wieviel Zyklen jeder einzelne Befehl benötigt, dann
zusammenaddieren. Der Sprung kostet nochmals 3 Zyklen.

Näheres gibt's hier:

http://www.avr-asm-tutorial.net/avr_de/beginner/sp...

Autor: Jahn (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
im myAVRWorkpad PLUS hab ich für sowas nen CodeWizard ich muss sagen
wier schnell mein AVR läuft und dann baut mir der Wizard die
warteroutine... hier bei 3,6864 MHz:

;--------------------------------------------------------------------
; myWait_us - Warte-Routine für x-Mikrosekunden einschließlich des
Aufrufes
; berechnete Abweichung: 8.5%
; PE: r16 = Anzahl der zu wartenden Mikrosekunden
; es wird mindestens 3µs gewartet, auch wenn r16 kleiner als 3
; PA: r16 = 0
;--------------------------------------------------------------------
; created by myAVR-CodeWizard
;--------------------------------------------------------------------
myWait_us:
   nop   ; wait
   subi   r16,3
   brcs   myWait_us_1
   breq   myWait_us_1
myWait_us_2:
   nop   ; wait
   dec   r16
   brne   myWait_us_2
myWait_us_1:
   ret
;--------------------------------------------------------------------

gruß Jahn

Autor: Jahn (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hier noch mal ne millisekunden routine bei 3,6864 MHz aus dem CodeWiz

;--------------------------------------------------------------------
; myWait_ms - Warte-Routine für x-Millisekunden
; ein Millisekundenzyklus dauert 1,052 ms
; PE: r16 = Anzahl der zu wartenden Milisekunden
; PA: r16 = 0
;--------------------------------------------------------------------
; created by myAVR-CodeWizard
;----------------------------------------------------------------------- 
--
myWait_ms:
   push   r16
   ldi   r16,1
myWait_ms_3:
   push   r16
   ldi   r16,5
myWait_ms_2:
   push   r16
   ldi   r16,255
myWait_ms_1:
   dec   r16
   brne   myWait_ms_1
   pop   r16
   dec   r16
   brne   myWait_ms_2
   pop   r16
   dec   r16
   brne   myWait_ms_3
   pop   r16
   dec   r16
   brne   myWait_ms
   ret
;----------------------------------------------------------------------- 
--

Gruß Jahn

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man braucht dazu nicht extra nen Codewizard zu bemühen.

Der Assembler-Präprozessor kann doch selber 32Bit Berechnungen
durchführen.
Einfach bei XTAL die gewünschte Quarzfrequenz eintragen:
;************************************************************************/
;*                                                                     
*/
;*                      Delay Macro 8 ... 65543 Cycle                  
*/
;*                                                                     
*/
;*              Author: Peter Dannegger                                
*/
;*                      danni@specs.de                                 
*/
;*                                                                     
*/
;************************************************************************/
.listmac

;delay 8 ... 65543 cycle

.macro  mdelay
        ldi     r24, low( @0 - 8 )
        ldi     r25, high( @0 - 8 )
        sbiw    r24, 4
        brcc    pc - 1
        cpi     r24, 0xFD
        brcs    pc + 4
        breq    pc + 3
        cpi     r24, 0xFF
        breq    pc + 1
.endmacro

;------------------------------------------------------------------------
.equ    xtal = 16000000         ;16MHz

;delay 1 ... 255, 256 ms

;input: R16 = 1 ... 255, 0
;used:  R16, R24, R25

delay_n_ms:
        mdelay  (xtal + 500) / 1000     ;1ms
        dec     r16
        brne    delay_n_ms
        ret
;------------------------------------------------------------------------


Peter

Autor: Lukas H (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also, ich haääte vielleicht dazusagen müssen, das ich inzwischen nun
schon  das kapitel 1,2und 4 des avr tutorials auf dieser page durch
habe und gut verstanden habe. un das mit den takzyklen hört sich ganz
gut an.
ich habe den AT Mega 8, der hat 16 Mhz. Kann mir jemand ganz simple
erklären, was ein takt zyklus ist? Und was die Mhz aussgaen, je mehr
Mhz, desto mehr zyklen pro sekunde ??!?

danke!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein µProzessor hat einen Grundtakt. Der Grundtakt
ist so was wie der Mann der auf einer Galeere: Der
Schlägt auf eine Pauke und gibt so den Takt vor in
dem gerudert wird.

In deinem Prozessor wird zwar nicht gerudert, aber
verschiedene Einheiten müssen da zusammenarbeiten.
Wann welche Einheit was zu tun hat, gibt der Systemtakt
vor.

Dein Mega8 wird mit 16Mhz betrieben. Das heisst der Quarz
schwingt 16 Millionen mal in der Sekunde. Folgerichtig
'schlägt der kleine Japaner im Chip' 16 Millionen mal
in der Sekunde auf die Pauke und es passieren in einer
Sekunde 16 Millionen Arbeitsschritte.
Die Zeit von einem Schlag zum nächsten ist der Taktzyklus.
Viele (die meisten) Befehle können auf deinem Mega8 in
einem Taktzyklus abgearbeitet werden. D.h. dein Mega8
kann dann im Extremfall 16 Millionen Befehle in der
Sekunde abarbeiten.

Autor: Fritze (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da du 16MHz bebutzt, braucht dein Atmel für einen Arbeitstakt
1/16000000 Sekunden. (62,5 Nanosekunden)

Für die Pause von 1 ms mußt du also 16000 Takte "verbraten".

Wenn du eine simple Schleife nutzen willst, mußt du entweder eine
16bit
Variable benutzen oder eine innere und eine äußere Schleife verwenden.

Autor: Lukas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, nu check ich das, danke für die gute beschreibung! Gibt es denn
einen einfachen befehl um eine bestimmte anzahl von zyklen "nichts"
zu tun?

Was sind denn "us" die bei der simulation unter prozessor/stopwatch
gezählt werden?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Befehl heißt nop und wartet genau einen Taktzyklus. Die Stopwatch
zählt µs (Mikrosekunden)

Autor: Fritze (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
- Ja,
  NOP, tut nichts für einen Takt

- us = µs
  Mikrosekunden

Autor: Lukas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, kann ich "nop" auch irgendwie multiplizieren? Ich mächte ja nicht
16000 mal nop schreiben

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich glaube, das mit den Zählschleifen hatten wir oben schon mal... Du
scheinst zu vergessen, dass Du in Assembler programmierst. Da ist halt
alles ein bisschen einfacher gehalten (ein Befehl macht genau eine
Elementar-Operation, in den meisten Fällen bezogen auf einen einzigen
Taktzyklus). Man muss dann eben ne Menge selber machen, lernt dadurch
aber die Hardware besser kennen, als wenn man gleich mit C (oder gar
Basic) anfängt. Musst Dir da halt was einfallen lassen.

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst eine Schleife drum herum legen.
So nach dem Muster:
1  Register mit einem Wert laden
2  nichts tun
3  Register um 1 vermindern
4  0 erreicht?
5  wenn nein, gehe zu 2

Hinweis: In einem Register kannst du nur Zahlen
bis 256 laden. D.h. du kannst nicht in einem
Rutsch mit nur einem Register von 16000 bis
auf 0 herunter zählen.
Es hindert dich aber niemand daran immer wieder
von 255 bis 0 zu zählen und das 62 mal :-)

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Er kann aber mit adiw bzw. sbiw mit 16-Bit-Werten arbeiten, muss dann
allerdings die richtigen Register dafür nehmen...

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> ok, kann ich "nop" auch irgendwie multiplizieren? Ich mächte ja
> nicht 16000 mal nop schreiben

Für relativ kurze Wartezeiten (Zeitschleifen) nutze ich gern mal rcall
/ ret, das vertrödelt schonmal 7 Takte pro Aufruf.

Aber solch "lange Verzögerungen" realisiert man besser mittels Timer.
Dabei sollte man sich mit einem ständig laufenden Timer Interrups im
Zeitabstand von 0,1ms..20ms (je nach sonstigen Aufgaben des Timers)
erzeugen, in denen man den Rest per "Software-Timer" machen kann.

Den Timer-Int braucht man sowiso zum Entprellen von Tasten, Generieren
von Blinktakten und anderen immer wieder gebrauchten Dingen, da kann
man sich also schon von Anfang an mit beschäftigen.

Zuvor solltest du aber das Prinzip der Warteschleife verstanden haben.
Das sind ineinander verschachtelte Zählschleifen, die erst verlassen
werden, wenn die gewünschte (voreingestellte) Anzahl "Runden"
absolviert wurde. Da ein MC während einer Warteschleife nichts anderes
(sinnvolleres) machen kann als eben Wartezeit abzählen, sollte man
Warteschleifen nur für sehr kurze Verzögeringen nutzen und ansonsten
meiden.

...

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine einfache 16bit-Warteschleife sieht so aus:

FOO:
    subi r16, low(1)   ; 1
    sbci r17, high(1)  ; 1
    brne FOO           ; 2 bei Sprung, sonst 1
                       ; 4n - 1

Ich habe hinter jede Answeisung als Kommentar die Zahl an Taktzyklen
geschrieben, die sie braucht. Die Schleife braucht pro Durchlauf 4
Taktzyklen, man muß also die gewünschte Zahl an Taktzyklen durch 4
teilen (zwei Bits nach rechts schieben), um den Wert zu bekommen, mit
dem der Schleifenzähler initialisiert werden muß. Dann schreibt man die
unteren 8 bit nach r16, die oberen nach r17.

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nagut, dann will ich auch mal ein Warteschleifen-Beispiel posten. Es
diente zum Erzeugen der Wartezeiten beim Initialisieren eines LCDs. Zu
diesem Zeitpunkt (während der Reset-Routine) ist der Timer noch nicht
aktiviert, deshalb diese Warteschleifen.

;====================================================================
; Interne Routinen, werden nur von lcd_init und lcd_clear aufgerufen
;--------------------------------------------------------------------
wait1ms:            ;wartet etwa 1 Millisekunden
 push wl                    ;Variablen beschaffen
 push wh
 ldi wl,low(clock/1000/25)  ;Startwert setzen
 ldi wh,high(clock/1000/25) ;(AVR-Takt/1000Hz/25 Takte je Runde)
 rjmp wait1                 ;weiter...

wait5ms:            ;wartet etwa 5 Millisekunden
 push wl                    ;Variablen beschaffen
 push wh
 ldi wl,low(clock/200/25)   ;Startwert setzen
 ldi wh,high(clock/200/25)  ;(AVR-Takt/200Hz/25 Takte je Runde)
 rjmp wait1                 ;weiter...

wait10ms:           ;wartet etwa 10 Millisekunden
 push wl                    ;Variablen beschaffen
 push wh
 ldi wl,low(clock/100/25)   ;Startwert setzen
 ldi wh,high(clock/100/25)  ;(AVR-Takt/100Hz/25 Takte je Runde)
wait1:
 rcall waitend              ;7 Takte trödeln
 rcall waitend              ;7 Takte trödeln
 rcall waitend              ;7 Takte trödeln
 subi wl,1                  ;Low-Byte vermindern
 sbc wh,null                ;High-Byte um Übertrag (Carry) vermindern
 brcc wait1                 ;nochmal, solange $0000 -> $ffff kein
                            ;Carry setzt
 pop wh                     ;Variablen
 pop wl                     ;entsorgen
waitend:
 ret                        ;fertig bzw.zurück...

Die Register "wl" und "wh" sind meist r24 und r25, das Register
"null" ist meist r3 und enthält immer 0. Die Konstante "clock"
enthält die Taktfrequenz des AVRs. Die veränderten Register werden
gesichert und wiederhergestellt.

...

Autor: Fritze (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, wenn du keinen Timer benutzen möchtest:
Wenn's nicht genau eine ms ist, NOPs einfügen bzw, Zählerwerte
verringern

pause:
 ldi counter1,0xFF ;innerer Zähler (255)
 ldi counter2,0x3E ;äußerer Zähler (62)

 pause_loop_aussen:
  dec counter2

   pause_loop_innen:
    dec counter1
   brne pause_loop_innen

  brne pause_loop_aussen



ret

Autor: tori (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wegen der Taktberechnung ist dass nicht immer genau hinzubekommen, da
einige Befehle auch 2 oder 3 Takte benötigen. Die Rechnerei ist sehr
mühsam, da Sprungbefehle in Abhängigkeit der Bedingung unterschiedliche
Taktanzahlen benötigen. Ich lasse mir meine Warteroutinen vom CodeWizard
im myAVR Workpad genau auf den Wert machen den ich brauche. Hie eine
ziehmlich genaue 1ms Routine (gerechnet incl. Aufruf).

tori

;--------------------------------------------------------------
; Titel : Warteroutinen Beispiel
;--------------------------------------------------------------
; Funktion : WarteRoutinen
; Schaltung :
;--------------------------------------------------------------
; Prozessor : ATmega8
; Takt : 16000000 Hz
; Sprache : Assembler
; Datum : 19.7.2006
; Version : 1.0
; Autor : tori
; Programmer:
; Port :
;--------------------------------------------------------------
; created by myAVR-CodeWizard
;--------------------------------------------------------------
.include "avr.h"

...

;--------------------------------------------------------------------
; Warte-Routine für 1 ms
; die Routine wartet inclusive Aufruf 1,014 ms
;--------------------------------------------------------------------
myWait_1ms:
   push   r16
   ldi   r16,1
myWait_1ms_3:
   push   r16
   ldi   r16,21
myWait_1ms_2:
   push   r16
   ldi   r16,255
myWait_1ms_1:
   dec   r16
   brne   myWait_1ms_1
   pop   r16
   dec   r16
   brne   myWait_1ms_2
   pop   r16
   dec   r16
   brne   myWait_1ms_3
   pop   r16
   ret

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@tori,

"Wegen der Taktberechnung ist dass nicht immer genau hinzubekommen,
da
einige Befehle auch 2 oder 3 Takte benötigen."


Das kann man aber auch ausnutzen.

Schau Dir mal mein obiges Macro an. Dem kann man jeden Wert von 8 ...
65543 Zyklen übergeben und die werden haargenau eingehalten.


Peter


P.S.:
Habe ich schon gesagt, daß Delayschleifen ohne Timer nur dann stimmen
können, wenn absolut kein einziger Interrupt verwendet wird.

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Tori:
Wer sich von irgendwelchen Codewizzards oder Berechnungsprogrammen
abhängig macht, verlernt im allgemeinen das logische Denken. Dass ein
Verzweigungsbefehl mal mehr und mal weniger Takte braucht, ist
überhaupt kein Problem, denn man sieht ja, welcher Fall eintritt.

...

Autor: Lukas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, dann feheln mir aber drei befehel, wie vermindere ich einen
register? wie prüfe ich ob in einem register eine bestimmte zahl drin
steht?

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Normalerweise würde man sagen:
Hol dir von Atmel das 'Instruction Set'

Da sind zumindest alle Befehle drinn, die der
Atmel kennt.

Nur ist das halt nur die halbe Miete. Die Befehle
alleine machens nicht. Erst die Kombination
der Befehle bringt Leben in die Bude.

Schau dich mal hier um
http://www.avr-asm-tutorial.net/avr_en/index.html

Da gibts einige Tutorials die dir die Grundlagen
beibringen.

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alternativ kannst du auch:

Von Atmel das 'Instruction Set Manual' downloaden
(Merkst du was? Ohne dieses Dokument kommst du nicht weit)

und dann einfach mal die bisher geposteten Lösungen
anylsieren. Alle Befehle die du nicht kennst schlägst
du im ISM nach.

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das AVR-Studio hat auch eine Online-Hilfe. Wenn man den Editorcursor auf
einen ASM-Befehl setzt und dann die F1-Taste drückt, dann erfährt man
etwas über den betreffenden Befehl. Ist fast wie beim guten alten
QBASIC...

...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.