SCL indirekte Adressierung von Strukturen

A

Anonymous

Guest
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo

Ich habe einen DB mit mehreren Datensätze. Diese haben alle die gleiche Struktur. Diese will ich in einer FOR-Schlaufe bearbeiten. Wie muss ich die Strukturen indirekte Adressieren damit ich auf die Daten zugreifen kann.

Ich habe ein Beispiel geschrieben um die indirekte Adressierung zu testen. Leider funktioniert es nicht. Was habe ich falsch gemacht?

Code:
TYPE ParameterDefinition    
    STRUCT
        DBNumber    : WORD;     // DB-Nummer der Daten
        WordNumber  : INT;      // Startword erster Datentrecord
        Number      : INT;      // Anzahl Datenrecord
        Length      : INT;      // Datenlänge
        Spare       : INT;      // Reserve, da es ein Compelierfehler gibt, wenn die Struktur nur 4 Word lange ist
    END_STRUCT
END_TYPE

TYPE DataDefinition
    STRUCT
        TimeSet     : INT;      // Vorgabezeit
        TimeActual  : INT;      // Aktuelle zeit
        Length      : INT;      // Längemessung
        Spare1      : INT;      // Reserve, da es ein Compelierfehler gibt, wenn die Struktur nur 4 Word lange ist
        Spare2      : INT;
    END_STRUCT
END_TYPE

DATA_BLOCK ParameterDB
  STRUCT
    Parameter : ParameterDefinition;      // Parameter
  END_STRUCT;
BEGIN
END_DATA_BLOCK

DATA_BLOCK DataDB
  STRUCT
    Data_1 : DataDefinition;    // Daten Element 1
    Data_2 : DataDefinition;    // Daten Element 2
    Data_3 : DataDefinition;    // Daten Element 3
    Data_4 : DataDefinition;    // Daten Element 4
    Data_5 : DataDefinition;    // Daten Element 5 
  END_STRUCT;

BEGIN
END_DATA_BLOCK

FUNCTION "TestDaten" : VOID 
TITLE = 'Daten von 5 Elementen bearbeiten'
VERSION : '1.0'
AUTHOR  : KLE
NAME    : Test1
FAMILY  : Exor
//KNOW_HOW_PROTECT

VAR_TEMP 
    Daten               : DataDefinition;
    pDaten AT Daten     : ANY;                          // Pointer Daten
    index               : INT;                          // Schleifenzähler
END_VAR 
BEGIN
    pDaten   := WORD_TO_BLOCK_DB(ParameterDB.Parameter.DBNumber).DW[ParameterDB.Parameter.WordNumber];   // Pointerzuweisung erster Datensatz

    FOR index:=1 TO ParameterDB.Parameter.Number DO     // In der Schlaufe werden alle Datensätzte bearbeitet.
        Daten.TimeSet    := 345        ;                // Hier habe ich einfach einige Zuweisungen gemacht, dass ich testen kann.
        Daten.TimeActual := Daten.TimeActual + 1;       // Leider funktionieren die Pointer nicht.
        IF Daten.TimeSet > Daten.TimeActual THEN
            Daten.Length := 123;
        END_IF;
        pDaten := WORD_TO_BLOCK_DB(ParameterDB.Parameter.DBNumber).DW[ParameterDB.Parameter.WordNumber + (ParameterDB.Parameter.Length * index)];    // Pointerzuweisung nächster Datensatz
    END_FOR;
END_FUNCTION

ORGANIZATION_BLOCK OB1
TITLE = 'Main Program (Cycle)'
VERSION : '0.0'

VAR_TEMP
    OB1_EV_CLASS   : BYTE ;   //Ereignisklasse und Kennung
    OB1_SCAN_1     : BYTE ;   //B#16#01: Abschluss des Neustarts, B#16#02: Abschluß des Wiederanlaufes
    OB1_PRIORITY   : BYTE ;   //Prioritätsklasse: 1
    OB1_OB_NUMBR   : BYTE ;   //OB-Nummer, OB1
    OB1_RESERVED_1 : BYTE ;   //Reserviert
    OB1_RESERVED_2 : BYTE ;   //Reserviert
    OB1_PREV_CYCLE : INT ;    //Laufzeit des vorheriegen Zyklus
    OB1_MIN_CYCLE  : INT ;    //Minimale Zykluszeit seit dem letzten Anlauf
    OB1_MAX_CYCLE  : INT ;    //Maximale Zykluszeit seit dem letzten Anlauf
    OB1_DATE_TIME  : DATE_AND_TIME ;    //Datum und Uhrzeit, zu dem der OB angefordert wurde  
