Forum: Mikrocontroller und Digitale Elektronik Erklärung des Sinn des Pointers


von Dennis B. (danrulz81)


Lesenswert?

Hallo zusammen,

ich lese mich gerade durchs AVR-ASM-Tut und wundere mich bei diesen 
Codezeilen:
1
.include "m8def.inc"
2
 
3
    ldi     R16, 0xFF
4
    out     DDRB, R16               ; Port B: Ausgang
5
 
6
    ldi     ZL, LOW(daten*2)        ; Low-Byte der Adresse in Z-Pointer
7
    ldi     ZH, HIGH(daten*2)       ; High-Byte der Adresse in Z-Pointer
8
 
9
    lpm                             ; durch Z-Pointer adressiertes Byte
10
                                    ; in R0 laden
11
    out     PORTB, R0               ; an PORTB ausgeben
12
 
13
ende:   
14
    rjmp ende                       ; Endlosschleife
15
 
16
daten:
17
    .db 0b10101010

Wieso wird nicht einfach das Register R16 mit der Binärzahl gefüllt und 
dann an PORTB ausgegeben? Wieso wird das über den Pointer gemacht? z.B. 
so:
1
 
2
.include "m8def.inc"
3
 
4
    ldi     R16, 0xFF
5
    out     DDRB, R16               ; Port B: Ausgang
6
 
7
    ldi     R16, 0b10101010        
8
                                    
9
    out     PORTB, R16               ; an PORTB ausgeben
10
 
11
ende:   
12
    rjmp ende                       ; Endlosschleife
Macht doch das Programm kürzer. Was genau ist eigentlich der Sinn des 
Pointers? Irgendwie hab ich das aus dem Tutorial nicht ganz verstanden.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Es ist mir jetzt zu aufwändig die exakte Stelle im Tutorial zu suchen. 
Eine Motivation könnte sein:

Vielleicht um zu erklären wie man mit Zahlen aus dem SRAM statt mit 
Konstanten arbeitet?

Stell dir vor, eine andere Routine speichert regelmäßig Werte an die 
RAM-Adresse Daten und der Code oben soll die Werte ausgeben. Das geht 
mit deiner zweiten Lösung ganz schlecht, weil du die Werte ja noch nicht 
kennst...

von heinzwurst (Gast)


Lesenswert?

der sinn ist, das du die daten aus dem programm memory liest, soll ja 
nur ein beispiel sein.

von Michael U. (amiga)


Lesenswert?

Hallo,

das Tutorial bietet Beispiele, mehr nicht. ;)

Dein Version ist kürzer und solange nur ein Wert ausgegeben werden soll 
auch sinnvoll.

Jetzt erweitern wir das mal.

Ausgabe von 40 Bitmustern nacheinander ausgegeben werden:
1
.include "m8def.inc"
2
 
3
    ldi     R17, 40                 ; Anzahl der Werte
4
5
    ldi     R16, 0xFF
6
    out     DDRB, R16               ; Port B: Ausgang
7
 
8
    ldi     ZL, LOW(daten*2)        ; Low-Byte der Adresse in Z-Pointer
9
    ldi     ZH, HIGH(daten*2)       ; High-Byte der Adresse in Z-Pointer
10
 
11
loop:    
12
    lpm     R0, Z+                  ; durch Z-Pointer adressiertes Byte
13
                                    ; in R0 laden und Z erhöhen
14
15
    out     PORTB, R0               ; an PORTB ausgeben
16
17
    dec     R17                     ; Zähler -1
18
    brne    loop
19
20
ende:   
21
    rjmp ende                       ; Endlosschleife
22
 
23
daten:
24
    .db 0b10101010

wäre Deine Version dann auch noch kürzer?

Es kommt letztlich auf das Ziel an, welchen Weg man wählt.

Gruß aus Berlin
Michael

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Zu dem Thema Pointer gibt es übrigens einen guten, allerdings 
englischsprachigen Podcast

Security Now 237: The Power of Pointers
An introduction to the use of "indirection" in computer science, 
security news, and more.
http://www.twit.tv/sn237

In der gleichen Serie werden in loser Folge die Innereien einer CPU von 
Anfang an erklärt.

Security Now 233: Let's Design A Computer
Security Now 235: Machine Language
Security Now 237: The Power of Pointers
Security Now 239: Stacks, Registers, and Recursion
Security Now 241: Hardware Interrupts

Eine Folge dauert ca. 1,5h. Man kann bei den Sendungen Live zusehen 
(Aufzeichnung Mittwochabend) oder die Tage drauf als MP3 oder Video 
downloaden. Heute abend müsste eigentlich mit #243 wieder eine Sendung 
aus der Reihe kommen.

von Michael U. (amiga)


Lesenswert?

Hallo,

Muß mich noch korrigieren, Edit ging nicht mehr...
1
daten:
2
    .db 0b10101010
