TIA SCL Daten von FB in beliebigen DB schreiben

ChrissT

Level-1
Beiträge
16
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

nachdem ich jetzt weis wie ich Daten in den DB eines FB schreibe möchte ich nun folgendes.
Für euch sicher kein großes Ding. Ich bin allerdings C Programmierer und finde mich in der SCL-Welt noch nicht so zurecht.


Bsp.

FB52 call FB15 -> schreibt Daten in DB52

Also Der FB52 ruft einen Funktionsbaustein FB15 auf. Dieser wertet Daten aus und soll diese in den DB52 des FB52 schreiben. Es handelt sich dabei um ein 20Byte array.

Wie mache ich das am besten.
Meine Vorstellung wäre, ich übergebe die Startadresse des Arrays dem FB15. Dieser schreibt dann über das Array die Daten in meinem DB52.

Kann mir da vielleicht jemand weiter helfen???

schönes Wochenende und Danke!
 
Hallo,
ich habe es nicht so richtig gecheckt ...
- Der FB52 mit dem DB52 ruft den FB15 auf.
- Der FB15 "befruchtet" in seiner Instanz ein Array auf das du im FB52 dann zugreifen willst ?
Ist das so korrekt ?
Wenn ja, dann brauchst du den FB15 nur zur einer Teilnehmer der Instanz des FB52 machen. Das geht, in dem du ihn im STAT-Bereich des FB52 als Typ deklarierst. Nun kann der FB15 alles an den FB52 "vererben" ...

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hey,

vielen Dank für die Antwort. Ich musste jetzt erstmal genau definieren was ich will. Wie gesagt, ich komme nicht aus der SCL Welt.
Ich versuche es nochmal genauer zu erklären.

Ich habe einen globalen DB 52 mit Listen (um genau zu sein habe ich davon mehrere)
L1 : Array [0 .. 8] of Byte;
L2 : Array [0 .. 8] of Byte;

Dann habe ich einen Baustein FB15 der mir Daten via Mailboxfunktion holt.
Jetzt suche ich nach einer Möglichkeit, den FB15 über einen FB52 aufzurufen und dem FB15 mitzuteilen, dass die Daten in die Liste L1 des DB52 legen soll oder in den DB53 oder in den DB54.....

Was vielleicht noch zu erwähnen ist, ist das die Antwort der Mailboxfunktion 12 Byte sind und ich nur die Daten ohne Offset benötige. Ich habe es schon geschafft, wenn dem FB15 indiziert das bytearray übergebe. db52.L1. So will ich das aber nicht.
Was ich damit sagen möchte ist, ich übergebe dem FB15 bspw. die Adresse und die Länge der des Arrays L1 in einem beliegen DB.

Gibt es vielleicht eine Möglichkeit, wenn ich den FB15 aufrufe, ihm mittzuteilen, benutze jetzt den DB5x und schreibe den Inhalt in L1????

Kann mir jemand helfen?
Grüße
 
Zuletzt bearbeitet:
Na ... das ist doch prima ...
Da solltest du dich (mal losgelößt von SCL) zum Einen mit dem SFC Blockmove (ich meine das ist SFC20 - bin mir da aber gerade nicht sicher) und zum Anderen mit dem Stichwort "ANY-Pointer" (hierzu auch gerne die Foren-Suche bemühen) beschäftigen. Damit läßt sich das lösen ...
Wenn du dazu speziellere Fragen hast : gerne posten ...

Gruß
Larry
 
Hallo Larry,

vielen Dank ich habe vermutet, dass es darauf hinaus läuft.
Ich habe jetzt also angefangen mich mit den ANY Pointern zu befassen. Ich habe auch folgendes Beispielprojekt gefunden:

Code:
FUNCTION_Block FB598  
  
