Step 7 Mit Pointer auf ARRAY im Instzanz-DB zugeifen

Paul

Level-2
Beiträge
929
Reaktionspunkte
239
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen

Ich hab mir in S7 Classic einen FB geschrieben der folgendes macht:

Einen Neuwert in ein FIFO schreiben und
den Durchschnitt aus allen FIFO Einträgen errechnen.
Es sind noch ein paar Gimicks mit dabei wie Länge des FIFO von außen beschalten, Initialisieren etc.
Funktioniert soweit super.

Nun meine Frage:
Das FIFO-Werte-ARRAY liegt im Instanz DB.
Der Knackpunkt ist dass ich es nicht hinbekomme das Array ohne Umweg anzusprechen.
Ich habe mir jetzt so geholfen;
INPUT Beinchen wird mit der Nr. des IDB (Int) beschrieben
der DB wird dann mit <AUF DB [#T_NR_IDB] >aufgerufen und bearbeitet

Code:
        .................
        .................
       .................

INIT: CLR                                     //######## Anfang LOOP 1 ##########
      L     #Schleifenzaehler_1         //Anzahl der bereits absolvierten Durchläufe
      L     4                                    //Pointer um 4 erhöhen wegen Doppelwort
      *I    
      L     4
      -I    
      SLW   3                                   //Pointer bilden
      LAR1                                      //und ins Adressregister schreiben
      L     #Neuwert
      [B]AUF   DB [#T_NR_IDB]        //Eigenen Instanz-DB aufrufen[/B]
      T     DBD [AR1,P#32.0]            //Anfangsadresse des Werte-Array im IDB
      ..............
      ..............
Wie gesagt, funktioniert super und ich kann damit auch gut leben.
Aber die gängige Vorgehensweise ist das doch eher nicht, oder?
Wie macht ihr das?



Ach ja, noch was:
Den Input Wert muss ich erst in den TEMP Bereich umrangieren
Code:
      L    #NR_IDB                       //INPUT
      T     #T_NR_IDB                  //TEMP
       .................
       .................
       AUF   DB [#T_NR_IDB]       //TEMP
sonst wird er nach dem AUF nicht gefressen :confused::confused:
 
Funktioniert soweit super.
Naja, Du hast noch nicht richtig getestet ...

Das FIFO-Werte-ARRAY liegt im Instanz DB.
Der Knackpunkt ist dass ich es nicht hinbekomme das Array ohne Umweg anzusprechen.
Ich habe mir jetzt so geholfen;
INPUT Beinchen wird mit der Nr. des IDB (Int) beschrieben
der DB wird dann mit <AUF DB [#T_NR_IDB] >aufgerufen und bearbeitet
Die IDB-Nummer muß nicht extra als Parameter übergeben werden, der IDB ist am Anfang des FB-Code normalerweise als "DI" bereits geöffnet.
Mit "L DINO" kann ein FB die Nummer des zuletzt als DI geöffneten DB lesen, was normalerweise die Nummer des eigenen IDB ist. Siehe AWL-Hilfe "DB-Aufruf"

Besser: Wenn der Programmcode nicht "T DBD [AR1,..]" sondern "T DID [AR1,..]" verwendet, dann braucht der Code die IDB-Nummer nicht wissen und den IDB nicht öffnen, weil der IDB ist ja (normalerweise) bereits geöffnet.

ABER: Wenn Du den FB als Multiinstanz benutzt, dann adressiert "T DID/DBD [AR1,..]" nur dann korrekt das von Dir gewollte Array in der eigenen Instanz, wenn zu der Offset-Adresse im IDB noch der Multiinstanz-Offset aus AR2 addiert wird - was Dein Programmstück aber offensichtlich nicht macht.

In "Multiinstanzfähig"-FB darf der Wert in AR2 nicht verändert werden bzw. muß vor einem Zugriff auf Instanzvariablen (im IDB) wiederhergestellt werden.

Wie gesagt, funktioniert super und ich kann damit auch gut leben.
Aber die gängige Vorgehensweise ist das doch eher nicht, oder?
Richtig. So macht man das eher nicht.

Sondern eher so:
Code:
        .................
        .................
       .................

INIT: CLR                       //######## Anfang LOOP 1 ##########
      L     #Schleifenzaehler_1 //Anzahl der bereits absolvierten Durchläufe
      +     -1
      SLD   5                   //SLD 3 + 2: index-->P# + Array-Elementgröße 4 Byte
      TAR2                      //Multiinstanzoffset aus AR2
      UD    DW#16#FFFFFF        //Bereichskennung (DB) entfernen
      +D                        //zum der Array-Offset addieren
      LAR1                      //AR1 und DI-Register zeigen nun in diese Instanz

      L     #Neuwert
      T     DID [AR1,P#32.0]    //(P#32.0: Anfangsadresse des Array in der Instanz)
      ..............
      ..............

Ach ja, noch was:
Den Input Wert muss ich erst in den TEMP Bereich umrangieren
Code:
      L    #NR_IDB                       //INPUT
      T     #T_NR_IDB                  //TEMP
       .................
       .................
       AUF   DB [#T_NR_IDB]       //TEMP
sonst wird er nach dem AUF nicht gefressen :confused::confused:
Das ist richtig so. Siehe AWL-Hilfe: Index > Indirekte Adressierung > Speicherindirekte Adressierung, der Pointer kann nicht in einer Multiinstanz liegen. Sehr wahrscheinlich hast Du Deinen FB als "Multiinstanzfähig" erstellt.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
In Classic ist es noch nicht möglich, mit AWL auf Arrayelemente vollsymbolisch zuzugreifen, in TIA geht mittlerweile auch das, mindestens bei 1500er CPUs.
Ich würde deshalb sowas immer in SCL programmieren, denn da kann ich direkt und vollsymbolisch auf die Arrayelemente zugreifen und habe auch im Fall von Multiinstanz immer die richtige Instanz angesprochen. Und falls sich mal an dem Array was ändert, braucht bloß alles neu übersetzt zu werden. Geht schneller und sicherer als mit Pointerberechnung in AWL, denn die ganze Pointerberechnung usw. macht der Compiler selbst im Hintergrund.
Allerdings wird der Code etwas größer als mit selbstgeschriebenen/selbstoptimierten AWL.
 
Hallo Harald
Vielen Dank erst mal dafür dass Du Dir die Mühe gemacht hast das so super ausführlich aufzudröseln.

Du schreibst
Naja, Du hast noch nicht richtig getestet ...
Das klingt für mich so, als wenn Du da noch einen richtig dicken Bock entdeckt hättest?
Wenn Du mit "richtig testen" die Multiinstanzfähigkeit meinst, dann hast Du natürlich recht.
Als Einzelinstanz macht der Baustein aber schon was er soll, wenn auch mit einer "exotischen" Herangehensweise.
Multiinstanz, so hoch hab ich mir mein Ziel gar nicht gesteckt, aber ist klar, damit kann das nicht funktionieren.

Werde deine Lösung gleich mal ausprobieren und mich ggf, noch mal melden.
Vielen Dank nochmals.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Du schreibst
Naja, Du hast noch nicht richtig getestet ...
Das klingt für mich so, als wenn Du da noch einen richtig dicken Bock entdeckt hättest?
Wenn Du mit "richtig testen" die Multiinstanzfähigkeit meinst, dann hast Du natürlich recht.
Nein, ich meinte nur die Multiinstanzfähigkeit: den FB als "Multiinstanzfähig" markieren, aber nicht multiinstanzfähig programmieren.

Harald
 
Noch eine kleine Ergänzung zu PN/DP`s Antwort wenn man etwas Symbolischer auf ein Array im Stat bereich zugreifen möchte.

Code:
      L     1
      T     #array_1[2]                 //array_1[2] = 1

      L     2
      T     #index_array_1


//create pointer to array_1
      L     P##array_1
      UD    DW#16#FFFFFF                //delete array identification (DI) from pointer in Akku1 - array identification is in the first 8 bit
      SRW   3                           //SLD 3 because last 3 bits of the pointer contain the bit-adress

      TAR2                              //load AR2 in Akku1 to enable correct access also in multiinstnces
      UD    DW#16#FFFFFF                //delete array identification (DB) from pointer in Akku1 - array identification is in the first 8 bit
      SRW   3                           //SLD 3 because last 3 bits of the pointer contain the bit-adress
      +I   
      SLW   3                           //reset to pointer format to have in the last 3 bits the bit-adress
      T     #pointer_array_1


//access to element of array_1
      L     #index_array_1
      L     2                           //length of the Datatype in array_1 in Byte (e.g. Integer -> 2 Byte) - for access to bits
      *I                                //calculate offset of the accessed element to pointer_array_1

      L     #pointer_array_1
      SRW   3
      +I                                //add offset to pointer array_1 /when accessing bool data the offset must calc differend (Bit adress must be changed)
      SLW   3
      LAR1                              //load pointer to AR1



      L     DIW [AR1,P#0.0]             //load element array_1[index_array_1]

Bezogen auf die Frage kann man dann natürlich noch statt "index_array_1" "Schleifenzaehler_1" verwenden.

Befindet sich das Array in einem komplexen Datentyp wie z.B. Struct, dann ist ein Pointerzugriff über P##struct_name.array_1 in Step7 leider nicht möglich.
Man kann nur mit P##struct_name den Pointer auf den begin von struct_name dynamisch ermittelt und anschließend muss das Offset innerhalb der Struktur absolut angegeben werden.


Code:
//create pointer to struct_name.array_1
      L     P##struct_name              //not possible to direct P##struct_name.array_1 - > P# cant access elemnts in Structs
      UD    DW#16#FFFFFF                //delete array identification (DI) from pointer in Akku1 - array identification is in the first 8 bit
      SRW   3                           //SLD 3 because last 3 bits of the pointer contain the bit-adress

      L     6                           //offset of array_1 in struct_name
      +I   

      TAR2                              //load AR2 in Akku1 to enable correct access also in multiinstances
      UD    DW#16#FFFFFF                //delete array identification (DB) from pointer in Akku1 - array identification is in the first 8 bit
      SRW   3                           //SLD 3 because last 3 bits of the pointer contain the bit-adress
      +I   
      SLW   3                           //reset to pointer format to have in the last 3 bits the bit-adress
      T     #pointer_array_1


....
 
Zurück
Oben