Alles wird hinterfragt ^^. Es geht hierbei um den Abschnitt "Ausgabe eines konstanten Textes" im Tutorial: http://www.mikrocontroller.net/articles/AVR-Tutorial:_LCD Meine Fragen sind: Funktioniert der Z-Pointer ähnlich wie der Stack? Wie ich das sehe kann der Z-Pointer 16bit speichern in High und Low. ist das Richtig? Kann man ein ASCII Zeichen den Code verändern? z.B. für ä ein $E1. Warum wird hier text*2 in den Z-Pointer geladen? Und nochmal eine Frage zum Stack: Warum wird "out SPL, temp1" ein leeres Register in den Stack geschrieben?
@ Michael Dierken (etzen_michi) >Funktioniert der Z-Pointer ähnlich wie der Stack? Naja, eher nicht. >Wie ich das sehe kann der Z-Pointer 16bit speichern in High und Low. ist >das Richtig? Ja. >Kann man ein ASCII Zeichen den Code verändern? z.B. für ä ein $E1. ??? Eher nicht. >Warum wird hier text*2 in den Z-Pointer geladen? http://www.mikrocontroller.net/articles/AVR-Tutorial:_Mehrfachverzweigung#Z-Pointer_leicht_verst.C3.A4ndlich >Warum wird "out SPL, temp1" ein leeres Register in den Stack >geschrieben? Das ist nicht leer, bestenfalls Null. MFG Falk
Michael Dierken schrieb: > Alles wird hinterfragt ^^. > > Es geht hierbei um den Abschnitt "Ausgabe eines konstanten Textes" im > Tutorial: http://www.mikrocontroller.net/articles/AVR-Tutorial:_LCD > > Meine Fragen sind: > > > Funktioniert der Z-Pointer ähnlich wie der Stack? Nein. > > Wie ich das sehe kann der Z-Pointer 16bit speichern in High und Low. ist > das Richtig? Ja, aber... Denn der Z-Pointer ist das, was Du mit ihm machst. Er kann als zwei normale Register benutzt werden, aber auch als Pointer (Zeiger, Adresszeiger). Er kann auf SRAM zeigen, aber auch auf Flash, siehe dazu die Hilfetexte der Befehle, die den Z-Pointer benutzen. Eine Befehlsübersicht findest Du im Datenblatt unter Instruction summary. > > Kann man ein ASCII Zeichen den Code verändern? z.B. für ä ein $E1. Das ist keine Frage des Z-Pointers, sondern der Schreibweise. Es gibt verschiedene Schreibweisen, die alle irgendwo in der Hilfe zum AVR-Studio erklärt werden, einfach mal ein bisschen in der Hilfe herumstöbern. > > Warum wird hier text*2 in den Z-Pointer geladen? Weil der Befehl "lpm" den Flash byteweise adressiert, siehe Hilfe zu LPM und die Erklärung der Memories im Datenblatt. > > > Und nochmal eine Frage zum Stack: > > Warum wird "out SPL, temp1" ein leeres Register in den Stack > geschrieben? Wieso ein leeres Register? Man lädt doch zuvor mit "ldi temp1, low(ramend)" die Adresse des RAM-Endes in das Register, ehe man es in den Stackpointer schreibt. ...
Eine weitere Frage: In dem auf dem hingewiesenen Teil des Tutorials wird sowohl ZL als auch ZH mit text*2 geladen. Wozu wird das ZH in diesem Falle verwendet? Das ZL wird dazu verwendet das der Text ausgelesen werden kann, aber wozu ist das ZH da?
Mensch, ZH und ZL gehören zusammen, das ist ein 16 Bit Pointer, verteilt auf zwei 8 Bit Register. RTFM!
Mensch .. warum funktioniert das wenn ich ZH wechlasse? Irgendwie verstehe ich das mit dem Z-Pointer und vorallem .db nicht ganz .. lese auch schon TFM aber i-wie komm ich da auchnicht weiter ....
Ich will das nicht nur nachmachen können .. ich will das nachvollziehen können.
Michael Dierken schrieb: > Mensch .. warum funktioniert das wenn ich ZH wechlasse? Weil höchst wahrscheinlich dein Programm kurz genug ist, dass der Text an einer Stelle im Speicher zu liegen kommt, an dem das höherweertige Byte der Adresse gleich 0 ist. Du kannst natürlich auch die Sparbuchzinsen eines Sparbuchs ausrechnen, indem du immer nur Zahlen bis 100 berücksichtigst. Bei einem Schüler mit einer Einlage von 25 Euro ist das kein Problem. Da kommt dann sogar das richtige raus. Wenn du aber etwas mehr auf dem Sparbuch hast, und der Banker rechnet dir die Zinsen anstelle von 2568 nur von 68 Euro aus (weil nur kleiner 100 in die Rechnung eingehen), dann wirst du zu Recht maulen. > > Irgendwie verstehe ich das mit dem Z-Pointer und vorallem .db nicht ganz Ist doch ganz einfach. Der Z-Pointer ist ein Zettel, auf dem steht: Der eigentliche Text (und da der nächste Buchstabe) ist in der Kommode, in Schublade 4 zu finden. Der Befehl LPM geht jetzt her, liest den Zettel und benutzt die Information auf dem Zettel (Kommode, Schublade 4) um von genau dort, Kommode/Schublade 4, den Buchstaben zu holen. Und wenn du dann auf den Zettel draufschreibst: Kommode / Schublafe 5, dann wird der LPM beim nächsten Zugriff eben zur Schublade 5 in der Kommode greifen um von dort den nächsten Buchstaben ins R0 zu laden.
Hoffe das jetzt keine Beschwerden kommen .. habe ich es so richtig verstanden? (Anhang, da es auf papier irgendwie einfach ist zu erklären) (Habe nochmal mit 1/4 der Auflösung hochgeladen.)
Daher das ich die Info bekomme habe dass das Bild wohl zu klein sein soll (da will man sich mal an die Upload Regeln halten) schriebe ich das hier nochmal so hin. 0 1 2 3 4 5 6 7 8 9 A B C D E F +------------------------------------------------+ | | | H i e r s t e h t d a s P | 0 | | +------------------------------------------------+ | | | r o g r a m m | 1 | | +------------------------------------------------+ | | | | 2 | | +------------------------------------------------+ | | | H i e r s t e h t d e r T | 3 | | +------------------------------------------------+ | | | e x t $00 | 4 | | +------------------------------------------------+ | | | | 5 | | +------------------------------------------------+
1 | ldi ZL, LOW(text*2) ; Lädt den Anfang von text (Byte H, |
2 | ldi ZH, High(text*2) ; Adresse 0x30) in den Z-Pointer |
3 | |
4 | lpm temp1, Z+ ; Kopiert das Byte (H) aus dem |
5 | ; Z-Pointer in temp1 |
6 | ; Und erhöt den Z-Pointer um |
7 | ; eins auf 0x31 |
8 | |
9 | cpi temp1, 0 ; Schaut nach ob der Inhalt von |
10 | ; temp1 = 0 ist uns setzt Z-Flag |
11 | ; wenn dem so ist |
12 | |
13 | text: |
14 | .db "Hier steht der Text", 0 |
Nach dem cpi kann man brne oder breq nutzen je nachdem ob ein Sprung ausgeführt werden soll sobald die kompletten Werte aus .db abgearbeitet wurden. Wenn dies alles richtig ist, was ist wenn mit .db ein Wert gespeichert wird welcher ein Byte besitzt welches komplett auf 0 steht?
Das hängt davon ab, was dem "cpi temp1,0" folgt. Beim Programm aus dem Tutorial würde die Schleife direkt am Anfang abgebrochen. Es ist ein bisschen wie die Frage: "Was passiert, wenn ich in Köln bin und nach Köln will?"
Was hängt davon ab was dem "cpi temp1, 0" folgt? Noch eine Frage: Habe jetzt verstanden wozu er das *2 in ldi SPL, LOW(text*2) braucht ^^. Aber da komtm ja gerne eine 9Bit lange adresse raus ... wie macht er dass? ... Schaut er direkt vorm bearbeiten nach ob das obere oder untere Bit geladen werden muss? Und speichert die dann direkt Bit 1-8ab? Arbeitet er mit den nächsten 2Byte und hat somit das Bit7 des ersten Byte im Bit0 des zweiten Byte? (so langsam fange ich an durch zu steigen .. zuindest hoffe ich das).
Michael Dierken schrieb: > Was hängt davon ab was dem "cpi temp1, 0" folgt? Das war die Antwort auf Deine Frage ".. was ist wenn mit .db ein Wert gespeichert wird welcher ein Byte besitzt welches komplett auf 0 steht?" Zu Deinem aktuellen Verständnis-Problem: Michael Dierken schrieb: > Aber da komtm ja gerne eine 9Bit lange adresse raus ... wie macht er > dass? ... Ich nehme mal an, mit "er" meinst Du Deinen Assembler. "LOW" ist ein Makro, was aus einer 16-Bit Zahl die unteren 8 Bits herausholt, "HIGH" ist ein Makro, das die oberen 8 Bit herausholt. LOW(0x1234) wird als 0x34 ausgewertet. HIGH(0x1234) wird als 0x12 ausgewertet. ZL und ZH bilden zusammen eine Adresse. Zu Deinem Posting: Du solltest Dir erst mal mit Dir selbst einig werden, ob Du die Bits von 0 bis 7 oder von 1 bis 8 durchnummerierst. ("Und speichert die dann direkt Bit 1-8ab?" und "das Bit7 des ersten Byte im Bit0 des zweiten Byte?") Üblich ist 0 bis 7, trotzdem gibt es immer wieder Missverständnisse, z.B. bei der Beschriftung des Pollin Atmel Evaluation Boards. Bitte schreibe etwas langsamer. Die Sekunden, die Du sparst, wenn Du Wörter wie "in", "auf" und "bei" einfach weg lässt, werden für alle anderen hier lästige Minuten, die sie darüber nachgrübeln, was Du wohl meinen magst. Leerzeichen sind auch nicht nur aus optischen Gründen da. Weniger lässig ist cooler. Auch wenn es im SMS-Zeitalter üblich geworden ist, im Telegrammstil zu kommunizieren, ist es in einem Forum, in dem technische Sachverhalte besprochen werden, fehl am Platze. Die "..." kannst Du gerne weglassen. Flüchtigkeitsfehler, wie "ldi SPL, LOW(text*2)" (Statt "ldi ZL..") vermeidet man, wenn man seinen Text vor dem Abschicken nochmal durchliest. Ich könnte noch einiges mehr dazu schreiben, aber ich fasse es mal wie folgt zusammen: Hier sind viele Leute, die Dir ohne Bezahlung mit Deinen Problemen helfen. Sie investieren Zeit und geben sich Mühe mit Dir, obwohl sie Dich nicht einmal kennen. Es sollte Dir eigentlich von selbst klar sein, dass Du diese Mühe dadurch honorieren solltest, dass Du Dir mit Deiner Frage mindestens gleich viel Mühe gibst!
Tach ... Was die Leerzeichen angeht konnte ich jetzt leider nicht sehen, welche Stellen du meinst. Das gleiche gilt für auf, bei und in. Lese mir auch den Text in der Regel immer noch einmal durch (Verwende ganz brav den "Vorschau" Button). Ich muss zugeben das ich mit der Groß und kleinschreibung etwas gegeizt habe. Das mit der Nummerierung 1-8 und 0-7 war absichtlich so. Nehmen wir den Wert $47. Dieser hat 8Bit Länge. Der wird nun *2 genommen wodurch ein Wert mit 9 Bit länge entsteht. Hier rauf bezieht sich meine Frage. Das LSB dieses 9Bit Stranges bestimmt soweit wie ich das verstanden habe ob die unteren 8 oder oberen 8Bit bei lpm temp1, Z+ in das Register kopiert werden. Meine Frage ist nun wie er das macht, dass von den 8Bit nichts verloren geht, da er wenn ich mich nicht irre immer nur 8Bit abspeichern kann.
Der Z-Pointer besteht aus 2 8 Bit-Registern. Dein Beispielwert ist nun wenig geignet, da 0x47 * 2 0x8E ist, aber egal. Das LSB einer Multiplikation mit 2 ist immer 0. Michael Dierken schrieb: > ..ob die unteren 8 oder oberen 8Bit bei lpm temp1, Z+ in das Register > kopiert werden. Welches Register? Bei der Operation sind 3 Register beteiligt, die alle verändert werden. Das Register temp1 erhält den Wert, der in der Speicherstelle steht, auf die der Z-Pointer zeigt. Der Z-Pointer, bestehend aus den Registern r30 und r31 (alias ZL und ZH) wird danach um 1 erhöht, indem r30 um eins erhöht wird, und der Übertrag zu r31 addiert wird.
Hi >Nehmen wir den Wert $47. Dieser hat 8Bit Länge. Wenn man führende Nullen weglässt, genaugenommen nur 7 Bit. >Der wird nun *2 genommen wodurch ein Wert mit 9 Bit länge entsteht. >Hier rauf bezieht sich meine Frage. Auch nicht so richtig. $47 x 2 = $8E. Und das passt immer noch in 8 Bit. Erst bei Werten >7F ergibt sich bei der Verdopplung ein Übertrag. >Meine Frage ist nun wie er das macht, dass von den 8Bit nichts verloren >geht, da er wenn ich mich nicht irre immer nur 8Bit abspeichern kann. Ich nehme mal an das bezieht sich auch auf LPM. Bei z.B. ldi ZL, LOW(text*2) rechnet der Assembler erst text*2 aus, und lädt dann den Low-Teil davon nach ZL. Wo soll da etwas verloren gehen. MfG Spess
Beim schreiben der Antwort ist mir grad aufgefallen das ich da wohl doch noch einiges Falsch verstanden habe ... also nochmal: Beim Befehl ldi ZL, LOW(text*2) werden nur die Niedrigeren 8Bit der Adresse im Speicher für die Position der Daten text ins Register ZL geladen. ldi ZH, HIGH(text*2) macht das gleiche mit den 8 höherwertigen Bits im Register ZH. In beiden Fällen wird jeweils die Adresse *2 genommen, was aber bedeutet das wenn sie als MSB eine 1 hat diese Verloren geht. Selbst wenn er diese 8Bit dann wieder durch 2teilen würde hätte er nichtmehr den richtigen Wert, da das damalige MSB doch nirgends mehr gespeichert ist und er an dieser Stelle eine 0 stzen würde. Oder ist die Antwort von Spess so zu verstehen, das er das sozusagen "ohne Ablegen" text*2 ausrechnet, und dann sozusagen kurzzeitig mit 9Bit arbeitet indem er bei den 9Bit nur das LSB beachtet, und das dann noch ohne extra Befehl wieder durch zwei teilt, wo der den Carry als MSB festlegt?? Oder wird das MSB beim übertrag automatisch als Bit0 in ZH geschrieben?
Hi Verstehe es doch mal, das wird einmal beim assemblieren vom Assembler ausgerechnet. Und der rechnet intern sogar mit 64 Bit. Die Register bekommen nur das passende Stück zugewiesen. Und wenn du das mal im Programm machen musst, wird der Übertrag durch das Carry-Flag berücksichtigt.
1 | ldi ZL,low(text) |
2 | ldi ZH,High(text) |
3 | lsl ZL |
4 | rol ZH |
5 | |
6 | oder |
7 | |
8 | ldi ZL,low(text) |
9 | ldi ZH,High(text) |
10 | add ZL,ZL |
11 | adc ZH,ZH |
MfG Spess
Michael Dierken schrieb: > ldi ZL, LOW(text*2) werden nur die Niedrigeren 8Bit der Adresse im > Speicher für die Position der Daten text ins Register ZL geladen. > > ldi ZH, HIGH(text*2) macht das gleiche mit den 8 höherwertigen Bits im > Register ZH. > > In beiden Fällen wird jeweils die Adresse *2 genommen, was aber bedeutet > das wenn sie als MSB eine 1 hat diese Verloren geht. Im Prinzip ja. Nur hat eine Adresse auf dem AVR das nicht. Eine Wort-Adresse! Auf einem AVR sind im Assembler alle Adresse grundsätzlich immer fir Hälfte dessen, was du beim Byteweise durchzählen durch den Speicher erhalten würdest. Dies deshalb, weil AVR wortweise organisiert sind. Jeder Befehl hat ausnahmslos immer eine gerade Anzahl an Bytes (und beginnt damit zwangsweise immer an einer gerade Speicheradresse). Damit kann man das unterste Bit einsparen und dadurch sind alle Adressen grundsätzlich nur die Hälfte. Ausnahme ist der LPM Befehl. Der will eine Byte-Adresse. Daher muss man das Verhalten des Assemblers ins Kalkül ziehen und selber wieder die Wort-Adresse verdoppeln um wieder eine Byte Adresse zu erhalten. > > Selbst wenn er diese 8Bit dann wieder durch 2teilen würde hätte er > nichtmehr den richtigen Wert, da das damalige MSB doch nirgends mehr > gespeichert ist und er an dieser Stelle eine 0 stzen würde. Er hat den richtigen Wert, weil bei 64kByte Speicher die größtmögliche Wort-Adresse nun mal die Hälfte von diesen 64kByte ist. > und dann sozusagen kurzzeitig mit 9Bit arbeitet indem er bei den 9Bit > nur das LSB beachtet, Was hast du immer mit deinen 9Bit Eine Zahl wird verdoppelt und davon wahlweise das High-byte bze. das Low-Byte genommen. Wo ist denn da jetzt das gedankliche Problem? > Oder wird das MSB beim übertrag automatisch als Bit0 in ZH geschrieben? Das verdoppeln geschieht doch Bevor die Zerlegung in Low-Byte und High-byte gemacht wird. Das ist eine ganz normale 16-Bit Operation, die der Assembler da ausführt! Da sind doch Klammern rundum die der Assembler selbstverständlich berücksichtigt! Wenn du willst, kannst du schreiben ldi r18, (2*3)+5 und der Assembler rechnet den AUsdruck aus und erzeugt den Befehl also ob du geschrieben hättest ldi r18, 25 machs doch nicht so kompliziert. Zusätzlich zu + - * / hast du halt noch die Operation "nimm das High Byte" bzw. "nimm das Low-Byte". Du verwendest ja auch Schiebeoperationen ganz normal out portb, 1 << 5 Die Schiebeoperation wird ja auch vom Assembler durchgeführt und dann mit dem Ergebnis der Befehl für den AVR zusammengestellt. out portb, $20 Und hier wird halt von einer 16 Bit Zahl das High Byte genommen ldi r17, HIGH( $8923 ) der Assembler macht daraus ldi r17, $89 und alles ist paletti. Und bei dir ergebit sich halt jetzt die Zahl, in dem der Assembler vorher noch eine andere Zahl verdoppeln muss. Und diese andere Adresse ist 'zufällig' eine Adresse in den Speicher, die als Wort-Adresse angegeben ist. Es ist doch keine Raketentechnik, wenn ein Assembler Ausdrücke berechnen kann und dann mit dem Ergebnis weiterarbeitet. Und ja: Der wertet seine Ausdrücke in 16 Bit aus.
Habe mir das nach ein paar Tagen Pause nochmal angeschaut und gehe mal davon aus das ich es jetzt verstanden habe. (Die Adresse wird sozusagen direkt von Compiler eringeschrieben und erst garnicht vom AVR rumgerechnet.) Tut mir leid das ich euch so damit genervt habe ... aber ich will das nunmal nicht nur nachmachen sondern auch verstehen können. Vielen Dank nochmal an alle die sich solche Mühe gemacht haben .. und das alles kostenfrei ^^. Ich befürchte aber das ich im weiteren Laufe des Tutorials wohl nochmal ein oder zwei Fragen haben werde.
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.