Schnelles Loggen mit Datenpuffer
Um Daten auch im Millisekunden Takt in eine Datenbank zu loggen, müssen diese zuvor zusammengefasst werden, bevor sie über den TwinCAT Database Server zur Datenbank übertragen werden. Diese sogenannten Datenpuffer können in ihrer Größe je nach Anforderung variieren. In dem Beispiel werden 100 Datensamples in einem Puffer zusammengefasst, bevor sie mit dem TwinCAT Database Server übertragen werden. Um keine Lücken durch den Schreibvorgang zu erhalten, müssen mehrere Puffer angelegt werden, in denen die Datensamples zusammengefasst werden. In dem Beispiel sind insgesamt 20 Puffer mit Hilfe eines 2-Dimensionalen Arrays angelegt.
Datensample
Definition:
TYPE ST_Data :
STRUCT
Timestamp : LINT;
fAM : LREAL;
fPeak : LREAL;
fPulse : LREAL;
fSawtooth : LREAL;
fSine : LREAL;
fSquare : LREAL;
fStairs : LREAL;
fTriangular : LREAL;
END_STRUCT
END_TYPE
Jeden Zyklus wird ein Element des Datenpuffers befüllt. Im Beispiel geschieht dies im 10ms Takt. Somit enthält ein Puffer Daten eines Zeitraums von 1s. Ist ein Puffer mit 100 Elementen gefüllt, wird durch ein weiteres Array signalisiert, dass die 100 Elemente nun mit dem Baustein FB_PLCDBCmdEvt übertragen werden können. Hierfür kann der gesamte Puffer dem Baustein übergeben werden. Jedes einzelne Element wird dann vom TwinCAT Database Server zur Datenbank übertragen. Dieses Beispiel kann auch mit anderen Bausteinen umgesetzt werden. Beachten Sie dabei, dass nicht alle Funktionsbausteine Arrays unterstützen.
Auszug aus dem Baustein FB_Record_tbl_Signals
( „State-Machine“ => State: Recording)
…
2://Recording
bRecording := TRUE;
//Fill buffer
stData[nWriteBufferIndex, nWriteIndex].Timestamp := nTimestamp;
stData[nWriteBufferIndex, nWriteIndex].fAM := fAM;
stData[nWriteBufferIndex, nWriteIndex].fPeak := fPeak;
stData[nWriteBufferIndex, nWriteIndex].fPulse := fPulse;
stData[nWriteBufferIndex, nWriteIndex].fSawtooth := fSawtooth;
stData[nWriteBufferIndex, nWriteIndex].fSine := fSine;
stData[nWriteBufferIndex, nWriteIndex].fSquare := fSquare;
stData[nWriteBufferIndex, nWriteIndex].fStairs := fStairs;
stData[nWriteBufferIndex, nWriteIndex].fTriangular := fTriangular;
//Set buffer index
nWriteIndex := nWriteIndex + 1;
IF nWriteIndex = 100 THEN
nWriteIndex := 0;
aWriteSQL[nWriteBufferIndex]:= TRUE;
nWriteBufferIndex := nWriteBufferIndex + 1;
IF nWriteBufferIndex = 20 THEN
nWriteBufferIndex := 0;
END_IF
IF aWriteSQL[nWriteBufferIndex] THEN
nState := 255;
RETURN;
END_IF
END_IF
//Write buffer element (100 samples) to database
IF aWriteSQL[nSQLIndex] THEN
IF fbPLCDBCmd.Execute(nDBID, ADR(sCmd), SIZEOF(sCmd),
ADR(stData[nSQLIndex,0]), SIZEOF(stData[nSQLIndex,0]) * 100,
ADR(aPara), SIZEOF(aPara)) THEN
IF fbPLCDBCmd.bError THEN
nState := 255;
ELSE
nRecords := nRecords + 100;
aWriteSQL[nSQLIndex] := FALSE;
nSQLIndex := nSQLIndex + 1;
IF nSQLIndex = 20 THEN
nSQLIndex := 0;
END_IF
IF NOT bRecord THEN
bRecording := FALSE;
nState := 0;
END_IF
END_IF
END_IF
END_IF
….
Anhang:
In diesem Best Practise wird mit Hilfe eines Funktionsgenerator Bausteins verschiedene Signale erzeugt, die in eine Datenbank geloggt werden können. Die Syntax des INSERT Kommandos ist allgemeingültig, wurde aber im speziellen mit einer MS SQL Datenbank getestet. Das unten angefügte ZIP enthält den kompletten Programmcode in Form eines Tnzip.
Download:TF6420_BestPractise_Buffer.zip