Forum: Mikrocontroller und Digitale Elektronik Zeitverzögerungen programmieren


von Florian S. (flocean)


Lesenswert?

Hallo zusammen,

ich bin gerade dabei das angebotene AVR Tutorial durchzuarbeiten. Ich 
bin jetzt leider beim LCD Display ansteuern hängen geblieben. Die 
Initialisierung für den 4 Bit Modus macht mir Probleme.

Mein Problem ist wie ich Zeitverzögerungen in Assembler programmieren 
kann. Mein verwendeter Mega8 betreibe ich mit dem internen Takt von 
1MHz. Das Prinzip ist mir klar ich muss so viel Rechenaufwand in den 
Code einbringen,  bis ich zum nächsten Steuerungsbefehl komme, dass ich 
die gewünschte Zeitverzögerung aus dem Datenblatt der LCD Anzeige 
erreiche. Wie baue ich eine Verzögerung von von z.B. von 5 ms ein? In 
der Theorie muss ich dem Controller 5000 Takte Arbeit geben. Wie 
realisiere ich das Ganze platzsparend?
Eine kleine weitere Frage: Die 4 Bit Initialisierung muss jedes mal nach 
Einschalten durchgeführt werden, oder muss das Ganze nur einmal 
erfolgen?

Vielen Dank für die Hilfe und die Geduld!

Beste Grüße,

Florian

von Patrick (Gast)


Lesenswert?

Florian S. schrieb:
> In
> der Theorie muss ich dem Controller 5000 Takte Arbeit geben. Wie
> realisiere ich das Ganze platzsparend?

Einfach zwei ineinander verschachtelte 8-Bit-Zähler. Der "innere" Zähler 
zählt von 0xFF bis 0, der äußere von 0x13 bis 0 (oder so).

Florian S. schrieb:
> Die 4 Bit Initialisierung muss jedes mal nach
> Einschalten durchgeführt werden, oder muss das Ganze nur einmal
> erfolgen?

Nur einmal am Anfang (bzw. nachdem das Display Spannung kriegt).

von Karl H. (kbuchegg)


Lesenswert?

Florian S. schrieb:

> Mein Problem ist wie ich Zeitverzögerungen in Assembler programmieren
> kann. Mein verwendeter Mega8 betreibe ich mit dem internen Takt von
> 1MHz. Das Prinzip ist mir klar ich muss so viel Rechenaufwand in den
> Code einbringen,  bis ich zum nächsten Steuerungsbefehl komme, dass ich
> die gewünschte Zeitverzögerung aus dem Datenblatt der LCD Anzeige
> erreiche. Wie baue ich eine Verzögerung von von z.B. von 5 ms ein? In
> der Theorie muss ich dem Controller 5000 Takte Arbeit geben. Wie
> realisiere ich das Ganze platzsparend?

Irgendwie verstehe ich deine Frage nicht.
All diese Dinge sind im Tuorial ausgeführt und in Form von Code gezeigt. 
Der beschreibende Text im Tutorial-Artikel ist nicht dort, damit es 
hübscher aussieht.

> Eine kleine weitere Frage: Die 4 Bit Initialisierung muss jedes mal nach
> Einschalten durchgeführt werden, oder muss das Ganze nur einmal
> erfolgen?

Jedes mal, wenn Spannung angelegt wird.
Das LCD merkt sich diese Einstellung nicht.

von Florian S. (flocean)


Lesenswert?

Okay vielen Dank für die schnelle Hilfe ich werd mich nochmal einlesen.

Beste Grüße

von spess53 (Gast)


Lesenswert?

Hi

Suche mal nach:

AVR delay loop generator

MfG Spess

von Florian S. (flocean)


Lesenswert?

So jetzt meld ich mich doch nochmal. Wie ich vorher übersehen hab, ist 
die Verzögerungschleife in den Standartroutinen. Nun liegt das Problem 
im verstehen der paar Zeilen. Hier der Ausschnitt:
1
delay5ms:                               ; 5ms Pause (bei 4 MHz)
2
           ldi  temp1, $21
3
WGLOOP0:   ldi  temp2, $C9
4
WGLOOP1:   dec  temp2
5
           brne WGLOOP1
6
           dec  temp1
7
           brne WGLOOP0
8
           ret                          ; wieder zurück

Meine Interpretation lautet folgendermaßen:

1. Lade in temp1, 0x21
2. Lade in temp2, 0xC9
3. Dekrementiere temp2
4. Wenn temp2 nicht 0 ist, springe auf WGLOOP1 und wiederhole 3. 
ansonsten
5. Dekrementiere temp1
6. Wenn temp1 nicht 0 ist, springe auf WGLOOP1 und wiederhole somit 1-5. 
ansonsten
7. zurück ins Hauptprogramm

