Pointer Zeiger FIFO LIFO

plc_tippser

Level-1
Beiträge
2.500
Reaktionspunkte
308
Zuviel Werbung?
-> Hier kostenlos registrieren
von Volker
user_offline.gif



icon1.gif
pointer
Hier ein paar Beispiele zur indirekten Adressierung / Pointer

Ein Merkerwort laden indem wir den Pointer direkt laden.
Code:
L P#30.0
T MD 10
L MW [MD 10] // lädt das mw30
Dies ist unflexibel.
-----------------------------------

Eleganter geht es, indem wir den Pointer selbst erzeugen und über das Adressregister ansprechen.
Code:
  L     30
  SLD   3
  LAR1                    // ergibt einen pointer von P#30.0 in adressregister1 
  L     MW [AR1,P#0.0]    // lädt das mw30
Schon besser. Aber warum schieben wir 3 nach links?
Das liegt am Aufbau des Pointer. vereinfacht: Byteadress(16Bit).Bitadress(3Bit). (genauerers im Bild im Anhang)
Die 30 liegt also durch das schieben in der Byteadresse. die Bitadresse ist 0.
-----------------------------------

Nun gibt es noch den Versatz (p#0.0). Dieser wird zum Pointer im Adressregister hinzuaddiert.
Code:
  L     MW [AR1,P#2.0]    // lädt das mw32 (30 + 2.0)
  U     M [AR1,P#4.4]     // fragt M 34.4 ab
Fast perfekt.
-----------------------------------

Nun wollen wir auch noch die Bitadresse fexibel gestalten.
Code:
  L     30
  SLD   3
  LAR1                    // im ar1 steht p#30.0
  L     4
  +AR1                    // die 4 wird zum ar1 hinzuaddiert. im ar1 steht jetzt p#30.4
  U     E [AR1,P#0.0]     // fragt e30.4 ab
  L     EW [AR1,P#0.0]    [COLOR=red]// das würde die cpu in stop bringen, da es das ew30.4 nicht gibt.[/COLOR]
[COLOR=red]           // nur bei bitoperationen darf die bitadresse <>0 sein.[/COLOR]
-----------------------------------

Um indirekt auf ein Datenwort zugreifen zu können, ist es zwingend erforderlich den Datenbaustein vorher zu öffnen.
Code:
[COLOR=red]L db10.dbw [AR1,P#0.0]   // dies funktioniert nicht[/COLOR]
 
  AUF   DB    10
  L     DBW [AR1,P#0.0]    // so ist es richtig
-----------------------------------

Anwendungsbeispiel mit einer Schleife
Code:
FILO für Datenbyte (FirstInLastOut)
FiLo         __\ byte1 \________________
            |  /       /                |
            |    byte2 \_________    /__|3.
            |          /         |   \
            |    byte3 \__    /__|2.
            |          /  |   \
            |    byte4 /__|1.
            |          \
            |
            |
quelle    4.|__/ byte
               \
Ablauf: 
1. zielbyte  3 wird nach zielbyte 4 kopiert. das alte byte 4 geht verloren.
2. zielbyte  2 wird nach zielbyte 3 kopiert
3. zielbyte  1 wird nach zielbyte 2 kopiert
4. quellbyte 1 wird nach zielbyte 1 kopiert
Code:
      AUF   #Datenbaustein      //Typ: Block_DB
      L     #Datenende          //Typ: INT
      L     1
      -I    
      T     #index              //Typ: DINT
anf:  NOP   0                   //Schleifenanfang
      L     #index
      SLD   3                   //pointer erzeugen
      LAR1                      //in das Adressregister laden
      L     DBB [AR1,P#0.0]
      T     DBB [AR1,P#1.0]
      L     #index
      L     1
      -I                        //Index um 1 verringern
      T     #index
      L     1
      +I    
      L     #Datenanfang        //Typ: INT
      <=I                       //prüfen ob fertig
      SPB   ende                //wenn ja ende
      SPA   anf                 //sonst schleife wiederholen
ende: NOP   0
      L     #Eintrag            //Typ: BYTE
      T     DBB [AR1,P#0.0]     //neues byte eintragen
einige Bauteine für weitere variablen / blöcke findet ihr auf der homepage von volker.
-----------------------------------

Indirekt auf einen Bereich im Temp-Bereich zugreifen
nummer: typ int im temp-bereich an adresse 0
maschine: Array [0..5] of int im temp-bereich ab adresse 2
Code:
// var zum test vorbelegen
      L     2
      T     #nummer
//----------------
      L     P##maschine                 //pointer auf array laden
      LAR1                              //ins adressregister speichern
      L     #nummer
      L     2
      *I                                //mit 2 multiplizieren da typ:int
      SLD   3                           //pointer bauen
      +AR1                              //zum adressregister hinzuaddieren
      L     W [AR1,P#0.0]               //läd den wert von #maschine[2]
-----------------------------------

Es kann auch Adressregister2 (AR2) verwendet werden.
Aber Vorsicht:
Das DI-Register und das Adressregister AR2 werden systemseitig für den FB- und Multiinstanz-CALL verwendet. Bei FC's braucht ihr euch nicht darum zu kümmern.

Weiterführende Themen: Any-Zeiger für Datentypen
.
 

Anhänge

  • pointerformat.gif
    pointerformat.gif
    18,4 KB · Aufrufe: 4.888
Zuletzt bearbeitet von einem Moderator:
Speicherindirekte Adressierung vs. Registerindirekte Adressierung

Wann man keine Wahl hat:
  • Speicherindirekte Adressierung geht nicht bereichsübergreifend (L W [#Pointer]), sondern nur bereichsintern (L DBW [#Pointer]) - die Bereichskennung muß immer in der Operation angegeben werden, eine eventuell im Pointer enthaltene Bereichskennung wird immer ignoriert.
  • Speicherindirekte Adressierung kann man zur indirekten Adressierung von Timern, Zählern, DB, FB und FC benutzen. Die registerindirekte Adressierung kann das nicht.

Wenn man die Wahl hat, dann ist speicherindirekte Adressierung besser lesbar und nicht so fehleranfällig, weil der Zugriffs-Speicherbereich und der Variablenname des benutzten Pointers in der Operation steht.

Speicherindirekte Adressierung eignet sich besonders
  • für Zugriff auf Arrays von einfachen Datentypen oder unstrukturierte Speicherbereiche. (Es kann kein zusätzlicher Versatz angegeben werden, wodurch für jeden Zugriff die genaue Adresse im Pointer stehen muß.)
  • wenn man mit mehreren Pointern arbeitet (z.B. Kopieraktionen), dann spart man sich das dauernde Umladen des AR1-Registers und muß AR2 nicht anfassen, was wiederum vorteilhaft bei der Verwendung in FB ist.
Registerindirekte Adressierung eignet sich besonders
  • für Zugriff auf Strukturen. Da kann man die Anfangsadresse in einem Adressregister halten und per zusätzlichem Versatz in der Operation auf verschiedene Strukturmember zugreifen, ohne das Adressregister verändern zu müssen.
  • zur Verarbeitung von ANY-Pointern, weil auch bereichsübergreifende Operationen möglich sind, wo die Bereichskennung nicht in der Operation sondern im Pointer enthalten ist.

Details siehe z.B.: Hilfe zu AWL > Index > Indirekte Adressierung

Harald
 
Zurück
Oben