miasma
Level-2
- Beiträge
- 368
- Reaktionspunkte
- 116
-> Hier kostenlos registrieren
Hallo!
Die Länge die es zu kopieren gilt ist variabel (Also der Parameter COUNT am MOVE_BLK)
Kannst Du ausschließen das der Fehler nicht hier liegt ?
Folge dem Video um zu sehen, wie unsere Website als Web-App auf dem Startbildschirm installiert werden kann.
Anmerkung: Diese Funktion ist in einigen Browsern möglicherweise nicht verfügbar.
Hallo!
Die Länge die es zu kopieren gilt ist variabel (Also der Parameter COUNT am MOVE_BLK)
Für Sendedaten würde ich keinen "optimierten" Speicher verwenden, weil Sendedaten immer eine bestimmte Struktur einhalten müssen, die in "optimiertem" Speicher aber umgewürfelt wird - es sei denn die Sendedaten sind als BYTE-Array strukturiert.
Wie sieht der Code genau aus?In diesem Beispiel, wenn c < 0 ist, dann wird mir aber nicht - wie erwartet - c inkrementiert, sondern es wird ein Nonsens-Wert auf d geschrieben.Code:a - b = c; IF c < 0 THEN c := c + 1; END_IF;
FUNCTION_BLOCK "TCP_CTRL"
{ S7_Optimized_Access := 'TRUE' }
VAR
Snd_Timer : Real;
Snd_Buffer { ExternalWritable := 'False'} : Array[1.."Snd_Buffer_Max"] of Int;
Test : Struct
TON_Snd_Lock : TON_TIME;
TON_Snd_Request : TON_TIME;
END_STRUCT;
END_VAR
BEGIN
#Test.TON_Snd_Lock(IN := #State.Snd_Lock,
PT := t#50ms);
#Test.TON_Snd_Request(IN := #State.Snd_Request,
PT := t#50ms);
IF #Test.TON_Snd_Lock.Q AND #Test.TON_Snd_Request.Q THEN
#State.Snd_Lock := FALSE;
#State.Snd_Request := FALSE;
END_IF;
END_FUNCTION_BLOCK
FUNCTION_BLOCK "TCP_DATA_AI"
{ S7_Optimized_Access := 'TRUE' }
VAR_INPUT
Cycletime : Real := 0.001; // OB Cycletime [s]
Intervall : Real := 1.0; // Aufzeichnungsintervall [s]
Snd_Intervall : Real := 3.0; // Sende Intervall [s]
BufferTime : Real := 10.0; // Pufferzeit [s] (gesamt)
In_0 : Variant; // INT, DINT or REAL, Connect to BYTE if not used
In_1 : Variant; // INT, DINT or REAL, Connect to BYTE if not used
END_VAR
VAR_IN_OUT
TCP_Ctrl : "TCP_CTRL";
END_VAR
VAR
Init : Array[0..#ChMax] of Bool;
Val : Array[1..#ChMax, 0..1] of Int;
ChNeed : Int; // Optimal Channel Size
ChUsed : Int;
FiFoUsed : DInt; // FiFo used Size
Er : Bool; // Error
ElSize : Int; // Element Size
ElNumb : Int; // Number of Elements
SSW : Int := 1; // State Machine
IntCount : Real; // Intervall Counter
SndCount : Real; // Sende Counter
i : Int := 1; // Loop Counter
iFF : DInt := 1; // Loop Counter for FiFo
Snd_ElNb : Int; // Number of Elements to send
Snd_ElNbMax : Int; // Number of max. Elements that fit in Buffer
Snd_EltoMuch : Bool; // Buffer to small
Snd_HeaderSize : Int; // Header Size
Snd_PtrREndOld : Int; // End of Element which was send before
Test : Struct
Active : Bool;
Len : UDInt;
Buffer : Array[1..32768] of Int;
END_STRUCT;
Tick : UDInt; // Ticks
PtrR : Int; // Read Pointer
PtrW : Int := 1; // Write Pointer
Type : Array[1..#ChMax] of Int; // 1..Int 2..Dint 3..Real
FIFO : Array[1..#FiFoMax] of Int; // Data Array
END_VAR
VAR CONSTANT
ChMax : Int := 2; // Default: 55
FiFoMax : DInt := 30; // Default: 1.100.000
END_VAR
BEGIN
// Ausführung nur im Intervall
#IntCount := #IntCount + #Cycletime;
IF #IntCount >= #Intervall THEN
#IntCount := 0;
REGION Eingänge lesen
"TCP_DATA_Rd_Variant"(IN := #In_0,
Int0 => #Val[1, 0],
Int1 => #Val[1, 1],
Init := #Init[1],
Type := #Type[1]);
"TCP_DATA_Rd_Variant"(IN := #In_1,
Int0 => #Val[2, 0],
Int1 => #Val[2, 1],
Init := #Init[2],
Type := #Type[2]);
END_REGION
REGION Initialisierung
#ElSize := 3;
#ChNeed := 2;
#ChUsed := 2;
#ElNumb := 10;
#FiFoUsed := 30;
END_REGION
REGION FiFo beschreiben
// Array befüllen
FOR #i := 1 TO #ChMax DO
CASE #Type[#i] OF
0: // Datentyp ungültig, kein Array Eintrag
;
1: // 2-Byte Datentyp ins Array eintragen
#FIFO[#iFF] := #Val[#i, 0];
IF #iFF < #FiFoUsed THEN
#iFF := #iFF + 1;
ELSE
#iFF := 1;
END_IF;
ELSE // 4-Byte Datentyp ins Array eintragen
#FIFO[#iFF] := #Val[#i, 0];
IF #iFF < #FiFoUsed THEN
#iFF := #iFF + 1;
ELSE
#iFF := 1;
END_IF;
#FIFO[#iFF] := #Val[#i, 1];
IF #iFF < #FiFoUsed THEN
#iFF := #iFF + 1;
ELSE
#iFF := 1;
END_IF;
END_CASE;
END_FOR;
// Write Pointer setzen
IF #PtrW < (#FiFoUsed / #ElSize) THEN
#PtrW := #PtrW + 1;
ELSE
#PtrW := 1;
END_IF;
END_REGION
END_IF;
REGION Daten senden
CASE #SSW OF
0: // nicht initialisiert
;
1: // Warten auf Sendefreigabe
#SndCount := #SndCount + #Cycletime;
IF NOT #TCP_Ctrl.State.Snd_Lock AND #SndCount >= #Snd_Intervall THEN
// Sendebaustein reservieren
#TCP_Ctrl.State.Snd_Lock := TRUE;
// Header schreiben
#Snd_HeaderSize := 8;
// Datenlänge bestimmen
IF #PtrW < #PtrR THEN
#Snd_ElNb := #PtrW - #PtrR + #ElNumb;
ELSE
#Snd_ElNb := #PtrW - #PtrR;
END_IF;
// Datenlänge limitieren
#Snd_ElNbMax := DINT_TO_INT(("Snd_Buffer_Max" - INT_TO_DINT(#Snd_HeaderSize)) / #ElSize);
IF #Snd_ElNb > #Snd_ElNbMax THEN
#Snd_EltoMuch := TRUE;
#Snd_ElNb := #Snd_ElNbMax;
ELSE
#Snd_EltoMuch := FALSE;
END_IF;
// Daten schreiben
// Kopierbefehl aufteilen wenn FiFo-Grenze überschritten wird
IF #Test.Active THEN
#Snd_PtrREndOld := #PtrR - 1;
IF #Snd_PtrREndOld + #Snd_ElNb > #ElNumb THEN
MOVE_BLK(IN := #FIFO[(#ElSize * #Snd_PtrREndOld) + 1],
COUNT := INT_TO_ULINT(#ElSize * (#ElNumb - #Snd_PtrREndOld)),
OUT => #Test.Buffer[#Snd_HeaderSize + 1]);
MOVE_BLK(IN := #FIFO[1],
COUNT := INT_TO_ULINT(#ElSize * (#Snd_PtrREndOld + #Snd_ElNb - #ElNumb)),
OUT => #Test.Buffer[#Snd_HeaderSize + 1 + (#ElSize * (#ElNumb - #Snd_PtrREndOld))]);
ELSE
MOVE_BLK(IN := #FIFO[(#ElSize * #Snd_PtrREndOld) + 1],
COUNT := INT_TO_ULINT(#ElSize * #Snd_ElNb),
OUT => #Test.Buffer[#Snd_HeaderSize + 1]);
END_IF;
ELSE
#Snd_PtrREndOld := #PtrR - 1;
IF #Snd_PtrREndOld + #Snd_ElNb > #ElNumb THEN
MOVE_BLK(IN := #FIFO[(#ElSize * #Snd_PtrREndOld) + 1],
COUNT := INT_TO_ULINT(#ElSize * (#ElNumb - #Snd_PtrREndOld)),
OUT => #TCP_Ctrl.Snd_Buffer[#Snd_HeaderSize + 1]);
MOVE_BLK(IN := #FIFO[1],
COUNT := INT_TO_ULINT(#ElSize * (#Snd_PtrREndOld + #Snd_ElNb - #ElNumb)),
OUT => #TCP_Ctrl.Snd_Buffer[#Snd_HeaderSize + 1 + (#ElSize * (#ElNumb - #Snd_PtrREndOld))]);
ELSE
MOVE_BLK(IN := #FIFO[(#ElSize * #Snd_PtrREndOld) + 1],
COUNT := INT_TO_ULINT(#ElSize * #Snd_ElNb),
OUT => #TCP_Ctrl.Snd_Buffer[#Snd_HeaderSize + 1]);
END_IF;
END_IF;
// Sendebefehl absetzen
#TCP_Ctrl.State.Snd_Request := TRUE;
// ReadPointer setzen, Sendebefehle im nächsten Zyklus nachholen, wenn Puffer zu klein
IF #Snd_EltoMuch THEN
#PtrR:=#PtrR+#Snd_ElNb;
ELSE
#PtrR := #PtrW;
END_IF;
#TCP_Ctrl.Snd_Buffer[3] := #PtrR;
#SndCount := 0;
#SSW := 2;
END_IF;
2: // Warten auf Senden beendet
IF NOT #TCP_Ctrl.State.Snd_Lock AND NOT #TCP_Ctrl.State.Snd_Request THEN
#SSW := 1;
END_IF;
ELSE
#SSW := 1;
END_CASE;
END_REGION
END_FUNCTION_BLOCK
Diese, wie auch andere solcher Angaben, sollten immer im richtigen Kontext betrachtet werden.... Trotzdem gibt Siemens an, dass der Zugriff auf einen optimierten DB schneller ist ...
Mal unabhängig davon ... was hält sich davon ab, es zu probieren um Gewissheit zu bekommen ...
Larry
Mal unabhängig davon ... was hält sich davon ab, es zu probieren um Gewissheit zu bekommen ...
Larry
Wir verwenden essentielle Cookies, damit diese Website funktioniert, und optionale Cookies, um den Komfort bei der Nutzung zu verbessern.
Siehe weitere Informationen und konfiguriere deine Einstellungen