Ein Blick in die Instruction Set sagt mir dass alles 1 Takt braucht bis 
auf brne, der Befehl braucht 1 bis 2 Takte.
Meine Frage: Gibt es eine Laufzeitformel für solche Schleifentypen? Mir 
schwebt ne Funktion die mir die Verzögerung in irgendeiner 
Sekundeneinheit ausgibt in Abhängigkeit der eingegebenen Registerwerte 
und dem Versorgungstakt. Die Laufzeit ist ja zusätzlich noch abhängig 
wie viele Befehle in den einzelnen Schleifen stehen, diese würd ich aber 
als Konstanten für genau diesen Schleifentyp annehmen, da das denke ich 
ne Standardschleife ist. Wenn diese Formel existiert, hab ich sie bis 
jetzt noch nicht gefunden. Ansonsten welchen Wert muss ich denn für brne 
nehmen 1 oder zwei Takte um so eine Formel selbst aufzustellen?

Vielen Dank für die Hilfe. Ich weiß sind doch wahrscheinlich sehr banale 
Fragen, aber tu mir etwas schwerer wie mir scheint.

Beste Grüße,

Florian

von Karl H. (kbuchegg)


Lesenswert?

Florian S. schrieb:

> Meine Frage: Gibt es eine Laufzeitformel für solche Schleifentypen?

Für die Herstellung 1 Schachtel brauchst du 2 Minuten. WIe lange 
brauchst du für 35 Schachteln?

(
Bzw. Was dich dann anders rum interessiert: Wieviele Schachteln kannst 
du in 60 Minuten machen?
)


> und dem Versorgungstakt. Die Laufzeit ist ja zusätzlich noch abhängig
> wie viele Befehle in den einzelnen Schleifen stehen, diese würd ich aber
> als Konstanten für genau diesen Schleifentyp annehmen

Nö.
Die weißt du doch.
Wenn du 25 in ein Register lädst und in der Schleife das Register um 1 
runterzählst und zum Schleifenanfang gehst, wenn noch nicht 0 erreicht, 
wie oft wird dann die Schleife durchlaufen?

von Florian S. (flocean)


Lesenswert?

Okay meine eigene Formel lautet:
1
Tdelay = ( 1 + 1 + Werttemp1 * 2 * Werttemp2 * 2 + 4 ) * 1/f
2
3
Tdelay = ( 6 + Werttemp1 * Werttemp2 * 4 ) * 1/f
Kurze Erklärung:

1+1 : Initialisierung der Zählerregister:
*2 : Da jeweils in jeder Schleife 2 Befehle stehen
+4: ret braucht 4 Takte

Diese Formel wurde unter der Annahme erstellt, dass brne 1 Takt braucht 
um abgearbeitet zu werden. Mit zwei wäre die Formel entsprechend:
1
Tdelay = ( 6 + Werttemp1 * Werttemp2 * 9 ) * 1/f
Kann man die Laufzeit so berechnen, oder hab ich nen Denkfehler? Ich hab 
nachgerechnet mit beiden Formeln kommt der falsche Wert für gewollte 5 
ms Verzögerung raus. Mit der ersten sinds 6.6 ms mit der zweiten 14.9 ms 
bei eingesetzten Werten Werttemp1 = 33 Werttemp2 = 201 und f = 4MHz. 
(alles natürlich dezimal). Das kann jetzt daran liegen, dass meine 
Formeln falsch sind oder, dass die Anwendung nicht arg laufzeitkritisch 
ist und somit großzügig gerechnet wurde, hauptsache die 
Mindestlaufzeitverzögerung wurde erreicht.

Beste Grüße,

Florian

von Karl H. (kbuchegg)


Lesenswert?

Florian S. schrieb:

> (alles natürlich dezimal). Das kann jetzt daran liegen, dass meine
> Formeln falsch sind oder, dass die Anwendung nicht arg laufzeitkritisch
> ist und somit großzügig gerechnet wurde, hauptsache die
> Mindestlaufzeitverzögerung wurde erreicht.

Kann mich so dunkel erinnern, dass ich da ziemlich genau gerechnet habe.


Probier halt deine Formeln mal mit einfacheren Zahlen aus.
Jede der beiden Schleifenkonstanten sei 1.
Was kommt dir in der Formel raus?
Spiel den Code mit Papier und Bleistift durch, wieviele Takte hast du 
verbraucht?
Vergleiche die Ergebnisse.

von Florian S. (flocean)