VAR  
	Test1: STRUCT  //ANY Struktur 1 anlegen              
		ANY_id: BYTE;  //Define ANY structure 1  
		Source_DataType: BYTE;  
		Source_Lenght: WORD;  
		Source_DB_Nummer: WORD;  
		Source_Byte_Pointer: DWORD;  
		END_STRUCT;  
	Test2: STRUCT  //ANY Struktur 2 anlegen  
		ANY_id: BYTE;  //Define ANY structure 2  
		Destin_DataType: BYTE;  
		Destin_Lenght: WORD;  
		Destin_DB_Nummer: WORD;  
		Destin_Byte_Pointer: DWORD;  
		END_STRUCT;  
	//Deklaration ANY Pointer für Quell-DB  
	//Declaring ANY pointer of source DB  
	pAny_source AT Test1: ANY;    
	//Deklaration ANY Pointer für Ziel-DB  
	//Declaring ANY pointer of target DB  
	pAny_destin AT Test2: ANY;    
	erg: INT;  //Rückgabewert / Return value  
END_VAR  
  
BEGIN  
Test1.ANY_id:= 16#10;  //Vorbelegen der Quell-ANY-Pointer Variablen  
Test1.Source_DataType:= 16#2;  //Assign values for source pointer  
Test1.Source_Lenght:= 16#0a;  
Test1.Source_DB_Nummer:= 16#06;  
Test1.Source_Byte_Pointer:= dw#16#84000000;  
  
Test2.ANY_id:= 16#10;  //Vorbelegen der Ziel-ANY-Pointer Variablen  
Test2.Destin_DataType:= 16#2;  //Assign values for destination pointer  
Test2.Destin_Lenght:= 16#0a;  
Test2.Destin_DB_Nummer:= 16#07;  
Test2.Destin_Byte_Pointer:= dw#16#84000000;  
//Aufruf SFC20 und Parametrierung der ANY-Pointer-Variablen  
//Calling SFC20 and programming of ANY pointer variables  
erg:= SFC20(srcblk:= pAny_source, dstblk:= pAny_destin);  
END_FUNCTION_BLOCK

Habe das ganze in TIA V12 über externe Quellen geladen und einen Baustein generiet. Leider habe ich immer bei

pAny_source "AT construct"

das der Datentyp an dieser Stelle nicht erlaubt ist. Ich habe dazu auch was gefunden, aber auch wenn ich es den TEMP Bereich verschiebe ändert sich daran nicht.
Hast du eine Idee???

Danke!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,
im Moment nicht - es gibt da aber auch ein kleines Problem :
- ich arbeite nicht mit TIA V12 - ich weiß nicht, ob es daran liegt ... 8)

Bei der Deklaration mache ich es gewöhnlich anders herum : ich lege mit die ANY-Variable an und bilde darauf die AT-Sicht. Das sollte aber eigentlich keine Rolle spielen.
Der ANY und die AT-Sicht müssen im gleichen Deklarationsbereich stehen (hier TEMP).

Gruß
Larry
 
Hallo,
SCL in TIA V12 funktioniert am besten mit Symbolischer Adressierung. Wenn du Daten in einem Globalen DB Schreiben/ Lesen möchtest geht das von jedem OB, FB, FC.
z.B. daten in den DB Schreibe "Daten".Array[index] := 1;
z.B. Daten aus dem DB lesen "Merker" := "Daten".Array[index];

MfG
loefflfab
 
