Step 7 SCL Anfänger Frage (im Prinzip Indiziert Zugriff auf DB's)

Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Boxy,

nebenbei erwähnt, DB_Nummer und Length sind beides positive Integerwerte. Deine statische Variable "Abbild" kann direkt symbolisch an die SFC20 als Parameter weiter gegeben werden. Hierfür musst du den Pointer nicht selbst zusammenbasteln.

Wenn du jedoch deinen "Arbeitsdatensatz" nicht in den Lokaldaten des Bausteins, sondern extern in einem weiteren DB als UDT ablegst, wird es noch wesentlich einfacher. Dann bleibt dir allerdings der ganze masochistische Kram mit dem Any-Pointer vergönnt :sad: . Ich weiß jetzt nicht, ob ich dir diesen Spaß verderben soll?


Gruß, Onkel

Danke für die Antwort :rolleyes:
Das mit dem Abbild direkt an den BLKMOV zu hängen, habe ich gerade selbst beim Versuch erfahren :rolleyes:
Ehrlich gesagt, warum dies dann so direkt funktioniert frage ich mich aber schon ein bisschen?
Wie würde dies dann aber bei einer Multiinstanz aussehen :confused:

Wenn du jedoch deinen "Arbeitsdatensatz" nicht in den Lokaldaten des Bausteins, sondern extern in einem weiteren DB als UDT ablegst, wird es noch wesentlich einfacher. Dann bleibt dir allerdings der ganze masochistische Kram mit dem Any-Pointer vergönnt :sad:

Beschreibe mir dies bitte einmal genauer?
Ich war ja eigentlcih auf der Suche nach einer einfachen Möglichkeit in SCL, DBxx-DBxz in DByy zu kopieren um dann intern immer mit DByy zu arbeiten.
Daher die ganze Sache da mit dem Any-Pointer, da ich hier dann den QuellDB dynamisch auswähle um diesen in den ArbeitsDB abzulegen ...

Irgendwie fehlt mir aber für das Projekt eh der ganze Lösungsansatz und von daher verdirbst Du mir da keinen Spaß :ROFLMAO:

Ich bin immer auf Tipps und Vorschläge offen und höre diese mir gerne an :cool:
Man(n) kann ja nur etwas dazu lernen!
 
.. Ehrlich gesagt, warum dies dann so direkt funktioniert frage ich mich aber schon ein bisschen?
Wie würde dies dann aber bei einer Multiinstanz aussehen :confused: ..

Der Compiler übergibt diese symbolische STRUCT-Variable als ANY mit dem Datentyp Byte an den Baustein. Und genau das kannst du dir zu nutze machen, wenn du deine Kopie extern in einem "Arbeits-DB" anlegst. Wichtig ist die Verwendung des UDT im DB und als Parametertyp im FC/FB.
Versuche mal folgende Schritte um zu setzen:


  1. Eingangsparameter mit der DB-Nr. als INT anlegen (das war gefordert)
  2. IN_OUT als UDTx anlegen (später Parameter mit UDTx aus DB versorgen)
  3. DB of UDTx anlegen (wie deine 20 anderen DBs)
  4. Im Baustein eine temporäre Variable vom Typ ANY anlegen, incl. AT-Sicht
  5. Zuweisen des IN_OUT aus (2.) auf den TEMP_ANY aus (4.) in SCL
  6. Überschreiben der DB-Nr. im TEMP_ANY mit (1.) mittels der AT-Sicht
  7. Kopieren der Daten mittels der SFC20
  8. etc.


Mit dem Punkt 5. wird praktisch der temporäre ANY vorbelegt. Es muss nur noch die DB-Nummer überschrieben werden. Am Ende sind das in SCL bis jetzt drei übersichtliche Programmzeilen.

Anschließend kannst du mit der Kopie über den IN_OUT im Baustein symbolisch lesend und schreibend arbeiten.

Am Ende muss vermutlich alles wieder zurück kopiert werden?


Gruß, Onkel
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Boxy,

ich hatte Dir in #7 empfohlen, den UDT zu übergeben, dann könntest Du ganz einfach sowas tun:
Code:
VAR_IN_OUT
  ioType : UDT2101; [COLOR="#008080"]//(der UDT wird als 6-Byte-POINTER übergeben)[/COLOR]
END_VAR
VAR_TEMP
  iResult : INT;
END_VAR
VAR
  Abbild : UDT2101; [COLOR="#008080"]//lokale Arbeits-Kopie des UDT[/COLOR]
END_VAR

[COLOR="#008080"]//einen kleinen UDT DWord-weise kopieren:[/COLOR]
  Abbild := ioType;

[COLOR="#008080"]//oder einen großen UDT besser mit BLKMOV kopieren:[/COLOR]
  iResult := BLKMOV(SRCBLK := ioType, DSTBLK := Abbild);

Warum willst Du die DB-Nummer übergeben? (da erscheint die DB-Verwendung nicht in den Referenzdaten/Querverweisen)
Soll der FB an mehreren Programmstellen mit jeweils festen Aktualparametern aufgerufen werden?
Oder soll bei einem FB-Aufruf die DB-Nummer aus einer Variable kommen?
Beginnt der UDT in den DB immer an Adresse DBX0.0?

Bei FB
  • nur in VAR_IN_OUT kann man einen "getypten" Pointer erstellen/übergeben
  • der UDT bzw. STRUCT wird als 6-Byte POINTER übergeben (nicht ANY)
  • es wird nur die Anfangsadresse des UDT übergeben, die Länge und die Struktur kennt der Compiler von der Typ-Deklaration
  • den Pointer kann man in SCL symbolisch in eine ANY-Variable kopieren, dabei übernimmt der Compiler die übergebene Anfangsadresse und ergänzt die ersten 4 Byte des ANY passend zur Typdeklaration des Übergabeparameters, z.B. P#DB120.DBX0.0 BYTE 100
  • der IN_OUT-Parameter muß nicht beschaltet werden, bei Aufruf in SCL kann er ganz weggelassen werden

Das kann man sich für das basteln eines ANY zunutze machen, so daß der Compiler automatisch den ANY-"Header" (ID + Datentyp + Länge entsprechend UDT) ausfüllt und muß dann nur noch die Anfangsadresse (DB-Nummer + Anfangsadresse mit Bereichskennung) eintragen. Dabei reicht es allerdings nicht, nur die DB-Nummer einzutragen, man sollte auch sicherstellen daß die Bereichskennung "DB" ist und die Anfangsadresse des UDT in dem DB korrekt ist.
Code:
VAR_INPUT
  inDBNo : INT;
END_VAR
VAR_IN_OUT
  ioType : UDT2101; [COLOR="#008080"]//(der UDT wird als 6-Byte-POINTER übergeben)[/COLOR]
END_VAR
VAR_TEMP
  iResult : INT;
  pAnyPointer : ANY;
  sAnyPointer AT pAnyPointer : STRUCT [COLOR="#008080"]//ANY Struktur:[/COLOR]
    AID : BYTE;  [COLOR="#008080"]// ANY-ID B#16#10 für S7[/COLOR]
    TYP : BYTE;  [COLOR="#008080"]// Datentyp[/COLOR]
    ANZ : INT;   [COLOR="#008080"]// Wiederholfaktor[/COLOR]
    DBN : INT;   [COLOR="#008080"]// DB-Nummer, falls Any auf DB[/COLOR]
    PTR : DWORD; [COLOR="#008080"]// Bereichsadresse mit Bereichskennung in MSB[/COLOR]
  END_STRUCT;
END_VAR
VAR
  Abbild : UDT2101; [COLOR="#008080"]//lokale Arbeits-Kopie des UDT[/COLOR]
END_VAR

[COLOR="#008080"]//ANY zu UDT2101 vorbelegen (P#<???> BYTE nnn)[/COLOR]
  pAnyPointer := ioType;             [COLOR="#008080"]//POINTER to UDT2101[/COLOR]
[COLOR="#008080"]//die übergebene DB-Nummer in den ANY eintragen:[/COLOR]
  sAnyPointer.DBN := inDBNo;         [COLOR="#008080"]//DB-Nummer[/COLOR]
[COLOR="#008080"]//der UDT beginnt immer an DBX0.0![/COLOR]
  sAnyPointer.PTR := DW#16#84000000; [COLOR="#008080"]//P#DBX0.0[/COLOR]
[COLOR="#008080"]//UDT von <inDBNo>.DBX0.0 in lokales Abbild kopieren[/COLOR]
  iResult := BLKMOV(SRCBLK := pAnyPointer, DSTBLK := Abbild);

Man kann auch einen ANY direkt auf die Adresse einer existierenden UDT-Variable setzen (und danach z.B. die DB-Nummern ändern):
Code:
  pAnyPointer := "DB120".UDT2101Variable; [COLOR="#008080"]//P#DB120.DBXy.0 BYTE xxx[/COLOR]
allerdings kann auf diese Art eine beliebige Variable angegeben werden - der Compiler prüft da nicht, ob die Variable vom gewünschten Datentyp (UDT2101) ist und die Längenangabe im ANY kann dann falsch sein!

Harald
 
Der Compiler übergibt diese symbolische STRUCT-Variable als ANY mit dem Datentyp Byte an den Baustein. Und genau das kannst du dir zu nutze machen, wenn du deine Kopie extern in einem "Arbeits-DB" anlegst. Wichtig ist die Verwendung des UDT im DB und als Parametertyp im FC/FB.
Versuche mal folgende Schritte um zu setzen:


  1. Eingangsparameter mit der DB-Nr. als INT anlegen (das war gefordert)
  2. IN_OUT als UDTx anlegen (später Parameter mit UDTx aus DB versorgen)
  3. DB of UDTx anlegen (wie deine 20 anderen DBs)
  4. Im Baustein eine temporäre Variable vom Typ ANY anlegen, incl. AT-Sicht
  5. Zuweisen des IN_OUT aus (2.) auf den TEMP_ANY aus (4.) in SCL
  6. Überschreiben der DB-Nr. im TEMP_ANY mit (1.) mittels der AT-Sicht
  7. Kopieren der Daten mittels der SFC20
  8. etc.


Mit dem Punkt 5. wird praktisch der temporäre ANY vorbelegt. Es muss nur noch die DB-Nummer überschrieben werden. Am Ende sind das in SCL bis jetzt drei übersichtliche Programmzeilen.

Anschließend kannst du mit der Kopie über den IN_OUT im Baustein symbolisch lesend und schreibend arbeiten.

Am Ende muss vermutlich alles wieder zurück kopiert werden?


Gruß, Onkel

Hi Onkel :p,

erst einmal Danke für die Erklärung!
Ich muss mir Deine Schritte einmal anschauen. Wobei der Eingangsparameter mit der DB-Nr. nicht zwangsläufig sein muss, warscheinlich würde diese [Nummer] zB per H-Funktion oder andersweitig innerhalb der Funktion selbst ausgelesen werden. Oder ich ermittle diese Nummer ausserhalb und rufe dann diesen FB mit den entsprechenden Parameten auf ...

Ob am Ende alles weider zurück kopiert werden muss, kann ich noch nicht sagen, aber denken einmal wennich noch eine Prüfung der Daten einbau wird dies ggf. möglich sein. Daher denke ich einmal "ja"



Hallo Boxy,

ich hatte Dir in #7 empfohlen, den UDT zu übergeben, dann könntest Du ganz einfach sowas tun:
Code:
VAR_IN_OUT
  ioType : UDT2101; [COLOR=#008080]//(der UDT wird als 6-Byte-POINTER übergeben)[/COLOR]
END_VAR
VAR_TEMP
  iResult : INT;
END_VAR
VAR
  Abbild : UDT2101; [COLOR=#008080]//lokale Arbeits-Kopie des UDT[/COLOR]
END_VAR

[COLOR=#008080]//einen kleinen UDT DWord-weise kopieren:[/COLOR]
  Abbild := ioType;

[COLOR=#008080]//oder einen großen UDT besser mit BLKMOV kopieren:[/COLOR]
  iResult := BLKMOV(SRCBLK := ioType, DSTBLK := Abbild);

Warum willst Du die DB-Nummer übergeben? (da erscheint die DB-Verwendung nicht in den Referenzdaten/Querverweisen)
Soll der FB an mehreren Programmstellen mit jeweils festen Aktualparametern aufgerufen werden?
Oder soll bei einem FB-Aufruf die DB-Nummer aus einer Variable kommen?
Beginnt der UDT in den DB immer an Adresse DBX0.0?

Eigentlich ist folgendes angedacht, der Anwender programmiert zB eine H-Funtion (zB NC-Programm) und übergibt somit eine Nummer, welchen Ablauf er starten möchte und dann wird zB mitteles M-Funkion dieser Ablauf gestartet.
In den Quell DBs werden diese Ablaufe über Masken usw. eingegeben / parametriert.
Durch den Start und der Funktionsnummer, wird nun dieser Ablauf welcher in dem spezifischen DB hinterliegt quasi ausgelesen und interpretiert.

Alternativ kann es ja auch sein, das man über eine Taste die Funktion bzw. einen spezifischen Ablauf starten möchte, dann wird ebenfalls eine Nummer entsprechend übergeben und den Ablauf gestartet. In weiterer Ausbaustufe kommt auch noch Vorabe von einer Automation usw. hinzu.

Daher denke ich, es könnte sein das dieser Baustein dann mehrfach aufgerufen werden könnte, aber ein zentrale Verwaltung wäre bestimmt auch möglich.

Der UDT bzw. die Quell DBs beginnen, wenn jeder Ablauf in einem eigen DB leigt immer eigentlich bei DBX0.0, da diese DBs vom Typ UDT dann sind.

Bei FB
  • nur in VAR_IN_OUT kann man einen "getypten" Pointer erstellen/übergeben
  • der UDT bzw. STRUCT wird als 6-Byte POINTER übergeben (nicht ANY)
  • es wird nur die Anfangsadresse des UDT übergeben, die Länge und die Struktur kennt der Compiler von der Typ-Deklaration
  • den Pointer kann man in SCL symbolisch in eine ANY-Variable kopieren, dabei übernimmt der Compiler die übergebene Anfangsadresse und ergänzt die ersten 4 Byte des ANY passend zur Typdeklaration des Übergabeparameters, z.B. P#DB120.DBX0.0 BYTE 100
  • der IN_OUT-Parameter muß nicht beschaltet werden, bei Aufruf in SCL kann er ganz weggelassen werden

Das kann man sich für das basteln eines ANY zunutze machen, so daß der Compiler automatisch den ANY-"Header" (ID + Datentyp + Länge entsprechend UDT) ausfüllt und muß dann nur noch die Anfangsadresse (DB-Nummer + Anfangsadresse mit Bereichskennung) eintragen. Dabei reicht es allerdings nicht, nur die DB-Nummer einzutragen, man sollte auch sicherstellen daß die Bereichskennung "DB" ist und die Anfangsadresse des UDT in dem DB korrekt ist.
Code:
VAR_INPUT
  inDBNo : INT;
END_VAR
VAR_IN_OUT
  ioType : UDT2101; [COLOR=#008080]//(der UDT wird als 6-Byte-POINTER übergeben)[/COLOR]
END_VAR
VAR_TEMP
  iResult : INT;
  pAnyPointer : ANY;
  sAnyPointer AT pAnyPointer : STRUCT [COLOR=#008080]//ANY Struktur:[/COLOR]
    AID : BYTE;  [COLOR=#008080]// ANY-ID B#16#10 für S7[/COLOR]
    TYP : BYTE;  [COLOR=#008080]// Datentyp[/COLOR]
    ANZ : INT;   [COLOR=#008080]// Wiederholfaktor[/COLOR]
    DBN : INT;   [COLOR=#008080]// DB-Nummer, falls Any auf DB[/COLOR]
    PTR : DWORD; [COLOR=#008080]// Bereichsadresse mit Bereichskennung in MSB[/COLOR]
  END_STRUCT;
END_VAR
VAR
  Abbild : UDT2101; [COLOR=#008080]//lokale Arbeits-Kopie des UDT[/COLOR]
END_VAR

[COLOR=#008080]//ANY zu UDT2101 vorbelegen (P#<???> BYTE nnn)[/COLOR]
  pAnyPointer := ioType;             [COLOR=#008080]//POINTER to UDT2101[/COLOR]
[COLOR=#008080]//die übergebene DB-Nummer in den ANY eintragen:[/COLOR]
  sAnyPointer.DBN := inDBNo;         [COLOR=#008080]//DB-Nummer[/COLOR]
[COLOR=#008080]//der UDT beginnt immer an DBX0.0![/COLOR]
  sAnyPointer.PTR := DW#16#84000000; [COLOR=#008080]//P#DBX0.0[/COLOR]
[COLOR=#008080]//UDT von <inDBNo>.DBX0.0 in lokales Abbild kopieren[/COLOR]
  iResult := BLKMOV(SRCBLK := pAnyPointer, DSTBLK := Abbild);

Man kann auch einen ANY direkt auf die Adresse einer existierenden UDT-Variable setzen (und danach z.B. die DB-Nummern ändern):
Code:
  pAnyPointer := "DB120".UDT2101Variable; [COLOR=#008080]//P#DB120.DBXy.0 BYTE xxx[/COLOR]
allerdings kann auf diese Art eine beliebige Variable angegeben werden - der Compiler prüft da nicht, ob die Variable vom gewünschten Datentyp (UDT2101) ist und die Längenangabe im ANY kann dann falsch sein!

Harald

Ich Danke auch Dir für die Erklärung :rolleyes: und werde mich mal damit vertiefen.
Denke mir ist nun klar geworden warum es einfacher wäre den UDT zu übergeben und daraufhin den DB einzuflicken ;)
Aber flasch war die Übung mit dem "Händischen" erstellen des Any-Pointers nun auch nicht ;)

Diese Tricks muss man halt kennen, was mir gerade aber nicht so recht lar ist, was übergebe ich da beim Aufruf?

Code:
VAR_IN_OUT
  ioType : UDT2101; [COLOR=#008080]//(der UDT wird als 6-Byte-POINTER übergeben)[/COLOR]
END_VAR

Wird da ein DB parametriert beim Aufruf oder?


Danke ecuh für eueren Support :rolleyes:
 
Wobei der Eingangsparameter mit der DB-Nr. nicht zwangsläufig sein muss
Wenn Du eine (variable) DB-Nummer übergeben willst und auch die Übergabe von UDT-DB oder UDT-Variablen möglich sein soll, dann kannst Du im FB so auswerten:
Code:
[COLOR="#008080"]//ANY zu UDT2101 vorbelegen, mit evtl. übergebener UDT-Adresse:[/COLOR]
  pAnyPointer := ioType;             [COLOR="#008080"]//POINTER to UDT2101[/COLOR]

[COLOR="#008080"]//falls eine DB-Nummer übergeben wird, dann mit diesem DB arbeiten (Vorrang):[/COLOR]
IF inDBNo <> 0 THEN
  sAnyPointer.DBN := inDBNo;         [COLOR="#008080"]//DB-Nummer in den ANY eintragen[/COLOR]
  sAnyPointer.PTR := DW#16#84000000; [COLOR="#008080"]//der UDT beginnt immer an DBX0.0![/COLOR]
END_IF;

[COLOR="#008080"]//UDT von <inDBNo>.DBX0.0 oder <ioType> in lokales Abbild kopieren:[/COLOR]
  iResult := BLKMOV(SRCBLK := pAnyPointer, DSTBLK := Abbild);


was übergebe ich da beim Aufruf?
Da kannst Du einen DB vom Typ UDT2101 oder eine Variable vom Typ UDT2101 anschalten.
Oder nichts anschalten und die DB-Nummer eines DB vom Typ UDT2101 anschalten oder von einem Global-DB, der eine Variable vom Typ UDT2101 ab Adresse DBX0.0 hat.

Angenommen, Du hast diese DBs:
Code:
DATA_BLOCK DB101 [COLOR="#008080"]//DB vom Typ UDT2101[/COLOR]
 UDT2101
END_DATA_BLOCK

DATA_BLOCK DB102 [COLOR="#008080"]//Global-DB enthält ab DBX2.0 eine Variable vom Typ UDT2101[/COLOR]
  STRUCT
    DB_VAR : INT;
    Data : UDT2101;
  END_STRUCT;
END_DATA_BLOCK

DATA_BLOCK DB103 [COLOR="#008080"]//Global-DB enthält ab DBX2.0 ein Array mit Variablen vom Typ UDT2101[/COLOR]
  STRUCT
    DB_VAR : INT;
    Tabelle : ARRAY [1..10] OF UDT2101;
  END_STRUCT;
END_DATA_BLOCK
dann kannst Du in SCL Deinen FB (z.B. FB123 mit IDB DB123) so aufrufen:
Code:
[COLOR="#008080"]//sicherstellen, daß keine DB-Nummer in inDBNo steht:[/COLOR]
  DB123.inDBNo := 0;       [COLOR="#008080"]//vor dem Aufruf der Instanz DB123[/COLOR]
  FB123.DB123(inDBNo := 0, ioType := ...); [COLOR="#008080"]//oder beim Aufruf[/COLOR]

[COLOR="#008080"]//einen DB vom Typ UDT2101 übergeben (geht nicht in AWL/FUP/KOP):[/COLOR]
  FB123.DB123(ioType := DB101);

[COLOR="#008080"]//eine Variable vom Typ UDT2101 übergeben (die muß nicht an Adresse DBX0.0 liegen):[/COLOR]
  FB123.DB123(ioType := DB102.Data);
  FB123.DB123(ioType := DB103.Tabelle[2]);

[COLOR="#008080"]//nicht schön (Zugriff auf interne IDB-Variable)
//und nicht sinnvoll (kopiert auf sich selbst), sowas geht aber auch:[/COLOR]
  FB123.DB123(ioType := DB123.Abbild);


[COLOR="#008080"]//eine DB-Nummer übergeben (der UDT2101 muß ab DBX0.0 im DB liegen):[/COLOR]
  FB123.DB123(inDBNo := 101); [COLOR="#008080"]//DB101[/COLOR]
  FB123.DB123(inDBNo := 101, ioType := DB102.Data); [COLOR="#008080"]//DB101 wird genommen! wg. Vorrang inDBNo[/COLOR]

[COLOR="#008080"]//eine variable DB-Nummer übergeben:[/COLOR]
  iTempDBnummer := 101;
  FB123.DB123(inDBNo := iTempDBnummer); [COLOR="#008080"]//DB101[/COLOR]

Harald
 
Zurück
Oben