Lesenswert?

Okay meine Fehlerquellen sind in diesen Fall:

1. nicht berücksichtigter Sprung zur Routine macht +3
2. Fallunterscheidung bei brne 1/2 Takte. Wobei ich da nicht weiß, wann 
ich was nehmen soll. Entweder der Befehl braucht immer einen Takt oder 
immer 2 Takte, oder es wird unterschieden, ob die die Bedingung erfüllt 
ist oder nicht. Vielleicht kann mir da jemand helfen in der Instruction 
Set steht dazu nichts (ich habs zumindest nicht gefunden keine Fußnote 
nichts).
3. Ich hab ein falsches Bild des Ablaufs. Ich hab ihn weiter oben kurz 
beschrieben, vielleicht ist der falsch.

Beste Grüße,

Flo

von trollalala (Gast)


Lesenswert?

Florian S. schrieb:
> 2. Fallunterscheidung bei brne 1/2 Takte. Wobei ich da nicht weiß, wann
> ich was nehmen soll. Entweder der Befehl braucht immer einen Takt oder
> immer 2 Takte, oder es wird unterschieden, ob die die Bedingung erfüllt
> ist oder nicht. Vielleicht kann mir da jemand helfen in der Instruction
> Set steht dazu nichts (ich habs zumindest nicht gefunden keine Fußnote
> nichts).
Aus dem Gedächnis: 1 Takt wenn die Bedingung falsch ist, also 
Register==0 und nicht gesprungen wird. 2 Takte wenn gesprungen wird.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Florian S. schrieb:
>
>> (alles natürlich dezimal). Das kann jetzt daran liegen, dass meine
>> Formeln falsch sind oder, dass die Anwendung nicht arg laufzeitkritisch
>> ist und somit großzügig gerechnet wurde, hauptsache die
>> Mindestlaufzeitverzögerung wurde erreicht.
>
> Kann mich so dunkel erinnern, dass ich da ziemlich genau gerechnet habe.

Das passt schon.
Laut Simulator werden (ohne den Return) 19998 Takte verbraucht, was bei 
4Mhz einer Zeit von 4.9995 ms entspricht.

Deine Formeln sind falsch.

von John B. (johnbauer)


Lesenswert?

spess53 schrieb:
> Hi
>
> Suche mal nach:
>
> AVR delay loop generator
>
> MfG Spess

Was Spess sagt. ->

http://bretm.home.comcast.net/~bretm/avrdelay.html

Gruß
John

von Karl H. (kbuchegg)


Lesenswert?

John Bauer schrieb:
> spess53 schrieb:
>> Hi
>>
>> Suche mal nach:
>>
>> AVR delay loop generator
>>
>> MfG Spess
>
> Was Spess sagt. ->
>
> http://bretm.home.comcast.net/~bretm/avrdelay.html

grundsätzlich richtig.
Nur sind das Dinge, die er eigentlich selbst können sollte. Der 
Generator bringt Komfort ersetzt aber nicht die Übung.

von spess53 (Gast)


Lesenswert?

Hi

brne braucht 2 Takte um wieder zum dec zurück zu springen und einen Takt 
wenn das Register Null ist. Macht 3n-1 Takte. Dazu kommt ein Takt für 
das Laden des Registers. Damit braucht

     ldi rxy,n
aaa: dec rxy
     brne aaa

genau 3n Takte.

MfG Spess

von Florian S. (flocean)


Lesenswert?

Vielen Dank für die vielen Tipps. Der Generator ist super, erleichtert 
einem die Arbeit wesentlich. Ich würde aber trotzdem gerne eine 
expilizite Formel herleiten, nur hab ich bis jetzt den Trick hinter der 
geschachtelten Schleife nicht gesehen.

Bis jetzt hab ich:

1. 2*1 Takt für Werte ins Register laden
2. 3 Takte für den Sprung in die Routine
3. 4 Tate für den Sprung zurück ins Hauptprogramm
4. Danach wird die innerste Schleife in einem Durchlauf mit 3 Takten 
durchlaufen wenn das Register danach nicht den Wert 0 hat. Also ins 
gesamt dann 3 * ( temp2 - 1 ) + 2 = 3 * temp2 - 1
5. Die Verschachtelung hab ich so gelöst ( 3 * temp2 - 1 ) * temp1 die 
innere Schleife wird ja mit der Anzahl der von temp1 durchlaufen.
5. die äußere Schleife wird wie 4 durchlaufen
6. nach jedem mal, nachdem die Innere Schleife runtergelaufen ist wird 
die äußere durlchlaufen und solange die Beding nicht erfüllt ist, wird 
wieder zum Register temp2 gesprungen, somit noch +temp2-1