END_VAR

BEGIN
    TestDaten();                     // Aufruf FC
END_ORGANIZATION_BLOCK


MfG und zum Voraus vielen Dank

Leo Künzle
 
Speicher die Quelle mal bitte absolut und stell den Code nochmal ein, durch die Symbolik ist der Code nicht zu übersetzen (bei mit jedenfalls) und von Hand ist mir das ehrlich zu mühselig. (Oder fehlt ein Code-Stück?)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habe das Programm nun angepasst. Es wird der FC100 und der DB20 erstellt.

Code:
TYPE ParameterDefinition    
    STRUCT 
        DBNumber    : WORD;     // DB-Nummer der Daten 
        WordNumber  : INT;      // Startword erster Datentrecord 
        Number      : INT;      // Anzahl Datenrecord 
        Length      : INT;      // Datenlänge 
        Spare       : INT;      // Reserve 
    END_STRUCT 
END_TYPE 

TYPE DataDefinition 
    STRUCT 
        TimeSet     : INT;      // Vorgabezeit 
        TimeActual  : INT;      // Aktuelle zeit 
        Length      : INT;      // Längemessung 
        Spare1      : INT;      // Reserve 
        Spare2      : INT;      // Reserve
    END_STRUCT 
END_TYPE 

DATA_BLOCK DB20 
  STRUCT 
    Parameter : ParameterDefinition;      // Parameter 
  END_STRUCT; 
BEGIN 
END_DATA_BLOCK 

DATA_BLOCK DataDB 
  STRUCT 
    Data_1 : DataDefinition;    // Daten Element 1 
    Data_2 : DataDefinition;    // Daten Element 2 
    Data_3 : DataDefinition;    // Daten Element 3 
    Data_4 : DataDefinition;    // Daten Element 4 
    Data_5 : DataDefinition;    // Daten Element 5 
  END_STRUCT; 

BEGIN 
END_DATA_BLOCK 

FUNCTION FC100 : VOID 
TITLE = 'Daten von 5 Elementen bearbeiten' 
VERSION : '1.0' 
AUTHOR  : KLE 
NAME    : Test1 
FAMILY  : Exor 
//KNOW_HOW_PROTECT 

VAR_TEMP 
    Daten               : DataDefinition; 
    pDaten AT Daten     : ANY;                          // Pointer Daten 
    index               : INT;                          // Schleifenzähler 
END_VAR 
BEGIN 
    pDaten   := WORD_TO_BLOCK_DB(DB20.Parameter.DBNumber).DW[DB20.Parameter.WordNumber];   // Pointerzuweisung erster Datensatz 

    FOR index:=1 TO DB20.Parameter.Number DO     // In der Schlaufe werden alle Datensätzte bearbeitet. 
        Daten.TimeSet    := 345        ;                // Hier habe ich einfach einige Zuweisungen gemacht, dass ich testen kann. 
        Daten.TimeActual := Daten.TimeActual + 1;       // Leider funktionieren die Pointer nicht. 
        IF Daten.TimeSet > Daten.TimeActual THEN 
            Daten.Length := 123; 
        END_IF; 
        pDaten := WORD_TO_BLOCK_DB(DB20.Parameter.DBNumber).DW[DB20.Parameter.WordNumber + (DB20.Parameter.Length * index)];    // Pointerzuweisung nächster Datensatz 
    END_FOR; 
END_FUNCTION 

ORGANIZATION_BLOCK OB1 
TITLE = 'Main Program (Cycle)' 
VERSION : '0.0' 