Ich bin leider immer noch kein Stück weiter ;(

Ich versuche nocheinmal die Funktion genauer zu beschreiben.

FB1 -> prüft welcher Teilnehmer felerhaft ist ruft dann FB2
FB2 -> hier wird vorgegeben welche Diagnosen geholt werden sollen. -> FB3
FB3 -> holt über kommandoschnittstelle die unterschiedlichen Diagnosen

1. Es gibt die Möglichkeit den fehlerhaften Teilnehmer bis zum FB3 zu kommunizieren so das dieser weiss in welchen globalen DB (jeder Teilnehmer hat einen eigenen DB für die Diagnosen) er die Daten packen soll. Hier könnte ich das dann auch einfach so machen: "Daten".Array[index] := 1;
Meiner Meinung nach völlig unschön!!!

In TIA V12 komme ich überhaupt nicht mit den Zeigern und den AT Sichten zurecht. Ich weiss zwar mittlerweile wie man einen anlegt, aber nicht wie ich Daten bzw. Array weiter reiche.

Wünschen würde ich mir folgendes:
FB1 erkennt fehler und teilt FB2 den dazugehörigen globalen DB mit. Also zb. DB1
FB2 holt die Diagnose über FB3 und gibt den globalen DB1 weiter und sagt dazu aber noch in welchem Array die Daten stehen sollen. Also sowas wie "Daten".Array[index] := 1;

Hat irgendjemand ne Lösung mit TIA V12.............
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

also dein FB1 wird im OB1 aufgerufen und prüft die Teilnehmer, die Teilnehmer haben einer Variable, sagen wir 1 oder 2 oder 3 usw. beim Ausfall wird im FB1 der FB2 aufgerufen und die Variable als Input übergeben.
Nun versteh ich das nicht ganz, FB2 prüft den Teilnehmer und wertet den Fehler aus oder? FB3 nimmt dann die Auswertung und soll dann das entprechende Array kopieren?
Sagen wir nun Teilnehmer 2 fällt aus und es liegt Fehler 2 an. Fehler 2 liegt in Array Fehler2 des DB2 und du willst das in das Array "Fehler" des DB3 haben, sagen wir das sind 10 Bytes, dann würde das in etwa so aussehen.
Ich hab mit TIA noch nix weiter gemacht, aber so mach ichs in SCL. Die Symbolik muß da entsprechend angepaßt werden...

Code:
 If Fehler = 2 then
               For i := 0 to 9 by1 Do 
               DB3.Fehler[i] := DB2.Fehler2[i];
               End_For; 
            End_if;



Das geht sicher hübscher und eleganter, aber ich denke mal es sollte erstmal weiterhelfen.
 
Wenn du schreibst du bist C-Programmierer: Wie würdest du das denn in C machen?
Das Konzept ist doch sehr ähnlich, außer dass es in SCL keine richtigen Pointer gibt bzw. die Weitergabe von Daten als Referenz durch mehrere Bausteine umständlich wird, da soetwas direkt nicht geht.

Wenn nur der FB1 weiß zu welchem Datensatz die Diagnosedaten gehören, kann er die unterlagerten FBs mit einem anonymen Datensatz aufrufen, und kopiert die nach Fertigstellung dann wieder an die entsprechende Stelle im Global-DB.
 
@ Bapho:

Vielen Dank für den Tipp. Das passt so nicht ganz. Ich will dem FB3 einfach einen globalen DB nennen indem er die Diagnosedaten legen soll. Nichts auswerten.
Eleganter geht dein vorhaben mit BLOCK_MOV.

@Thomas_v2.1
C-Code:

int diagnose (int* buffer)
{
memcpy(diagnose, buffer, sizeof(buffer)) //jaja ich weiss sizeof ist nur die länge der Adresse ist aber klar was ich meine ;)
}

int buff[10];

diagnose(int* buff) //Aufruf der Funktion und übergabe des Zeigers auf den Speicherbereich.

An deiner Idee bin ich gerade am basteln. Da Teilnehmer 1 der DB1, Teilnehmer 2 der DB2, usw zugordnet ist, würde ich aber gerne die DB-Nummer als Variable übergeben. Da die DB's alle gleich aufgebaut sind.
Bsp:

Teilnehmer := 1
DB[Teilnehmer].Array1 //in dieses Array könnte ich dann die Daten mit BLOCK_MOV kopieren.

Geht sowas?? Also die DB Nummer als Variable. WORD_TO_BLOCK_DB gibts in TIA nicht....
Ich flipp noch aus...........
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich versteh nicht wozu die der Zugriff über DB Nummern, sowas würde ich nur machen wenn es absolut nicht anders geht. Und in 99% der Fälle geht es anders - wenn man die Daten richtig strukturiert hat.

Man kann in einem DB auch Arrays anlegen, oder Arrays of Struct (oder besser noch UDT), oder Array of Array, oder...
Code:
DATA_BLOCK "Global_DB"

STRUCT
    Data : ARRAY[0..10] OF STRUCT
        iVal1 : INT;
        iVal2 : INT;
    END_STRUCT;
END_STRUCT

Zugriff geht dann über Index:
Code:
"Global_DB".Data[#Index].iVal1 := 123;

Kopieren geht ohne Blockmove
Code:
"Global_DB".Data[1] := "Global_DB".Data[2];
 
C-Code:

int diagnose (int* buffer)
{
memcpy(diagnose, buffer, sizeof(buffer)) //jaja ich weiss sizeof ist nur die länge der Adresse ist aber klar was ich meine ;)
}

int buff[10];

diagnose(int* buff) //Aufruf der Funktion und übergabe des Zeigers auf den Speicherbereich.

Soetwas geht in SCL nicht, bzw. macht keinen wirklichen Sinn.
Man legt vorher fest wie ein Datensatz der Diagnose auszusehen hat, und macht daraus optimalerweise einen UDT.
Dann legst du einen FC an, der als IN_OUT Parameter eine Variable vom Typ des UDTs hat.
In dem FB der den FC aufruft, legst du z.B. im Stat-Bereich ebenfalls eine Variable vom Typ des UDTs an. Wird der FC aufgerufen bekommt er als Parameter die Instanz-Variable übermittelt.

Hier mal ein Beispiel wie ich das vom Prinzip her meine (Programm ist so ohne sinnvolle Funktion, nur als Demonstration):
Code:
// Datensatz für Diagnosedaten
TYPE "tDiagSet"
    STRUCT
        Status : INT;
        FehlerNr : INT;
    END_STRUCT
END_TYPE


// Global-DB mit Speicher für 10 Diagnosesätze
DATA_BLOCK "Global_DB"
STRUCT
    Data : ARRAY[1..10] OF "tDiagSet";
END_STRUCT
BEGIN
END_DATA_BLOCK


// Funktion die Diagnosedaten einsammelt
FUNCTION "GetDiagData" : VOID
VAR_IN_OUT
    DiagData : "tDiagSet";
END_VAR

BEGIN
    DiagData.Status := 100;
    DiagData.FehlerNr := 1;
END_FUNCTION


// Übergeordnete Funktion
FUNCTION_BLOCK FB901
VAR
    DiagBuf : "tDiagSet";
END_VAR

// Diagnosedaten holen
"GetDiagData"(DiagData := DiagBuf);

// Diagnosesatz in Global DB kopieren
"Global_DB".Data[1] := DiagBuf;

END_FUNCTION_BLOCK
 
Irgendwie habe ich das Gefühl wir reden aneinander vorbei.

Du hast 10 Teilnehmer und 10 DBs mit gleicher Struktur, wenn ein Teilnehmer Probleme macht, werden diverse Diagnosedaten in dem DB abgelegt. Du willst nun im Fehlerfall die Daten in aus dem entsprechenden DB in einen anderen DB kopieren um das dann da zu puffern oder was auch immer. Dein Problem ist nun, wie du die Daten aus dem richtigen DB kopierst, oder?
Also machste dir einen Fehler FC/FB (Methode), legst da als Input die Nummer des entsprechenden DB an und kopierst dann die Geschichte mit Blockmove oder mit einer Schleife.
Ich habe den Blockmove immer nur in AWL verwendet, in SCl spar ich mir das Pointerbasteln und mach es mit einer For Schleife.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

nochmal viele Dank für eure Bemühungen. Ich versuche es jetzt mal so darzustellen wie ich es habe.


DATA_BLOCK "Global_DB1"
Liste_1: ARRAY[1..10] OF "Byte";
Liste_2: ARRAY[1..10] OF "Byte";
Liste_3: ARRAY[1..10] OF "Byte";
BEGIN
END_DATA_BLOCK

DATA_BLOCK "Global_DB2"
Liste_1: ARRAY[1..10] OF "Byte";
Liste_2: ARRAY[1..10] OF "Byte";
Liste_3: ARRAY[1..10] OF "Byte";
BEGIN
END_DATA_BLOCK

//Teilnehmer 1 fehlerhaft FB1-->FB2
FUNCTION "GetDiagData" : VOID
VAR_IN_OUT
DB : "Global_DB1"; // Das hier geht schon nicht in TIA V12 wie soll ich einem FB einen DB mitteilen?
END_VAR

//FB2->FB3 //holt Diagliste 1
//get liste 1 und lege sie in
Global_DB1.Liste_1 := (Daignose Daten für Liste 1)
//get liste 2 und lege sie in
Global_DB1.Liste_2 := (Daignose Daten für Liste 2)

Ich will doch nur, dass jeder Teilnehmer einen eigenen DB hat indem man, sollte er fehlerhaft (gewesen) sein, die Diagnosedaten findet. Die Diagnosedaten zu holen soll eine Funktion übernehmen, der ich aber noch mitteilen will wohin sie die Daten kopieren soll. Ich habe bei einem fehlerhaften Teilnehmer immer den gleichen DB, aber unterschiedliche "Listen" (ARRAYs) die gefüllt werden müssen.

Letztendlich brauche ich doch nur eine Art referenz um offen für Erweiterungen zu sein. Mein Ziel ist es, sollte ein weiterer Teilnehmer dazu kommen, dass man lediglich den DB kopieren und diesen als neuen Parameter weiter geben muss.

Das muss gehen, da bin ich mir sicher.... Ich will doch nur einen Zeiger auf ein globalen DB und dann einen Zeiger auf ein ARRAY in diesem DB.
 
Zuletzt bearbeitet:
Wie viele Teilnehmer hast du denn, und auf wieviele soll das ggf. erweitert werden?
Wenn es nur 10 sind, würde ich wohl eine Case-Abfrage machen in der dann für den Teilnehmer auf den zugehörigen Datenbereich geschrieben wird.

Vielleicht ist dein Konzept mit deiner zentralen Diagnosefunktion die alle Teilnehmer abfragt auch nicht ganz optimal.
Wenn du einen FB pro Teilnehmer hättest der nur sich selber diagnostiziert ist das einfacher zu handhaben. Kommt ein neuer Teilnehmer hinzu, fügst du einfach eine neue FB-Instanz hinzu und fertig.
 
Ich habe anfänglich drei Teilnehmer und will bis 16 erweitern können.

An die CASE Abfrage hab ich auch schon gedacht. Ich könnte eine Teilnehmernummer weiterreichen. Aber dann müsste ich doch auch über einen INDEX auf den DB zugreifen können oder?
Auch das ist mir bis jetzt noch nicht gelungen.

Die Idee mit dem FB finde ich gar nicht so schecht. Erhöhe ich dadurch nicht die CPU-Last? Ich meine ich hab ein vielfaches an FBs.
Aber kennst du das, wenn du dir einen Weg ausgedacht hast, der sicherlich gut ist, aber nur an der Umsetzung scheitert, dann verfolge ich den bis es passt. Und eine Referenz zu übergeben muss in TIA SCL doch gehe oder?

Kannst du dir mittlerweile vorstellen was ich machen will?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Also,

jetzt hab ich was gefunden. Mit POKE kann man anscheinend über einen Index auf einen DB zugreifen. Was ich allerdings nicht geschafft habe, ist daten in ein array des DB zu schreiben.

//DB1
DATA_BLOCK "Global_DB1"
Liste_1: ARRAY[1..10] OF "Byte";
Liste_2: ARRAY[1..10] OF "Byte";
Liste_3: ARRAY[1..10] OF "Byte";
BEGIN
END_DATA_BLOCK

FOR #count := 0 TO 10 DO
POKE(area:=16#84,
dbNumber:=#teilnehmer,
byteOffset:=(#offset+#count),
value:=#data_recv[#count]);
;
END_FOR;

Sollte das nicht funktionieren? Offset ist für die erste Liste ->Liste_1 doch 0, oder?
 
Zurück
Oben