Forum: Mikrocontroller und Digitale Elektronik 1ms Pause-Schleife


von Ithamar G. (antimon)


Lesenswert?

Hallo zusammen,

irgendwie hab ich nach stundenlangem Googlen, ausprobieren etc. keinen
Erfolg gehabt, bevor ich ganz verzweifle, wende ich mich lieber an die
Profis...

Ich möchte eine Schleife programmieren, die mir in etwa 1ms Pause
erzeugt, dieser möchte ich dann über einen Parameter die Anzahl der
Durchläufe (sprich: die Anzahl der ms) übergeben.

Mein Ansatz hat leider nicht funktioniert:

[assembler]
delay:
  LDI    r17, 2
dely1:
  LDI    r16, 166
dely:
  DEC    r16
  BRNE  dely
  DEC    r17
  BRNE  dely1
  DEC    r25
  BRNE  delay
  RET
[/assembler]

Meine Idee war folgende: DEC und BRNE brauchen zusammen 3 Takte, wird
diese Schleife 165x ausgeführt, haben wir ungefähr 500 Takte. Das Ganze
dann 2x durchlaufen entspricht 1000 Takte - also bei 1Mhz wäre das 1ms
Und im Register r25 steht die Anzahl der Gesamtdurchläufe, sprich die
Anzahl der ms... aber ich komm nicht auf 1ms wenn ich in r25 ne 2
reinschreibe-wo liegt mein Denkfehler?

Und wenn ich in einer Variablen fq=4000000 die Taktfrequenz bei einem
externen Quarz drinstehen habe, wie mache ich es am geschicktesten,
dass ich obige Schleife dann auch 4x so oft durchlaufen lasse?

Irgendwie hab ich heut schon den halben Tag vertan, ohne auf ein
Ergebnis zu kommen... vielen Dank also schon mal für Eure Hilfe!!

von Marc G. (marc_gauger)


Lesenswert?

Brne ist doch erst wenn der wert Negativ ist oder? und 2 minus 1 minus 1
= 0 und nicht negativ, also würd ich sagen schreib einfach mal 1 rein.
vielleicht kommst du dann auf deine ms.

Nur eine Idee.

MFG Marc

von Andi K. (Gast)


Lesenswert?

Ist doch Easy:

.equ AVRTakt=8
Wait1000uS:
 ldi r24,low(1000*AVRTakt/4)
 ldi r25,high(1000*AVRTakt/4)
WaituS:
  sbiw r25:r24,1
 brne WaituS
 ret

In AVRTakt einfach die tatsächliche Frequenz in MHz definieren,
fertig.
Kann auch so was wie 3.62345 etc. sein.
Ist zwar jetzt nicht auf den Takt genau aber es reicht.
Für ziemlich genau gibt es sowieso nur Timer-Interrupt.

Für z. B. 50µS läßt sich das erweitern mit

Wait50uS:
 ldi r24,low(50*AVRTakt/4)
 ldi r25,high(50*AVRTakt/4)
 rjmp WaituS

Die Formel N*AVRTakt/4 rechnet die Anzahl der Schleifendurchläufe unter
Berücksichtung, das ein Durchlauf 4 Takte dasuert, aus.
Bei 8MHz sind dann 65535 / 8 * 4 = 32,7675 mS möglich.
Ließe sich für eine längere Zeit auch auf 24 oder 32Bit-Zählung
erweitern.

MfG
Andi

von Ithamar G. (antimon)


Lesenswert?

Wahrscheinlich denk ich da zu kompliziert... und es geht auch
einfacher...

Was du meinst, ist aber vermutlich BRMI (Branch if Minus), BRNE ist
Branch if not equal, also wenn das Ergebnis ungleich 0 ist...

von Andi K. (Gast)


Lesenswert?

Oder so:

WaitmS:
 ldi r24,low(1000*AVRTakt/4-1)
 ldi r25,high(1000*AVRTakt/4-1)
WaitmS1:
  sbiw r25:r24,1
 brne WaitmS1
 nop
 dec r16
 brne WaitmS
 ret

In r16 die Anzahl der mS und dann aufrufen.
Das NOP ist zum Ausgleich wegen dem Zyklus von 4 Takten.

MfG
Andi

von Ithamar G. (antimon)


Lesenswert?

lol - also soo easy ist das leider nicht... zumindest für mich nicht ;)

Ich wusste ned mal dass man so einfach zwei Register konkatenieren
kann, bisher hab ich nur einen HC68011 programmiert, und da ist die
Umstellung auf AVR schon ziemlich groß...

Also prinzipiell ist dein Code supereinfach und funktioniert auch
(fast) gut... ich hab nur das Problem dass die Ausgabe auf dem µC um
den Faktor 4 zu schnell vor sich geht. Im Simulator läuft der µC mit 4
Mhz, stelle ich AVRTakt auf 4 ein, kommt ziemlich genau 1ms raus.
Der reale µC hat zwar einen 4Mhz Quarz dran, der aber noch nicht
aktiviert ist, läuft also mit den internen 1Mhz. Und bei AVRTakt=1 und
hundertfachem Schleifendurchlauf blinkt er 4x/Sekunde... woran kann das
liegen?

Ansonsten vielen Dank für den Code, der hat mir schon einiges an Ärger
erspart!!

von kryon2000 (Gast)


Lesenswert?

Denk daran das der Aufruf der Unterroutine auch nochmal 7 takte benötigt
(rcall + ret) ;-)

von kryon2000 (Gast)


Lesenswert?

Deine Routine von oben würde so aussehen:
1
ldi  r25, 1
2
rcall  delay    ;1011 takte  
3
4
delay:      ;------------------------
5
  LDI    r17, 2      ;---------------
6
7
dely1:
8
  LDI    r16, 166  ;-------
9
dely:        ;   498 t    1002t     1004t
10
  DEC    r16    ;
11
  BRNE  dely    ;-------
12
13
  DEC    r17
14
  BRNE  dely1    ;---------------
15
16
17
  DEC    r25  
18
  BRNE  delay    ;-----------------------
19
  RET

Der Aufruf würde also 1011 takte verschwenden wenn r25 = 1 wäre.

von Andi K. (Gast)


Lesenswert?

Na ja, bei einer Pause von 1mS braucht man glaube ich nicht über 7 Takte
(1µS) zu reden.


@Ithamar Garbe (Antimon): Wenn Du sicher bist, das der AVR mit 1MHz
läuft, hast Du dann AVRTakt auf 1 eingestellt?

MfG
Andi

von Mika (Gast)


Angehängte Dateien:

Lesenswert?

Im Anhang gibts nen Schleifengenerator. Hat bisher perfekt
funktioniert.
Gruss Mika

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.