VAR_TEMP 
    OB1_EV_CLASS   : BYTE ;   //Ereignisklasse und Kennung 
    OB1_SCAN_1     : BYTE ;   //B#16#01: Abschluss des Neustarts, B#16#02: Abschluß des Wiederanlaufes 
    OB1_PRIORITY   : BYTE ;   //Prioritätsklasse: 1 
    OB1_OB_NUMBR   : BYTE ;   //OB-Nummer, OB1 
    OB1_RESERVED_1 : BYTE ;   //Reserviert 
    OB1_RESERVED_2 : BYTE ;   //Reserviert 
    OB1_PREV_CYCLE : INT ;    //Laufzeit des vorheriegen Zyklus 
    OB1_MIN_CYCLE  : INT ;    //Minimale Zykluszeit seit dem letzten Anlauf 
    OB1_MAX_CYCLE  : INT ;    //Maximale Zykluszeit seit dem letzten Anlauf 
    OB1_DATE_TIME  : DATE_AND_TIME ;    //Datum und Uhrzeit, zu dem der OB angefordert wurde  
END_VAR 

BEGIN 
    FC100();                     // Aufruf FC 
END_ORGANIZATION_BLOCK

Gruss Leo
 
so können wir damit nichts anfangen. damit der korrekt übersetzt werden kann brauchen wir die zuordnungliste.
 
Ich habe einen DB vergessen zu ersetzten. Eine Zuordnungliste habe ich nicht erstellt.

Code:
TYPE ParameterDefinition    
    STRUCT 
        DBNumber    : WORD;     // DB-Nummer der Daten 
        WordNumber  : INT;      // Startword erster Datentrecord 
        Number      : INT;      // Anzahl Datenrecord 
        Length      : INT;      // Datenlänge 
        Spare       : INT;      // Reserve 
    END_STRUCT 
END_TYPE 

TYPE DataDefinition 
    STRUCT 
        TimeSet     : INT;      // Vorgabezeit 
        TimeActual  : INT;      // Aktuelle zeit 
        Length      : INT;      // Längemessung 
        Spare1      : INT;      // Reserve 
        Spare2      : INT;      // Reserve
    END_STRUCT 
END_TYPE 

DATA_BLOCK DB20 
  STRUCT 
    Parameter : ParameterDefinition;      // Parameter 
  END_STRUCT; 
BEGIN 
END_DATA_BLOCK 

DATA_BLOCK DB21 
  STRUCT 
    Data_1 : DataDefinition;    // Daten Element 1 
    Data_2 : DataDefinition;    // Daten Element 2 
    Data_3 : DataDefinition;    // Daten Element 3 
    Data_4 : DataDefinition;    // Daten Element 4 
    Data_5 : DataDefinition;    // Daten Element 5 
  END_STRUCT; 

BEGIN 
END_DATA_BLOCK 

FUNCTION FC100 : VOID 
TITLE = 'Daten von 5 Elementen bearbeiten' 
VERSION : '1.0' 
AUTHOR  : KLE 
NAME    : Test1 
FAMILY  : Exor 
//KNOW_HOW_PROTECT 

VAR_TEMP 
    Daten               : DataDefinition; 
    pDaten AT Daten     : ANY;                          // Pointer Daten 
    index               : INT;                          // Schleifenzähler 
END_VAR 
BEGIN 
    pDaten   := WORD_TO_BLOCK_DB(DB20.Parameter.DBNumber).DW[DB20.Parameter.WordNumber];   // Pointerzuweisung erster Datensatz 

    FOR index:=1 TO DB20.Parameter.Number DO     // In der Schlaufe werden alle Datensätzte bearbeitet. 
        Daten.TimeSet    := 345        ;                // Hier habe ich einfach einige Zuweisungen gemacht, dass ich testen kann. 
        Daten.TimeActual := Daten.TimeActual + 1;       // Leider funktionieren die Pointer nicht. 
        IF Daten.TimeSet > Daten.TimeActual THEN 
            Daten.Length := 123; 
        END_IF; 
        pDaten := WORD_TO_BLOCK_DB(DB20.Parameter.DBNumber).DW[DB20.Parameter.WordNumber + (DB20.Parameter.Length * index)];    // Pointerzuweisung nächster Datensatz 
    END_FOR; 
