TIA Variant zum Zweiten

vollmi

Level-3
Beiträge
5.423
Reaktionspunkte
1.403
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi zusammen

Ich habe mir mal einen Kommunikationsbaustein geschrieben für die 1500er bzw mit kleinen Aenderungen für die 1200er.

Code:
FUNCTION_BLOCK "SendReciveOverTCP_1500"TITLE = 'Kommunikationsbaustein'
{ S7_Optimized_Access := 'FALSE' }
AUTHOR : VoR
FAMILY : TUV
NAME : KLP
VERSION : 1.1
// Dieser Baustein bietet den Server an.
// Passt zum Baustein MasterCom mit BSEND/RECV
//
// 1.0 Erste Version
// 1.1 Korrigierte Version um empfangszyklus zu messen
   VAR_OUTPUT 
      zykl : Time;
      WD : Bool;
   END_VAR


   VAR_IN_OUT 
      Configuration {OriginalPartName := 'TCON_IP_v4'; LibVersion := '1.0'} : TCON_IP_v4;
      DB_1_Recv : Variant;   // DB der von AS nach LST geht
      DB_1_Send : Variant;   // DB der von LST nach AS geht
   END_VAR


   VAR 
      save_status_Put : Word;
      save_status_Get : Word;
      Zeit_alt : Time;
      SEND_Instance {OriginalPartName := 'TSENDC'; LibVersion := '3.0'} : TSEND_C;
      RCV_Instance {OriginalPartName := 'TRCVC'; LibVersion := '3.0'} : TRCV_C;
      WD_TIMER {OriginalPartName := 'IEC_TIMER'; LibVersion := '1.0'} : TON_TIME;
      Send_Reset {OriginalPartName := 'IEC_TIMER'; LibVersion := '1.0'} : TON_TIME;
   END_VAR


   VAR_TEMP 
      Zeit : Time;
      len : Word;
   END_VAR




BEGIN
	#len := 0;
	
	// Watchdog bearbeiten
	#WD_TIMER(IN :=  NOT #RCV_Instance.DONE
	         ,PT := t#5s);
	
	#WD := #WD_TIMER.Q; // OUT: BOOL
	
	#Zeit := TIME_TCK(); // Zeile muss für 1200er entfernt werden.
	IF #RCV_Instance.DONE THEN
	    #zykl := #Zeit - #Zeit_alt;
	    #Zeit_alt := #Zeit;
	END_IF;
	
	
	#SEND_Instance(CONT:=TRUE,
	                LEN:=#len,
	                CONNECT:=#Configuration,
	                DATA:=#DB_1_Send);
	
	
	#SEND_Instance.REQ := TRUE;
	
	IF #SEND_Instance.ERROR OR #SEND_Instance.DONE OR #Send_Reset.Q THEN
	    #SEND_Instance.REQ := False;
	END_IF;
	
	IF #SEND_Instance.ERROR THEN
	    #save_status_Put := #SEND_Instance.STATUS;
	END_IF;
	
	#Send_Reset(IN:=#SEND_Instance.REQ,
	            PT:=t#10s);
	
	
	
	
	
	#RCV_Instance(EN_R:=TRUE,
	               CONT:=1,
	               LEN:=#len,
	               CONNECT:=#Configuration,
	               DATA:=#DB_1_Recv);
	
	
	IF #RCV_Instance.ERROR THEN
	    #save_status_Get := #RCV_Instance.STATUS;
	END_IF;
	
	
END_FUNCTION_BLOCK

Das funktioniert eigentlich ganz okay. Da man aber einen Variant übergeben muss habe ich keine möglichkeit da irgendwie rauszukriegen um welche DB Nummer es sich handelt. Die bräuchte ich aber um einen Peek Poke drauf zu machen. um mit einen Watchdogzähler einzubauen.

Hat jemand eine IDEE wie ich aus dem Variant irgendwie rausbekomme welcher DB da angeschlossen ist? Ggf noch wie lange ebenjener ist? Auch wenn er nicht aus einem PLC-Typ abgeleitet wurde und auch nicht zwingend ein Array ist?

mfG René
 
Hi Vollmi

