Pointer FB (STAT, TEMP)

saarlaender

Level-1
Beiträge
94
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi Leute,

ich tu mich leider noch immer schwer mit gewissen Pointer-Geschichten, insbesondere mit dem konkreten Umsetzen von dem was ich im Forum hier so finde...


Ich habe einen FB (wird als Multiinstanz aufgerufen) mit einer UDT-Struktur jeweils in IN, STAT und OUT.

Hintergrund: Ich gebe die Struktur an verschiedene Aufrufe innerhalb des FBs weiter, muss aber davor noch die Daten verändern. Dazu kopiere ich die UDT-Struktur von IN nach STAT, ändere die Daten dort und gebe diese dann an die weiteren Aufrufe weiter. Am Ende kopiere ich dann von STAT nach OUT, da die Aufrufe diese Daten ebenfalls verändern.


Das Problem: Ich muss einen TEIL eines Array of Char ändern - das würde bei einem DB als Ziel mit BLKMOV gehen (P#DB1.DBX0.0 BYTE 10 oder auch P#DB1.DBX10.0 BYTE 22). BLKMOV krigt das aber nicht bei STAT bzw TEMP hin.

Die TEMP-Pointer sind für mich eigentlich kaum mehr ein Hexenwerk, aber die STAT-GEschichte (AR retten und widerherstellen, AR2 addieren usw) schon...



Ich möchte also über einen Pointer einen gewissen Bereich in STAT (ein Teil eines Array of Char, innerhalb eines UDT) ansprechen und zur Sicherheit auch wie hier öfters nachzulesen war das Adressregister retten und zurück spielen (?!).



Bei TEMP würde das z.B. so bei mir aussehen:

Code:
      LAR1  P##ANY_Pointer

      L     B#16#10                     //Syntax-ID
      T     LB [AR1,P#0.0]

      L     B#16#2                      //Typ: Byte
      T     LB [AR1,P#1.0]

      L     25                          //Länge zu lesender Bereich
      T     LW [AR1,P#2.0]

      L     0                           //DB-Nummer, hier 0 da vorherige Lokaldaten
      T     LW [AR1,P#4.0]

      L     50                          //Startadresse des zu lesenden Bereiches
      SLD   3
      T     LD [AR1,P#6.0]

      L     B#16#87                     //vorherige Lokaldaten
      T     LB [AR1,P#6.0]

Hier würde der TEMP-Bereich ab 50.0 bis 75.0 angesprochen werden. Damit könnte ich dann entweder via BLKMOV von dort Lesen oder eben hin schreiben.


Wie würde dies für den gleichen Bereich in STAT aussehen? Hier mal meine Schlussfolgerung, allerdings ohne die Sicherung und Widerherstellung vom Adressregister...

Code:
      LAR1  P##ANY_Pointer

[B][I]>> TAR 2 //wg. Multiinstanz
>> +AR1 //wg. Multiinstanz[/I][/B]

      L     B#16#10                     //Syntax-ID
      T     LB [AR1,P#0.0]

      L     B#16#2                      //Typ: Byte
      T     LB [AR1,P#1.0]

      L     25                          //Länge zu lesender Bereich
      T     LW [AR1,P#2.0]

      L     0                           //DB-Nummer, hier 0 da vorherige Lokaldaten
      T     LW [AR1,P#4.0]

      L     50                          //Startadresse des zu lesenden Bereiches
      SLD   3
      T     LD [AR1,P#6.0]

      L     B#16#87                     //vorherige Lokaldaten
      T     LB [AR1,P#6.0]

Stimmt das so, um den STAT-Bereich 50.0-75.0 anzusprechen?
Wie würde in diesem Fall die Rettung usw vom Adressregister aussehen?


Vielen Dank


EDIT: Ich kann den UDT statt in STAT evt. auch in TEMP legen, aber es geht ja hier in erster Linie ums Verständnis... :)
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Code:
L     0                           //DB-Nummer, hier 0 da vorherige Lokaldaten 
     T     LW [AR1,P#4.0]
ist auf jeden fall nicht richtig...

Code:
L DINO
T LW[AR1,P#4.0

Auch die Bereichskennung solltest du auf DB oder DI ändern... ob du DB oder DI nimmst sollte aber egal sein!
 
Code:
       TAR1  dTempAR1                   //Adressregister 1 retten
       TAR2  dTempAR2                   //Adressregister 2 retten
       ..
       ..
       TAR2                             //Adressregister 2 Laden
       UD DW#16#FFFFFF                  //Bereichskennung ausmaskieren
       LAR1 P##ANY_Pointer              //Zeiger ins Adressregister 1 Laden
       +AR1                             //beide Register addieren

      ..
      ..
      LAR1  dTempAR1                   //Adressregister 1 wieder herstellen
      LAR2  dTempAR2                   //Adressregister 2 wieder herstellen
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@RN:
da die Verwendung des Befehls +AR1 nicht ganz unproblematisch ist (man weiß ja nie, wie groß die vorherige Instanz so ist) würde ich es lieber so vorschlagen wollen :
Code:
   TAR2                             //Adressregister 2 Laden
       UD DW#16#FFFFFF                  //Bereichskennung ausmaskieren
       LAR1 P##ANY_Pointer              //Zeiger ins Adressregister 1 Laden
    [COLOR=#B22222][B]   +D                 [/B][/COLOR]            //beide Register addieren
 
Dann musst du aber den Pointer in den Akku laden das ganze wieder in das AR1 schreiben. Und dann besteht kein unterschied mehr in der Funktion...
Code:
 TAR2                             //Adressregister 2 Laden
       UD DW#16#FFFFFF                  //Bereichskennung ausmaskieren
[COLOR=#b22222]      [B] L [/B]   [/COLOR] P##ANY_Pointer              //Zeiger ins Adressregister 1 Laden
    +D             //beide Register addieren
   [B][COLOR=#b22222] LAR1
[/COLOR][/B]

 
Zuviel Werbung?
-> Hier kostenlos registrieren
Dann vielleicht sogar besser so

Code:
       TAR1  dTempAR1                   //Adressregister 1 retten
       TAR2  dTempAR2                   //Adressregister 2 retten
       ..
       ..
       TAR2                             //Adressregister 2 Laden
       UD DW#16#FFFFFF                  //Bereichskennung ausmaskieren
       L P#ANY_Pointer                  //Zeiger Pointer Laden
       +D                               //beide Zeiger addieren
       LAR1                             //Zeiger in das Adressregister 1 Laden 
       ..
       ..
       LAR1  dTempAR1                   //Adressregister 1 wieder herstellen
       LAR2  dTempAR2                   //Adressregister 2 wieder herstellen
 
@RN:
da die Verwendung des Befehls +AR1 nicht ganz unproblematisch ist (man weiß ja nie, wie groß die vorherige Instanz so ist) würde ich es lieber so vorschlagen wollen

Grundsätzlich hat Lupo recht, das Addieren mit Adressregistern, ist nicht ganz umproblematisch.
Dadurch das bei der Addition der Adressregisters durch den Befehl '+AR1' oder 'AR2' der Operandenbereich erhalten wird
ist es keine wirkliche Doppelwort Addition, sondern eine Wort Addition, die Vorzeichen richtig auf 24Bit erweitert wird.

Addieren zum Adressregister
Zu den Adressregister können Sie einen Wert addieren, um z.B. Programmschleifen die Adresse eines Operanden
bei jedem Schleifendurchlauf zu erhöhen. Den Wert geben Sie entweder als Konstante (als bereichsinternen Zeiger)
bei der Anweisung an oder er steht im rechten Wort des Akkumulators 1. Die Art der des im Adressregister stehenden
Zeigers (bereichsinternen oder bereichsübergreifend) und der Operandenbereich bleiben erhalten.

Addieren mit Zeiger
Die Anweisungen +AR1 P#y.x und +AR2 P#y.x addieren einen Zeiger zum angegebenen Adressregister. Beachten Sie,
das bei diesem Anweisungen der Bereichszeiger eine maximale Größe von P#4095.7 hat. Steht ein Wert größer als
P#4095.7 im Akkumulator, wird die Zahl als Festpunktzahl im Zweierkomplement interpretiert und subtrahiert.

Addieren mit Wert im Akkumulator
Die Anweisungen +AR1 und +AR2 interpretieren das im Akkumulator 1 stehenden Wert als Zahl im INT-Format, erweitern
ihn vorzeichenrichtig auf 24 Bit und addieren ihn zum Inhalt des Adressregisters. Auf diese Weise kann auch ein Zeiger
verkleinert werden. Ein Über- oder Unterschreiten des maximalen Bereiches der Byteadresse (0 bis 65535) hat keinen
weiteren Auswirkungen: Die obersten Bits werden "abgeschnitten":

Code:
[COLOR=#ffffe0].
.[/COLOR]
   Byte n             Byte n+1         Byte n+2          Byte n+3
   - - - - - - - - | - - - - - - - - | V y y y y y y y | y y y y y x x x


x = Bitadresse      V V V V V V V | V y y y y y y y | y y y y y x x x
y = Byteadresse     <----------------|
z = Bereich           [SIZE=1]Vorzeichen wird aufgefüllt
[/SIZE]V = Vorzeichen

Beachten Sie, dass die Bitadresse in den Bits 0 bis 2 steht. Möchten Sie die Byteadresse bereits im Akkumulator 1 erhöhen,
müssen Sie ab Bit 3 Addieren (den Wert um 3 stellen nach links schieben).
 
Zuletzt bearbeitet:
@RN: sogesehen richtig, aber du hast ja bereits den Inhalt von AR2 maskiert. Und wenn ich nix übersehen hab war es dann von Anfang an ja richtig.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@RN: sogesehen richtig, aber du hast ja bereits den Inhalt von AR2 maskiert. Und wenn ich nix übersehen hab war es dann von Anfang an ja richtig.

Um was es mir ging war das Vorsicht bei der Größe der Adresse des Zeigers zu walten ist.
Wenn du einen FB als Multiinstanz schreibst und dieser in einer großen Instanz weit hinten
steht, kann es leicht passieren das der Pointer >4095.7 ist. Bei der Verwendung von +AR1
oder +AR2 zeigst du schnell ins bodenlose. Das Ausmaskieren der Bereichskennung beim
AR2 ist selbsverständlich, sonst wird diese zur Bereichskennung vom AR1 mit Addiert, wenn
man nicht aufpasst und +D nutzt.
 
Code:
       TAR1  dTempAR1                   //Adressregister 1 retten
       TAR2  dTempAR2                   //Adressregister 2 retten
       ..
       ..
       TAR2                             //Adressregister 2 Laden
       UD DW#16#FFFFFF                  //Bereichskennung ausmaskieren
       LAR1 P##ANY_Pointer              //Zeiger ins Adressregister 1 Laden
       +AR1                             //beide Register addieren

      ..
      ..
      LAR1  dTempAR1                   //Adressregister 1 wieder herstellen
      LAR2  dTempAR2                   //Adressregister 2 wieder herstellen

Wenn ich die ARs wie oben addiere, kann ich dann Gefahrlos weiter im Baustein LAR1 P##dies und LAR2 P##das benutzen? Oder muss ich dieses dann jedesmal vor dem Pointern machen?
 
Nach dem Addieren kannst du damit ganz normal auf Variablen zugreifen, möchtest du
aber wie in deiner Fragestellung einen neuen Pointer zuweisen LAR1 P##dies, solltest du
schon wissen wo dieser herkommt und entsprechend behandeln. Also unter Umständen
das AR2 hinzu addieren.

Möchtest du den Pointer nur erhöhen, um auf eine weitere Variablen im Datenfeld zu zeigen,
so kannst ihn einfach erhöhen.

Code:
+AR1 P#0.1        //lässt das Adressregister 1 auf das nächste Bit zeigen
+AR2 P#2.0        //lässt das Adressregister 2 auf das nächste Wort zeigen
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Nach dem Addieren kannst du damit ganz normal auf Variablen zugreifen, möchtest du
aber wie in deiner Fragestellung einen neuen Pointer zuweisen LAR1 P##dies, solltest du
schon wissen wo dieser herkommt und entsprechend behandeln. Also unter Umständen
das AR2 hinzu addieren.
Danke erstmal,


Das erhöhen ist schon klar. Es ging mir jetzt eben nur darum, wenn ich zB in NW 1 folgendes habe

Code:
L     WORD_In
T     WORD_Temp
     TAR2                              //Adressregister 2 Laden
      UD    DW#16#FFFFFF                //Bereichskennung ausmaskieren
      LAR1  P##WORD_2_Temp                //Pointer auf DB_Zone_1
      +AR1                              //beide Register addieren

      L     8                           
M00:  T     #Schleife                   


      L     #WORD_Temp               
      T     LW [AR1,P#0.0]              

      L     #WORD_Temp               
      +     1
      T     #WORD_Temp

      +AR1     P#2.0                       
        

      L     #Schleife                   
      LOOP  M00
...
...
...

und im nächsten NW

Code:
      LAR1  P##dies            //Pointer auf WORD In
      LAR2  P##das      //Pointer auf  BYTE OUT

      L     8                           
M01:  T     #Schleife_2            


      U      [AR1,P#0.4]                
      S      [AR2,P#0.0]                

      +AR1    P#2.0                             
      +AR2    P#0.1                       
        

      L     #Schleife_2            // Schleife
      LOOP  M01
...
...
...

und im 3. NW dann wieder nur LAR1 P##irgendwas usw.

Wann muss ich dann das AR1 und AR2 addieren?
 
Zuletzt bearbeitet:
eigentlich musst du das AR2 Addieren, wenn deine Daten (auf die du zeigen möchtest)
im Stat-Bereich deines FBs liegt und dieser FB eine Multiintanz eines anderen FBs ist.

hier ist jetzt mal so ein Datenbaustein wo zweimal ein FB als Multiinstanz enthalten ist
mit den Feldern Multi_1 und Multi_2.
DATA_BLOCK DB 101
TITLE =
VERSION : 0.0

FB 101
BEGIN
irgendwas_1 := W#16#0;
Multi_1.Feld[0] := 0;
Multi_1.Feld[1] := 0;
Multi_1.Feld[2] := 0;
Multi_1.Feld[3] := 0;
Multi_1.Feld[4] := 0;
Multi_1.Feld[5] := 0;
Multi_1.Feld[6] := 0;
Multi_1.Feld[7] := 0;
Multi_1.Feld[8] := 0;
Multi_1.Feld[9] := 0;
Multi_1.Feld[10] := 0;
Multi_2.Feld[0] := 0;
Multi_2.Feld[1] := 0;
Multi_2.Feld[2] := 0;
Multi_2.Feld[3] := 0;
Multi_2.Feld[4] := 0;
Multi_2.Feld[5] := 0;
Multi_2.Feld[6] := 0;
Multi_2.Feld[7] := 0;
Multi_2.Feld[8] := 0;
Multi_2.Feld[9] := 0;
Multi_2.Feld[10] := 0;
END_DATA_BLOCK

Möchtest du jetzt in deinen erstellten Multiinztanzbaustein zugreifen muß du wissen
wo er sich im Instanzdatenbaustein befindet, die Daten befinden sich ja nicht unbedingt
bei 0.0 sondern etwas tiefer. Das AR2 teilt im Prinzip den Multiinstanzbaustein mit wo
dieser im Instanzdatenbaustein seine Daten findet.
 
eigentlich musst du das AR2 Addieren, wenn deine Daten (auf die du zeigen möchtest)
im Stat-Bereich deines FBs liegt und dieser FB eine Multiintanz eines anderen FBs ist.

Aha, da ich aber auf IN und OUT Vars zeige, brauch ich es nicht zu machen.
Also nur wenn man auf STAT Vars zeigt, die dann noch in andere FB als Multiinstanzen angelegt sind.
Wieder was gelernt, danke!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
neh neh, das gilt für alle Variablen die in der Instanz abgelegt werden, das wären
IN; OUT; INOUT und STAT. Die Lokalvariablen nicht.
Das Beispiel war nur so gedacht, das mann zb ein Datenfeld mit Werten füllen möchte.

Lese bitte auch noch mal Beitrag #10...
 
Zuletzt bearbeitet:
Ok,

und wie mache ich das denn jetzt?

Jedesmal
Code:
TAR2                              //Adressregister 2 Laden
UD    DW#16#FFFFFF                //Bereichskennung ausmaskieren
LAR1  P##dies                //Pointer       
+AR1

wie mache ich es wenn ich LAR1 p##dies und LAR2 P##das benutze?

Code:
 TAR2                              //Adressregister 2 Laden       
UD    DW#16#FFFFFF                //Bereichskennung ausmaskieren
LAR1  P##dies                //Pointer       
+AR1 
LAR2 P##das
 
Code:
       TAR1  dTempAR1                   //Adressregister 1 retten
       TAR2  dTempAR2                   //Adressregister 2 retten
       ..
       ..
       TAR2                             //Adressregister 2 Laden
       UD DW#16#FFFFFF                  //Bereichskennung ausmaskieren
       L P#das                          //Zeiger Pointer Laden
       +D                               //beide Zeiger addieren
       LAR1                             //Zeiger in das Adressregister 1 Laden 

       TAR2                             //Adressregister 2 Laden
       UD DW#16#FFFFFF                  //Bereichskennung ausmaskieren
       L P#dies                         //Zeiger Pointer Laden
       +D                               //beide Zeiger addieren
       LAR2                             //Zeiger in das Adressregister 2 Laden
       ..
       ..
       LAR1  dTempAR1                   //Adressregister 1 wieder herstellen
       LAR2  dTempAR2                   //Adressregister 2 wieder herstellen

Oder vielleicht auch so

Code:
       TAR1  dTempAR1                   //Adressregister 1 retten
       TAR2  dTempAR2                   //Adressregister 2 retten
       ..
       ..
       TAR2                             //Adressregister 2 Laden
       UD DW#16#FFFFFF                  //Bereichskennung 
       T dTempOffsetAR2

       L P#das                          //Zeiger Pointer Laden
       +D                               //beide Zeiger addieren
       LAR1                             //Zeiger in das Adressregister 1 Laden 

       L dTempOffsetAR2                 //Offset Adressregister 2 Laden
       L P#dies                         //Zeiger Pointer Laden
       +D                               //beide Zeiger addieren
       LAR2                             //Zeiger in das Adressregister 2 Laden
       ..
       ..
       LAR1  dTempAR1                   //Adressregister 1 wieder herstellen
       LAR2  dTempAR2                   //Adressregister 2 wieder herstellen
 
Zurück
Oben