END_FUNCTION 

ORGANIZATION_BLOCK OB1 
TITLE = 'Main Program (Cycle)' 
VERSION : '0.0' 

VAR_TEMP 
    OB1_EV_CLASS   : BYTE ;   //Ereignisklasse und Kennung 
    OB1_SCAN_1     : BYTE ;   //B#16#01: Abschluss des Neustarts, B#16#02: Abschluß des Wiederanlaufes 
    OB1_PRIORITY   : BYTE ;   //Prioritätsklasse: 1 
    OB1_OB_NUMBR   : BYTE ;   //OB-Nummer, OB1 
    OB1_RESERVED_1 : BYTE ;   //Reserviert 
    OB1_RESERVED_2 : BYTE ;   //Reserviert 
    OB1_PREV_CYCLE : INT ;    //Laufzeit des vorheriegen Zyklus 
    OB1_MIN_CYCLE  : INT ;    //Minimale Zykluszeit seit dem letzten Anlauf 
    OB1_MAX_CYCLE  : INT ;    //Maximale Zykluszeit seit dem letzten Anlauf 
    OB1_DATE_TIME  : DATE_AND_TIME ;    //Datum und Uhrzeit, zu dem der OB angefordert wurde  
END_VAR 

BEGIN 
    FC100();                     // Aufruf FC 
END_ORGANIZATION_BLOCK

mfg Leo

E-Mail leo.kuenzle@exor.ch
 
Bei welchen Symbolen gibt es eine Fehlermeldung? Ich kann bei mir den Code in ein neues Projket ohne Problem einlesen.


mfg

Leo Künzle
 
So jetzt habe ich den Fehler bei mir gefunden. Das Programm sollte jetzt compilierbar sein.


Code:
TYPE UDT1    
    STRUCT 
        DBNumber    : WORD;     // DB-Nummer der Daten 
        WordNumber  : INT;      // Startword erster Datentrecord 
        Number      : INT;      // Anzahl Datenrecord 
        Length      : INT;      // Datenlänge 
        Spare       : INT;      // Reserve 
    END_STRUCT 
END_TYPE 

TYPE UDT2 
    STRUCT 
        TimeSet     : INT;      // Vorgabezeit 
        TimeActual  : INT;      // Aktuelle zeit 
        Length      : INT;      // Längemessung 
        Spare1      : INT;      // Reserve 
        Spare2      : INT;      // Reserve
    END_STRUCT 
END_TYPE 

DATA_BLOCK DB20 
  STRUCT 
    Parameter : UDT1;      // Parameter 
  END_STRUCT; 
BEGIN 
END_DATA_BLOCK 

DATA_BLOCK DB21 
  STRUCT 
    Data_1 : UDT2;    // Daten Element 1 
    Data_2 : UDT2;    // Daten Element 2 
    Data_3 : UDT2;    // Daten Element 3 
    Data_4 : UDT2;    // Daten Element 4 
    Data_5 : UDT2;    // Daten Element 5 
  END_STRUCT; 

BEGIN 
END_DATA_BLOCK 

FUNCTION FC100 : VOID 
TITLE = 'Daten von 5 Elementen bearbeiten' 
VERSION : '1.0' 
AUTHOR  : KLE 
NAME    : Test1 
FAMILY  : Exor 
//KNOW_HOW_PROTECT 

VAR_TEMP 
    Daten               : UDT2; 
    pDaten AT Daten     : ANY;                          // Pointer Daten 
    index               : INT;                          // Schleifenzähler 