Insgesamt macht das dann:

macht dann zusammengefasst:

Bei mir kommen jetzt nur leider 20005 Takte raus(Ich glaub solangsam 
blamier ich mich :-D). Über noch ne Anregung was nicht stimmt wär ich 
nochmals sehr dankbar.

Beste Grüße,

Florian

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Um die Verwirrung zu vervollständigen:

Man kann die Taktfrequenz des AVR auch relativ einfach ändern – auch 
beim internen RC-Oszillator. Manche AVR lassen sich dann mit z.B. 500 Hz 
betreiben – das vereinfacht die Warteschleifen dann beträchtlich. 
Außerdem sinkt der Stromverbrauch deutlich.

von Karl H. (kbuchegg)


Lesenswert?

Florian S. schrieb:
> Vielen Dank für die vielen Tipps. Der Generator ist super, erleichtert
> einem die Arbeit wesentlich. Ich würde aber trotzdem gerne eine
> expilizite Formel herleiten, nur hab ich bis jetzt den Trick hinter der
> geschachtelten Schleife nicht gesehen.

Schreibs dir mal so an

           ldi  temp1, $21

> A -------------

WGLOOP0:               ldi  temp2, $C9
WGLOOP1:               dec  temp2
                       brne WGLOOP1
> B -------------

           dec  temp1
           brne WGLOOP0



Wie Spess schon gezeigt hat, benötigt der Teil von >A bis >B genau 3n 
Takte, wobei sich das n hier
        ldi  temp2, $C9
wieder findet. Ein Durchgang durch diesen Teil dauert also
($C9 ist gleich 201)  3 * 201 Takte. Macht in diesem Fall 603 Takte.

Gut.
Wie oft wird dieser innere Teil wiederholt?
Der wird $21 mal wiederholt. $21, das ist dezimal 33.
D.h. der innere Teil (von >A bis >B wird in Summe  mit 33 * 603 Takten 
zu Buche schlagen. Das ergibt 19899 Takte

Gut. Das ist der Anteil des inneren Teils.
Wieviel kommt da noch für den äusseren Teil dazu?
Der dec wird 33 mal ausgeführt und braucht jeweils 1 Takt.
der brne wird ebenfalls 33 mal ausgeführt. 32 mal braucht er 2 Take und 
1 mal 1 Takt.
d.h. da ist noch

    19899
  +    33     für den dec
  +    64     für den brne, wenn er springt
  +     1     für den brne, wenn er nicht springt
 --------
    19997

und dann fehlt noch der

           ldi  temp1, $21

der nur ein einziges mal ausgeführt wird.

   19997
       1
  -------
   19998

und genau dasselbe sagt auch der Simulator, der auf exakt die gleiche 
Anzahl kommt. Allerdings in dem er das Programm abarbeitet.

Nachdem jetzt der prinzipielle Vorgang korrekt ist, gehst du her und 
fasst das ganze in eine Formel :-)

von spess53 (Gast)


Lesenswert?

Hi

n sei der Wert der inneren und m der Wert der äußeren Schleife. Dann ist 
3m die Anzahl der Takte der äußeren Schleife. Dazu kommen m*3n Takte für 
die innere Schleife. Damit ist die Summe der Takte 3m+m*3n. So, und 
jetzt erstellst du die Formel für

     ldi r1,m
aaa: ldi r2,n
bbb: nop
     dec r2
     brne bbb
     nop
     dec r1
     brne aaa

MfG Spess

von Florian S. (flocean)


Lesenswert?

Dann komm ich ja auf die gleiche Anzahl nur hab ich die Sprünge in und 
wieder zurück noch mit berücksichtigt. Okay passt dann wars ja garnicht 
falsch. Vielen dank.

Beste Grüße,

Florian

von Karl H. (kbuchegg)


Lesenswert?

Florian S. schrieb:
> Dann komm ich ja auf die gleiche Anzahl nur hab ich die Sprünge in und
> wieder zurück noch mit berücksichtigt. Okay passt dann wars ja garnicht
> falsch. Vielen dank.

Na, dann gratulier ich.

von Peter D. (peda)


Lesenswert?

Man muß keine kryptischen Zahlen hinschreiben.
Der Assembler soll gefälligst selber Konstanten ausrechen, man schreibt 
nur die Formeln hin. Zwar nur Ganzzahl 32Bit, aber das sollte reichen.

Hier mal ein Delay-Macro:

Beitrag "Re: AVR: Delay 7 ... 65542 Zyklen"


Peter

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.