Hallo zusammen,
ich arbeite gerade das AVR-Assembler-Tutorial durch und bin im LCD-Teil
über die Warteschleifen "gestolpert". Die Berechnung habe ich verstanden
und auch anwenden können, mich störte jedoch die Assembler-Fehlermeldung
bei MCU-Takten >15Mhz.
Mit zusätzlichen nop wollte ich nicht operieren, stattdessen schwebte
mir ein Warteschleifenkonstrukt vor, das bei üblichen Frequenzen (bis
20Mhz) funktioniert und wo ich direkt die ms oder µs als Zahl eintragen
kann, ohne erst großartig rumzurechnen. Also quasi einmal rechnen und
dann nur noch einfach anwenden :-)
Mit Hilfe einiger anderer Tutorials kam ich dann auf folgende Lösung:
1
.equ XTAL = 16000000 ; MCU clock in Hz
2
.equ fck = XTAL / 1000 ; clock in kHz
3
4
; some delay routines
5
6
Delay50us: ; 50 us routine
7
.equ c50us = (50*fck)/4000 - 1 ; put values between 1 and 999us here
8
ldi R25,HIGH(c50us)
9
ldi R24,LOW(c50us)
10
rjmp Delayloop
11
ret
12
13
Delay5ms: ; 5 ms routine
14
.equ c5ms = (5*fck)/4 - 1 ; put values between 1 and 999ms here
15
ldi R25,HIGH(c5ms)
16
ldi R24,LOW(c5ms)
17
rjmp Delayloop
18
ret
19
20
Delay30ms: ; 30 ms routine
21
.equ c30ms = (30*fck)/4 - 1 ; put values between 1 and 999ms here
22
ldi R25,HIGH(c30ms)
23
ldi R24,LOW(c30ms)
24
rjmp Delayloop
25
ret
26
;
27
; delayloop, awaits values in R25:R24
28
;
29
Delayloop:
30
sbiw R24,1
31
brne Delayloop
32
ret
So weit, so gut. Wenn ich die Takte nachrechne und mit Hilfe dieser die
Zeit berechne, so komme ich immer auf korrekte Werte.
Wenn ich aber mit dem Oszi nachmesse, dann sind die tatsächlichen Zeiten
immer ein wenig länger.
Nun kommt aber das (für mich) erstaunlichste. Wenn ich unter Verwendung
der obigen Routinen eine längere Warteschleife erzeugen möchte (z.B. ca.
1s), dann sind die Zeiten spürbar kürzer.
Ich versuchte es so:
1
longdelay:
2
sbi PORTC, 0
3
ldi Temp3, 40 ; wait 1200ms
4
loop:
5
rcall Delay30ms ; 30ms x 40
6
dec Temp3
7
brne loop
8
cbi PORTC, 0
9
ret
Das Signal auf PORTC dient der Messung durch das Oszi.
Was für einen Denkfehler mache ich?
Ralf G. schrieb:> Mehr als 16ms passen nicht in deine zwei Register. (Wenn ich mich jetzt> nicht verzählt habe)
Oh ja, stimmt!. Ich hab's gerade nachgerechnet :(
OK, das erklärt den Zeitschwund. Meine 30ms sind gar keine...
Danke! Manchmal ist man echt betriebsblind...
Also wenn ich Delay50us nachrechne, so komme ich auf 806 Takte, incl.
rcall&ret, bei 16 MHz also 50.375 us.
Nur am Rande: die ret nach den rjmp Delayloop sind überflüssig.
S. Landolt schrieb:> Also wenn ich Delay50us nachrechne, so komme ich auf 806 Takte, incl.> rcall&ret, bei 16 MHz also 50.375 us.
Ja, die 50us stimmen ja auch. Bei den 30ms haut es nicht mehr hin.
> Nur am Rande: die ret nach den rjmp Delayloop sind überflüssig.
Danke!
Gruß
Ralf
Ich bezog mich auf:
> Wenn ich aber mit dem Oszi nachmesse, dann sind> die tatsächlichen Zeiten immer ein wenig länger.
Und verstehe jetzt
> Ja, die 50us stimmen ja auch.
nicht.
S. Landolt schrieb:> Und verstehe jetzt>> Ja, die 50us stimmen ja auch.> nicht.
Ich wollte damit sagen, dass die 50us rechnerisch stimmen.
Messtechnisch weiß ich gerade nicht mehr genau welche Zeiten länger
waren. Ich habe am letzten Wochenende an mehreren Routinen Messpunkte
eingebaut und nachgemessen.
Ich messe noch einmal nach.
c-hater schrieb im Beitrag #5000393:
> Bullshit. [...]
Vielen Dank für die konstruktive Kritik. Darüber freut sich doch jeder
Anfänger und ist anschließend schwer motiviert!
Ein kleines Bespiel, wie man die angestrebte Verzögerung ohne
"stumpfblöde Delays" hinkriegt, wäre hingegen höchst demotivierend
gewesen und hätte mich garantiert mit gesenktem Haupte in die nicht
weniger stumpfblöde Arduino-Ecke zurückwandern lassen.
Mea maxima culpa...
c-hater schrieb im Beitrag #5000393:
> Bullshit. Ein- bis zweistellige µs mögen noch halbwegs OK sein, ms sind> aber definitiv Zeiträume, die man nicht mehr mit stumpfblöden Delays> wartet. Jedenfall nicht in Assembler.
Ketzerische Frage: Wenn die Anwendung sowieso warten muss, welche Gründe
sprechen denn gegen die 'stumpfblöden Delays', von der Ästhetik mal
abgesehen?
c-hater schrieb im Beitrag #5000484:
> Man muss bloß nicht stinkendfaul sein...
Man muss aber auch nicht respektlos und beleidigend sein!
Was soll das? Habe ich dir was getan? Habe ich dich beleidigt?
Warum beleidigst du mich????
Wenn du meinen Eingangspost gelesen hättest, dann wüsstest du, dass ich
Anfänger bin und mich gerade durch das Assembler-Tutorial arbeite. Das
Kapitel "Timer" hab ich noch nicht erreicht, wohl aber die
Verzögerungsschleifen.
Mir "Stinkendfaulheit" zu unterstellen ist eine absolute
Unverschämtheit!!!
So was kannst du dir wirklich sparen.
Aber wenn man als Gast mit Pseudonym unterwegs ist, dann kann man ja
auch mal rumpöbeln. Gibt es hier keine Moderatoren, die so einen Müll
einfach LÖSCHEN????
Ralf J. schrieb:> Mir "Stinkendfaulheit" zu unterstellen ist eine absolute
Bedenke:Wie man in den Wald hinein ruft,... merkt sich das Netz.
Schleifen haben teilweise unterschiedliche Laufzeiten: z.B. wenn ein
anderer Takt verwendet wird od. bei einem Prozessor ein Interrupt
auftaucht, der auch Zeit verbraucht.
Hallo Oszi40,
das mit der Laufzeit und der Interrupt-Anfälligkeit ist mir durchaus
bewusst. Darauf hinzuweisen finde ich aber gut, weil es mich als
Lernenden einfach weiterbringt.
Kommentarte, die mit "Bullshit" beginnen und im nächsten Post mit
"Stinkendfaul" enden, bringen mich aber nicht weiter! Ganz im Gegenteil!
Zum Punkt "wie man in den Wald hineinruft..." kann ich nur antworten,
dass ich nicht mit der Vulgärsprache angefangen habe :-)
Gruß
Ralf
Jo, geht mal wieder zur Sache hier ;-)
Mal im Ernst: Ich kann die Empörung des Themenstellers vollkommen
verstehen.
Unsachliche, arrogante und beleidigende Posts, wir die von C-hater,
haben hier nichts zu suchen und gehören entfernt!
Die Fragen eines Anfängers waren nachvollziehbar und vernünftig
gestellt. Der Junge arbeitet sich gerade durch das Tutorial, zeigt
Initiative und Interesse. Es gibt keinen vernünftigen Grund so jemanden
mit Beleidigungen und Beschimpfungen herunter zu putzen!
Meine Meinung!
Gute Nacht und Grüße
Bernd
@Hardcoder: Ich sehe das ebenso. Unangemessen und vor allem niveaulos.
Natürlich kann man Timer googeln, dafür muss man aber erst einmal von
deren Existenz wissen, gerade für Anfänger nicht klar...
@Rolf: Weiter so! Lass dich nicht von idiotischen Antworten
verunsichern. Die gibt es hier leider viel zu oft...
MfG
Gerd
c-hater schrieb im Beitrag #5000393:
> Bullshit.
@c-hater: Bullshit ist, die Idee eines Anfängers (nämlich eine
universelle Warteroutine zu schreiben) pauschal zu verunglimpfen!!
Stindendfaul ist der, der keine wirklichen Alternativen aufzeigt,
sondern auf Google verweist! Wenn wir alles Googeln könnten und würden,
welchen Sinn hätte dann dieses Forum??
@MODS: Der Bullshit von c-hater gehört gelöscht!
@Cosmicos: guckst du z.B. hier:
http://www.avrfreaks.net/comment/693064#comment-693064
Ein typischer Anfängerfehler ist es, auf c-hater überhaupt zu reagieren.
Wollte ich eigentlich schreiben, aber eben ist es mir an anderer Stelle
selbst passiert. Schlecht. Aber ich arbeite dran, ich arbeite dran...
Guten Morgen alle zusammen,
vielen Dank für eueren Zuspruch!
Ich merke mir den Namen c-hater auf jeden Fall und werde solch
destruktive Kommentare in Zukunft ignorieren.
Jetzt gehe ich erst einmal in den Hobbykeller und schaue mir die
Timer-Interrupts näher an :-)
LG
Ralf
> destruktive Kommentare in Zukunft ignorieren
Exakt so und nur so; denn oft genug kommen aus dieser Ecke brauchbare
Ideen und Anregungen, diese nimmt man stillschweigend mit, selten genug
allerdings sind sie nicht mit Unverschämtheiten durchsetzt, diese
überliest man; und darf sie auf gar keinen Fall persönlich nehmen, denn
so sind sie tatsächlich nicht gemeint, es ist nur der übliche
Umgangston.
S. Landolt schrieb:> Exakt so und nur so; denn oft genug kommen aus dieser Ecke brauchbare> Ideen und Anregungen, diese nimmt man stillschweigend mit, selten genug> allerdings sind sie nicht mit Unverschämtheiten durchsetzt, diese> überliest man;
Ich habe gerade in einigen anderen Threads gestöbert und bin tatsächlich
oft auf Äußerungen von c-hater gestoßen, die ich einfach nur als dumpf,
vulgär, unter der Gürtellinie und grob beleidigend bezeichnen kann.
Da bin ich ja (noch) gut weggekommen :-D
Trotz des durchklingenden Fachwissens bin ich der Meinung, dass man so
etwas nicht hinnehmen kann.
Vielleicht ist das ein grundsätzliches Problem offener Foren, die
Gastbeiträge zulassen und auch auf Beschwerden der User offenbar nicht
reagieren, aber normal ist das nicht. So etwas habe ich in anderen Foren
noch nicht erlebt.
Vielleicht sollten die Betreiber dieses Forums, das an sich hervorragend
ist, dies mal als Denkanstoß nehmen??
Man traut sich als Anfänger ja kaum was zu schreiben, weil man sich
sonst schnell eine Beleidigung einfängt :-(
Hi
Das Gastschreibrecht hat durchaus Seine Berechtigung.
Wenn das Forum durch Zufall gefunden wird und man eine Idee/Lösung zu
einem Problem hat, muß man sich nicht anmelden und hat schon wieder
Seine eMail-Addy in den Tiefen des WWW den Spam-Bots ausgeliefert.
Auch meldet man sich kaum für nur einen Post an.
Wobei die Dauer-Gäste mit dem Argument nicht durch kommen.
Sieh Es doch positiv:
Der Hater hat einen Rüffel bekommen und hat zumindest bis jetzt hier in
dem Thread Nichts mehr abgesondert.
Somit auch keine Beleidigung oder sonstiges Zeug, bei Dem Du dann 'nicht
mehr so gut' weg kommst :)
Ralf J. schrieb:> Da bin ich ja (noch) gut weggekommen :-D
MfG
Ralf J. schrieb:> Ich habe gerade in einigen anderen Threads gestöbert und bin tatsächlich> oft auf Äußerungen von c-hater gestoßen, die ich einfach nur als dumpf,> vulgär, unter der Gürtellinie und grob beleidigend bezeichnen kann.
Das ist Einer von schätzungsweise 10 "Lautsprechern", die entweder einen
irrsinnigen Spaß am Beleidigen oder aber ein Selbstbewußtsein, das für
10 Personen ausreichen würde in sich vereinen. Jeder, der eine Woche
mitgelesen hat, kennt sie dann.
Ralf J. schrieb:> Vielleicht sollten die Betreiber dieses Forums, das an sich hervorragend> ist, dies mal als Denkanstoß nehmen??
Komm nicht auf den Gedanken, Dich wehren zu wollen, dann bist DU weg,
nicht der große Könner.
Es gibt die Möglichkeit, Nutzer auszublenden. Das ist das Einzige, was
man gegen diese Plage tun kann.
Ralf J. schrieb:> ...mit gesenktem Haupte in die nicht> weniger stumpfblöde Arduino-Ecke zurückwandern lassen.>
Hallo erstmal und herzlich willkommen in diesem wunderbaren Forum.
Ich hoffe du hälst durch und bleibst am Ball. Meistens lohnt es sich
nicht Assembleränfängern die auch noch wenige Posts hier geschrieben
haben zu antworten, da sie dies meist für irgendwelche Prüfungen bzw.
die Schule brauchen und man dann nichts mehr von ihnen liest.
Ich finde eines, was man einem Anfänger ziemlich schnell in der
µC-Assemblersprache beibringen sollte ist, per Interrupt eine mehr oder
weniger universelle Zeitbasis zu erstellen. Warten ist für mich in der
ASM-Programmiersprache, so etwas wie die Perlen vor die Säue werfen.
Und in Zeiten wo alle von Energiesparen reden, legt man den µC lieber
schlafen, also in einem Energiesparmodus, als ihn für mehre Takte warten
zu lassen, denn aus so einem SLEEP-MODUS, wacht dieser auch relativ
schnell auf.
Hier mal zwei Beispiele, wo man gut erkennen kann was ich meine.
Irgendwann gewöhnt man sich vielleicht einen Anfängerprogrammierstil an,
der einem bei der Fehlersuche immer wieder wahnsinnig macht.
Beitrag "Einzelnen Taster entprellen"Beitrag "Re: AVR-Mikrocontrollertechnik-Kursus in Assembler besprechung"
Bernd_Stein
Bernd S. schrieb:> Ich hoffe du hälst durch und bleibst am Ball. Meistens lohnt es sich> nicht Assembleränfängern die auch noch wenige Posts hier geschrieben> haben zu antworten, da sie dies meist für irgendwelche Prüfungen bzw.> die Schule brauchen und man dann nichts mehr von ihnen liest.
Hallo Bernd, danke für deinen Post und die interessanten Links!
Über Prüfungen in der Schule bin ich zum Glück hinaus, ich stehe schon
länger auf der anderen Seite des Pultes ;-)
AVR und Assembler sind ein reines Hobby und daher habe ich eine hohe
Motivation und auch Durchhaltewillen. Ich finde das alles einfach mega
interessant und kann es auch konkret in anderen Hobbys einsetzen (z.B.
im Modellbau).
Ich bleibe am Ball!
Grüße
Ralf
Ralf J. schrieb:> Ich bleibe am Ball!>
Das ist sehr schön, so habe ich einen weiteren Mitstreiter, der in etwa
auf meinem Wissensstand ist und mit dem ich mich hier über die eine oder
andere für mich interessante AVR-ASM-Frage austauschen kann.
Zufälligerweise hat sich bei mir in einer Übungsaufgabe, durch Antworten
der anderen User eine Frage ergeben, die ganz gut zu deiner hier
gestellten Frage passt und eine schöne Übung für uns ist, um zu
erkennen, ob wir wirklich verstanden haben, wie so etwas zu berechnen
ist.
Es ist natürlich auch eine kleine Fleißaufgabe, da du wahrscheinlich
genau so wenig wie ich, dir sicher bist, wie viele Takte die nun
folgenden Befehle haben und dies dann erstmal ermittelt werden muss.
Danach geht es aber schon los mit dem Verständnis dieser Schleife,
wenn man die erste Hürde richtig genommen hat und erkannt hat,
wieviele " B's " denn geschrieben wurden. Der µC ist ein ATmega bzw.
ATmega8.
Da ich finde, das da schon so einiges zusammenkommt für einen Anfänger,
will ich einige Erläuterungen zuvor abgeben :
Es geht hierbei vorrangig um die indirekte Addressierung und im Detail
um das Post-Inkrement. Was bedeutet, das zuerst der Zeiger bzw.
Pointer auf die entsprechende SRAM-Speicheradresse initialisiert wird
( Y-Zeiger ) und dann in der Schleife der Buchstabe " B ", in diese
Speicherzellen geschrieben wird, wobei jedesmal überprüft wird
( CPI-Befehl ), ob das gewünschte Speicherbereichende erreicht ist.
Post-Inkrement bedeutet, das zuerst in die Speicheradresse geschrieben
wird und dann der Zeiger um eins erhöht wird.
1
ldi r16,'B'
2
ldi yl,$60
3
ldi yh,$00
4
_NEXT:
5
st y+,r16
6
cpi yh,$04
7
brne _NEXT
8
cpi yl,$00
9
brne _NEXT
10
nop
11
12
.EXIT
Die Anzahl der Takte ergibt sich zu " Anzahl der B's x5 -1 +5 ".
Der NOP-Befehl wird nicht mitbetrachtet, da dieser nur für den
Breakpoint im Simulator gebraucht wurde.
Eine Bonuserkenntnis ist, zu bemerken, das hierbei zwei Zeilen und somit
2-Takte unnötig sind. Das hat jedoch mit reiner Logik zu tun, die schon
mal zu wünschen übrig läßt, wenn man sich erstmal mit so vielen Details
herumschlagen muss.
Bernd_Stein
Bernd S. schrieb:> Eine Bonuserkenntnis ist, zu bemerken, das hierbei zwei Zeilen und somit> 2-Takte unnötig sind. Das hat jedoch mit reiner Logik zu tun, die schon> mal zu wünschen übrig läßt, wenn man sich erstmal mit so vielen Details> herumschlagen muss.
Zweite Erkenntnis wäre, zu erkennen, dass dieses Beispiel so nicht viel
Sinn ergibt. Falls RAM bei 0x60 begint, endet es nicht bei 0x400,
sondern bei 0x45F.
Somit ist deine Annahme, dass 2 Zeilen unnötig sind, schon hinfällig.
Dritte Erkenntnis wäre, dass es vielleicht doch so gewollt ist, da
sonst der Stack überschrieben werden könnte.
Vierte Erkenntnis wäre, dass deine Rechnung mit Taktanzahl nicht
richtig ist.
usw.
P.S.
Normallerweise wird zuerst geprüft und erst danach etwas
reingeschrieben, nicht umgekehrt.
Immer neue Erkenntnise... ;-)
Bernd S. schrieb:> Es ist natürlich auch eine kleine Fleißaufgabe, da du wahrscheinlich> genau so wenig wie ich, dir sicher bist, wie viele Takte die nun> folgenden Befehle haben und dies dann erstmal ermittelt werden muss.
Hallo Bernd,
ich bin zwar noch gar nicht bei den Zeigern im AVR-Tutorial angekommen,
habe aber dennoch mit meinem Kenntnisstand versucht, die Takte zu
berechnen.
Also erst einmal ein Blick ins Datenblatt, um zu schauen, welcher Befehl
wie viele Takte verbraucht:
1
Register
2
Takte Dezimal
3
ldi r16,'B' 1
4
ldi yl,$60 1 (96)
5
ldi yh,$00 1
6
_NEXT:
7
st y+,r16 2
8
cpi yh,$04 1 (1024)
9
brne _NEXT 2/1
10
cpi yl,$00 1
11
brne _NEXT 2/1
Dann ausrechnen. Ich komme auf folgende Formel:
3 + (5 * 928) - 1 + 3 - 1 = 4644
Die beiden Befehle, die meines Erachtens überflüssing sind, sind die
beiden letzten. Das Low-Nibble ist beim Schleifenende der ersten
Schleife bereits Null...
Wie habe ich mich geschlagen :-)
Marc V. schrieb:> Falls RAM bei 0x60 begint, endet es nicht bei 0x400,> sondern bei 0x45F.
Aha, warum das? Ich bin jetzt mal vom einfachen Hochzählen ausgegangen.
Also von 0x0060 bis 0x0400, was dann 928 Schleifendurchläufe ergeben
würde...
Ralf J. schrieb:> Aha, warum das? Ich bin jetzt mal vom einfachen Hochzählen ausgegangen.
Weil das 1KB RAM ergibt.
Auf Adressen von 0x00 bis 0x5F befinden sich (beim M8) Register.
Hier ist etwas für euch beide, läuft mit ganzzähligen Werten für
Frequenz und Dauer ziemlich genau (rcall und ret nicht gerechnet).
Frequenz von 1-16MHz
Dauer von 1-20ms (für 16MHz, langsamere Frequenzen können entspr.
länger, z.B. 8MHz von 1-40ms)
Und als Übung kannst du versuchen, längere Zeiten mit 16MHz zu
kriegen oder Zeiten kürzer als 1ms zu erreichen. :)
P.S.
Oder einen Fehler zu finden, ist zwar im Simulator probiert, aber
aus dem Kopf geschrieben - alle gefundenen Fehler darfst du
natürlich gerne behalten...
Ralf J. schrieb:> 3 + (5 * 928) - 1 + 3 - 1 = 4644>> Wie habe ich mich geschlagen :-)>
Super hast du dich geschlagen. Alles richtig. Sogar dran gedacht, das
beim Branch-Befehlen jeweils einmal ein Takt abzuziehen ist.
@Marc Vesely. Danke für die Anregung, es ist mir aber zu kompliziert und
da ich bei meinem Lehrgang auch weiter kommen möchte, nehme ich mir
hierzu auch nicht die Zeit. Außerdem halte ich nichts davon einem µC
damit zu beschäftigen, das er die Zeit vertrödelt.
Bernd_Stein
Marc V. schrieb:> Und als Übung kannst du versuchen, längere Zeiten mit 16MHz zu> kriegen oder Zeiten kürzer als 1ms zu erreichen. :)
Hallo Marc,
danke für deine Anregungen. Dein Beispiel entspricht exakt den
Warteschleifen meines Eingangsposts in diesem Thread :-)
Die habe ich nun schon zu Genüge berechnet (und auch den Denkfehler
gefunden). Dank der Anregung vom hater würde ich ein solches Konstrukt
aber nicht im ms-Bereich verwenden.
In die Alternative, die Timer, muss ich aber erst noch einlesen.
> Weil das 1KB RAM ergibt.> Auf Adressen von 0x00 bis 0x5F befinden sich (beim M8) Register.
Ja klar. Die Schleife, in ihrer obigen Form, macht aber dennoch IMHO
keine 1024 Durchläufe, sondern lediglich 928. Darum ging es ja und nicht
um den Sinn oder Unsinn dieser Schleife...
Grüße
Ralf