END_VAR 
BEGIN 
    pDaten   := WORD_TO_BLOCK_DB(DB20.Parameter.DBNumber).DW[DB20.Parameter.WordNumber];   // Pointerzuweisung erster Datensatz 

    FOR index:=1 TO DB20.Parameter.Number DO     // In der Schlaufe werden alle Datensätzte bearbeitet. 
        Daten.TimeSet    := 345        ;                // Hier habe ich einfach einige Zuweisungen gemacht, dass ich testen kann. 
        Daten.TimeActual := Daten.TimeActual + 1;       // Leider funktionieren die Pointer nicht. 
        IF Daten.TimeSet > Daten.TimeActual THEN 
            Daten.Length := 123; 
        END_IF; 
        pDaten := WORD_TO_BLOCK_DB(DB20.Parameter.DBNumber).DW[DB20.Parameter.WordNumber + (DB20.Parameter.Length * index)];    // Pointerzuweisung nächster Datensatz 
    END_FOR; 
END_FUNCTION 

ORGANIZATION_BLOCK OB1 
TITLE = 'Main Program (Cycle)' 
VERSION : '0.0' 

VAR_TEMP 
    OB1_EV_CLASS   : BYTE ;   //Ereignisklasse und Kennung 
    OB1_SCAN_1     : BYTE ;   //B#16#01: Abschluss des Neustarts, B#16#02: Abschluß des Wiederanlaufes 
    OB1_PRIORITY   : BYTE ;   //Prioritätsklasse: 1 
    OB1_OB_NUMBR   : BYTE ;   //OB-Nummer, OB1 
    OB1_RESERVED_1 : BYTE ;   //Reserviert 
    OB1_RESERVED_2 : BYTE ;   //Reserviert 
    OB1_PREV_CYCLE : INT ;    //Laufzeit des vorheriegen Zyklus 
    OB1_MIN_CYCLE  : INT ;    //Minimale Zykluszeit seit dem letzten Anlauf 
    OB1_MAX_CYCLE  : INT ;    //Maximale Zykluszeit seit dem letzten Anlauf 
    OB1_DATE_TIME  : DATE_AND_TIME ;    //Datum und Uhrzeit, zu dem der OB angefordert wurde  
END_VAR 

BEGIN 
    FC100();                     // Aufruf FC 
END_ORGANIZATION_BLOCK

mfg

Leo
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich habe unter SCL noch nie einen ANY-Pointer verwendet, dachte das geht garnicht. Ich möchte das heute auch nicht mehr nachvollziehen.
Aber die "Fehler" beim Compilieren liegen wahrscheinlich an der Option unter Extras-Einstellungen "Bausteinnummer automatisch erzeugen".

SCL V5.3 SP1

Gruß, Onkel
 
den letzten code konnte ich übersetzen.

aber das schau ich mir in 1 woche mal genauer an , wenns denn noch aktuell ist.

----
schönen urlaub :wink:
 
Leider muß ich das jetzt nochmal machen, die letzte Version ging grad ebend verlustig :twisted:

Ich würde es nicht so kompliziert machen:

Code:
DATA_BLOCK DB21 
  STRUCT     
   Data : ARRAY  [0 .. 5 ] OF UDT 2;    
  END_STRUCT ;

Du definierst ein Array aus der UDT2.
Jetzt kannst du über einen Index zugreifen, wenn du nur einen Datenbaustein verwendest (DB21).

Code:
DB21.Data[Datenwort_Index].TimeSet := 567;

Hast du mehrere DB (DB21,22,...) geht es so leider nicht.
Du kannst dann nur audf Byte, Word oder Doppelwort zugreifen.

Code:
WORD_TO_BLOCK_DB(DB_Nummer_Word).DW[Datenwort_Index] := 1000;
oder
WORD_TO_BLOCK_DB(DB_Nummer_Word).DW10 := 1000;

Wenn noch einer etwas Besseres weiß, wäre ich auch dankbar.
Ob die Any-Pointer-Vaiante irgendwie zum Laufen zu bringen ist muß ich später mal testen, dazu sollte man sich aus jeden Fall das Compiler-Ergebnis in AWL anschauen, um zu sehen, was der Comiler eigenlich umsetzt.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ach so, noch ein Zusatz:

Code:
pDaten   := WORD_TO_BLOCK_DB(DB20.Parameter.DBNumber).DW[DB20.Parameter.WordNumber];   // Pointerzuweisung erster Datensatz 

    FOR index:=1 TO DB20.Parameter.Number DO     // In der Schlaufe werden alle Datensätzte bearbeitet. 
        Daten.TimeSet    := 345        ;                // Hier habe ich einfach einige Zuweisungen gemacht, dass ich testen kann. 
        Daten.TimeActual := Daten.TimeActual + 1;       // Leider funktionieren die Pointer nicht. 
        IF Daten.TimeSet > Daten.TimeActual THEN 
            Daten.Length := 123; 
        END_IF; 

        pDaten := WORD_TO_BLOCK_DB(DB20.Parameter.DBNumber).DW[DB20.Parameter.WordNumber + (DB20.Parameter.Length * index)];    // Pointerzuweisung nächster Datensatz 
    END_FOR;

Daten hat doch in diesen Code nichts mit pDaten zu tun, es gibt keine Verbindung zwischen beiden, die Deklaration

Code:
Daten               : UDT2; 
pDaten AT Daten     : ANY;

legt nur die Sicht fest.
 
Das mit dem Array ist nicht optimal, da ich die Daten im restlichen Programm mit dem Namen z.B Data_1 zugreifen muss. Mit einem Array würde das restliche Programm somit sehr unübersichtlich.


mfg

Leo
 
Verstehe ich nicht, statt

Code:
 L    "Daten".Data_1.Timeset 

schreibst du

  L     "Daten".Data[1].TimeSet
[/code]
 
Hallo,

da meine Challenge genau der damals beschriebenen entspricht und noch keine Lösung gefunden wurde, möchte ich diesen Thread noch mal hervor holen. Genau wie Anonymous möchte ich in immer gleicher Weise auf mehrere Instanzen eines UDT zugreifen. Ein Array wäre eine Lösung, aber dann hätten die Instanzen einen "nichtssagenden" Namen wie Motor[1] bis Motor[10]. Im Schaltplan sind diese aber mit M201, M302 etc. bezeichnet. Um die Übersichtlichkeit des Codes zu verbessern, wäre es sinnvoll, diese zu übernehmen.

Läßt sich das in SCL machen?

Gruß Hagen
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Um die Übersichtlichkeit zu erhöhen kann man Kommentare an den Code schreiben.

Wenn man indiziert auf Daten zugreifen will, dann müssen diese in indiziert adressierbarer Form organisiert sein - sprich: Array ("Array of Daten" oder "Array of Pointer to Daten"). In SCL gibt es noch die Möglichkeit, mit "AT"-Sichten Einzel-Instanzen über ein Instanz-Array zu legen. Durch verkettete Listen kann man ebenfalls in Schleifen iterieren. Bei wenigen Instanzen kann man mit CASE-Fallunterscheidungen arbeiten.

Um wieviele Instanzen geht es denn? Gibt es einen zwingenden Grund, die Instanzen indiziert anzusprechen?

Harald
 
Hallo Harald,

es geht darum einen Multiplexer zu bauen, der im OB35 über eine serielle Schnittstelle jeweils eine von maximal 6 Messkarten anspricht. Natürlich kann man die Daten für die Karten in einem Array ablegen. Dann habe ich aber keine Zuordnung zum Schaltplan mehr.

Habe mir jetzt überlegt, die im DB abgelegten Daten per BLKMOV zunächst in ein Array zu kopieren und dann damit zu arbeiten. Ich muss dann nur die Anfangsadresse, die Anzahl der Karten und die Länge der Struktur wissen, falls diese sich nochmal verändert. Möchte es halt so universell wie möglich gestalten, ohne bei einer Änderung in der Struktur die Daten für BLKMOV händisch anpassen zu müssen.

Gruß Hagen
 
Zuletzt bearbeitet:
Ähhhh ... OB35 und serielle Schnittstelle ... ???
Bist du dir sicher, dass du das so machen willst ...?

Wofür möchtest du das Ganze denn als Array of UDT verpacken wenn du doch eigentlich einen UDT "M101" und den nächsten "M234" nennen willst. Dann leg sie doch einzeln an ...
Oder hast du bei der späteren Verarbeitung Vorteile wenn du die Daten in einem Array hast ?

Gruß
Larry
 
Zurück
Oben