es gibt da eine Funktion VARIANT_TO_DB_ANY. Die liefert dir im DB_ANY, der auch nix anderes ist als ein UINT die DB-Nummer. Seit wann es die gibt ... vielleicht seit V13 .. oder doch erst 13SP1 ... ich weiß nicht mehr. Also die verrät dir die DB Nummer.
Wenn der DB optimiert ist, dann gibt es keine Möglichkeit heraus zu bekommen, wie lang der ist.

Bei einer Schulung (oder sollte ich Workshop sagen) hat einer erzählt, dass ein DB aus drei Teilen besteht. Wir können im FB für jede Variable angeben, ob diese Retain oder nicht ist. Und dann gibt es da noch den dritten Wert: SetInDB. Die Retain und NichtRetain Variablen sind im optimierten Speicher. Die anderen sind im nicht optimierten Speicher. Damit hat der DB, der aus dem FB entsteht drei Längen. Ein GetDBLength müsste einen Parameter bekommen, damit wir anfragen können welche Länge wir denn nun meinen. Darauf meinte der Dozent: "Aber wozu? Was hätten wir davon?"

Klar, er hätte meine Neugier befriedigt, aber was wäre der Anwendungsfall? Und leider hatte ich keinen richtigen außer Kommunikation. Und dafür gibts was. TSEND und TRCV. Die haben VARAINT an der Schnittstelle "und die machen alles für uns" sagte er :-(

Wenn ich von einer Struktur wissen will, wie groß die auf der Leitung ist, dann kann ich diese mit SERIALIZE oder DESERIALZE in einen Buffer schreiben, aus einem Puffer lesen. Im Puffer hat sie das Leitungsformat. Das hat aber nichts mit der Ablage im Speicher zu tun. Die beiden Funktionen sind Fett und Laaaaangsam. Was mich bei der Kommunikation aber nicht stört, denn TSEND und TRCV sind sowieso asynchron :)

Wenn der DB nicht optimiert ist gibt es noch eine Möglichkeit. In AWL :-( L DBLEN
Das geht aber halt nur in AWL und nur für nicht optimierte DB. Aber da du mit der 1500 arbeitest, kannst du in etwa

Code:
OPEN DB[ #tempDB_ANY ]
L DBLEN
T #tempLen

versuchen

'n schön' Tach auch
HB
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi Vollmi

es gibt da eine Funktion VARIANT_TO_DB_ANY. Die liefert dir im DB_ANY, der auch nix anderes ist als ein UINT die DB-Nummer. Seit wann es die gibt ... vielleicht seit V13 .. oder doch erst 13SP1 ... ich weiß nicht mehr. Also die verrät dir die DB Nummer.

Leider nur wenn der DB nicht optimiert ist UND aus einem Systemdatentyp oder Anwenderdatentyp besteht. Ein Standardglobaldb aus ein paar INT oder Word oder Strukturen zusammengesetzt wie man ihn z.B. seit Classic überall nutzte liefert keine DB Nummer zurück.
Das ist ja der Witz daran. Aus was für einem Grund sollte es nötig sein die DB Nummer eines SystemdatentypDBs zu bekommen aber aus einem standardglobalDB nicht?

Wenn der DB optimiert ist, dann gibt es keine Möglichkeit heraus zu bekommen, wie lang der ist.

Fürs Erste würde mir auch reichen einfach nur die DB nummer herauszubekommen aus einem stink normalen nicht optimierten GlobalDB der per Variant übergeben wurde.

Code:
OPEN DB[ #tempDB_ANY ]
L DBLEN
T #tempLen

versuchen

Was per AWL geht will ich mal versuchen. Eben ich hätte erstmal gerne nur die DB Nummer aus nem Variant erfahren. Nicht mehr. Alles weitere ist dann eher nice to have.

mfG René
 
HI vollmi,

wenn dein Variant ein Array ist, dann kannst du es über CountOfElemts() ermitteln.

Code:
IF IS_ARRAY(#Tag_VARIANTToArray) THEN
 "Tag_Result" := CountOfElements(#Tag_VARIANT);
 END_IF;


Gr. Michitronik
 
Zurück
Oben