3
    .db 0b11110000

usw. hier müssen jetzt batürlich die 40 Werte als Tabelle hin

Gruß aus Berlin
Michael

von MarioT (Gast)


Lesenswert?

Michael U. schrieb:
> Jetzt erweitern wir das mal.
>
> Ausgabe von 40 Bitmustern nacheinander ausgegeben werden:

Mußt natürlich auch 40 Daten Anbieten.

von Dennis B. (danrulz81)


Lesenswert?

Michael U. schrieb:

>
1
> daten:
2
>     .db 0b10101010
3
>     .db 0b11110000
4
>
>
> usw. hier müssen jetzt batürlich die 40 Werte als Tabelle hin
O.k. Das macht natürlich Sinn. Danke. Und warum erhöst du den Pointer um 
"1"? Erhöht sich dadurch die Adresse, auf die er zeigt um 1, oder wie 
muss ich mir das vorstellen? Werden dann die Daten immer von unten nach 
oben in den Speicher geschrieben?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Stefan B. schrieb:

> Vielleicht um zu erklären wie man mit Zahlen aus dem SRAM statt mit
> Konstanten arbeitet?

Korrektur: Dann müsste man dann dem Assembler noch mit der .DSEG 
Direktive beibringen, dass die Adresse Daten im RAM steht 
(http://www.mikrocontroller.net/articles/AVR-Tutorial:_SRAM)

Das Beispiel oben liest über den Pointer den Wert aus dem ROM.

von Karl H. (kbuchegg)


Lesenswert?

Dennis Brenzel schrieb:
>> [/avrasm]
>>
>> usw. hier müssen jetzt batürlich die 40 Werte als Tabelle hin
> O.k. Das macht natürlich Sinn. Danke. Und warum erhöst du den Pointer um
> "1"?

Damit er an das nächste 'Byte' rankommt

Am Anfang 'zeigt' der Z-Pointer hier hin

              daten:
--->                 .db 0b10101010
                     .db 0b11110000
                     .db 0b00111000
                     ....

der Wert von dort wird durch

   lpm     R0, Z+

nach R0 geholt  (R0 enthält dann 0b10101010) und gleichzeitig wird der 
Z-Pointer um 1 erhöht, so dass er hier hin zeigt

              daten:
                     .db 0b10101010
--->                 .db 0b11110000
                     .db 0b00111000
                     ....

beim nächsten

   lpm     R0, Z+

wird daher 0b11110000 nach R0 geladen, und gleichzeitig der Z-Pointer 
wieder um 1 Stelle weitergerückt.

              daten:
                     .db 0b10101010
                     .db 0b11110000
--->                 .db 0b00111000
                     ....

Beim nächsten lpm kommt dann der nächste Wert drann, usw, usw.

von MarioT (Gast)


Lesenswert?

Dennis Brenzel schrieb:
> Und warum erhöst du den Pointer um
> "1"? Erhöht sich dadurch die Adresse, auf die er zeigt um 1, oder wie
> muss ich mir das vorstellen?

http://www.avr-roboter.de/controller/befehle/beschreibung/l.html#lpm

Dennis Brenzel schrieb:
> Werden dann die Daten immer von unten nach
> oben in den Speicher geschrieben?

Dennis Brenzel schrieb:
>>> daten:
>>     .db 0b10101010
>>     .db 0b11110000
>> >
Die Daten werden im Programmspeicher(Flash) beim Programmieren abgelegt.

Stefan B. schrieb
ROM?

von Dennis B. (danrulz81)


Lesenswert?

AAAAAAAAAAAHHHHHHHHHH, da geht mir ein Licht auf. Wieso wird das so 
nicht im Tutorial erklärt? Super verständliche Hilfe!
Kann ich statt dessen auch nen X- oder Y-Pointer nehmen?

von Karl H. (kbuchegg)


Lesenswert?

Dennis Brenzel schrieb:
> AAAAAAAAAAAHHHHHHHHHH, da geht mir ein Licht auf. Wieso wird das so
> nicht im Tutorial erklärt? Super verständliche Hilfe!

Weil genau unter der von dir kritisierten Codestelle ein Programm 
angegeben ist, welches genau das macht. Einmal mit der 'alten' Nur-lpm 
Variante, einmal mit den neueren 'lmp Z+,rr' Befehlen. Nur mit 
Textausgabe, aber ansonsten ist es genau das gleiche Prinzip.

> Kann ich statt dessen auch nen X- oder Y-Pointer nehmen?

Datenblatt schauen. Gibt es einen Befehl lpm X+, rr ?

von Dennis B. (danrulz81)


Lesenswert?

Zu spät für nen Edit.
-->hab ich mir selber beantworten können. Laut Tutorial funktionieren X 
und Y Pointer gleich, mit einer Ausnahme: Mit dem X-Pointer ist kein 
Zugriff LDD/STD mit einem Displacement möglich.
Eine Frage bleibt noch? Muss ich den auch initialiesieren, wie bspw. den 
Stackpointer (btw: Warum muss man den eigentlich initialisieren?)?

von Karl H. (kbuchegg)


Lesenswert?

Dennis Brenzel schrieb:

> Eine Frage bleibt noch? Muss ich den auch initialiesieren,

Was verstehst du unter initialisieren?

Klar musst du dem Z-Pointer irgendwann einmal sagen, dass es bei daten 
losgeht. Du könntest ja 5 Tabellen im Programm haben und je nach 
Situation eine andere abarbeiten wollen.

> wie bspw. den
> Stackpointer (btw: Warum muss man den eigentlich initialisieren?)?

Bei neueren AVR muss man das auch nicht mehr. Nimm es einfach als 
gegeben hin, dass du beim Stackpointer für klare Verhältnisse sorgen 
musst.

von Dennis B. (danrulz81)


Lesenswert?

Karl heinz Buchegger schrieb:

> Klar musst du dem Z-Pointer irgendwann einmal sagen, dass es bei daten
> losgeht. Du könntest ja 5 Tabellen im Programm haben und je nach
> Situation eine andere abarbeiten wollen.

Muss ich dem ZL und ZH dann erstmal "0" übergeben, damit er am Anfang 
los läuft? Oder ist das Adressspezifisch?

von MarioT (Gast)


Lesenswert?

1
    ldi     ZL, LOW(welche_Daten_ins_LCD*2)        
2
    ldi     ZH, HIGH(welche_Daten_ins_LCD*2)
3
4
    lpm     R0, Z+
5
;usw
6
7
    ldi     ZL, LOW(Eingang_Text*2)        
8
    ldi     ZH, HIGH(Eingang_Text*2)
9
10
    lpm     R0, Z+
11
;usw
12
13
welche_Daten_ins_LCD:
14
.db 17 ,5 ,1 ,12
15
16
Eingang_Text:
17
.db "Kollektor Solar-VL  Solar-RL  W",0b11100001,"rmet.SekPuffer.o  Puffer.m  Puffer.u  Strahlung "
18
.db "Heizkr.RL WarmwasserHeizkr.VL Aussen    Temp.Raum --------- Durchf.SolKessel.VL "

Ich hoffe es ist Verständlich.

von Karl H. (kbuchegg)


Lesenswert?

Dennis Brenzel schrieb:
> Karl heinz Buchegger schrieb:
>
>> Klar musst du dem Z-Pointer irgendwann einmal sagen, dass es bei daten
>> losgeht. Du könntest ja 5 Tabellen im Programm haben und je nach
>> Situation eine andere abarbeiten wollen.
>
> Muss ich dem ZL und ZH dann erstmal "0" übergeben, damit er am Anfang
> los läuft? Oder ist das Adressspezifisch?

reden wir vom selben?

Hier:

    ldi     ZL, LOW(daten*2)        ; Low-Byte der Adresse in Z-Pointer
    ldi     ZH, HIGH(daten*2)       ; High-Byte der Adresse in Z-Pointer

lädst du den Z-Pointer mit der Startadresse der Daten. Oder um bei 
meinem graphischen Beispiel zu bleiben. Genau diese beiden Anweisungen 
'installieren' den ersten Pfeil in


             daten:
--->                 .db 0b10101010
                     .db 0b11110000
                     .db 0b00111000
                     ....

von Stefan B. (stefan) Benutzerseite


Lesenswert?

MarioT schrieb:

> Stefan B. schrieb
> ROM?

Ich bin ein älterer Herr und verstehe nur ganze Sätze. Wenn "ROM?" nicht 
nur ein rhetorisches Schmankerl ist, frag' einfach nochmal.

von Dennis B. (danrulz81)


Lesenswert?

Ich denk mal ja, so hab ich es verstanden:

Der Wert in den Klammern (hier:welche_daten_ins_LCD und Eingang_Text) 
sagen dem Z-Pointer, bei diesem "Label" musst du den ersten Wert holen. 
Z+ erhöhen, um an den 2. Wert zu kommen usw. Richtig Verstanden?

von MarioT (Gast)


Lesenswert?

Stefan B. schrieb:
> Ich bin ein älterer Herr und verstehe nur ganze Sätze. Wenn "ROM?" nicht
> nur ein rhetorisches Schmankerl ist, frag' einfach nochmal.

Entschuldige! Ich dachte Du hast Dich verschrieben und bemerkst den 
Fehler.
AVR haben kein ROM.

von MarioT (Gast)


Lesenswert?

Dennis Brenzel schrieb:
> Richtig Verstanden?

Ja.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Stimmt, Flash (Datenblatt) oder Flash-ROM oder program space 
(avr-libc, Tutorial) ist gemeint.

von Dennis B. (danrulz81)


Lesenswert?

Super, ich danke euch.

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.