Ringpuffer in TwinCAT 3

EffEff

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

ich muss nach vielen Jahren wieder eine SPS programmieren (sonst nutze ich eher LabView, Matlab).
Meine Aufgabe besteht darin, Daten in einen RingPuffer zu schreiben und zyklisch in eine CSV zu schreiben.

Probleme habe ich vorallem bei den RingPuffer. Probiert habe ich FB_MemRingBuffer und FB_MemRingBufferEx.
Mit beiden Funktionen kann ich in einen Puffer speichern und auch die wieder (teilweise) auslesen.
Was ich aber nicht verstehe ist folgendes:

1. Die beiden Funktionsblöcke funktionieren nicht als Ringpuffer, d.h. wenn die Größe des Puffers überschritten ist, schreibt es nicht am Anfang weiter (überschreibt somit nicht die ältesten Werte).
2. Ich erstelle meinen Puffer: ARRAY[1..10] OF INT; Danach schreibe ich 10 Integer Werte rein (1..10) --> im Array steht jetzt [2,0,1,2,0,2,2,0,3,0]; Die Funktion gibt einen Fehler zurück und wenn ich die Werte beginnend beim ältesten auslese, erhalt ich nur 3 Werte;

Beides verstehe ich nicht. In der Dokumentation steht auch nichts.

Hat jemand von euch Erfahrung damit? Sicher könnte ich den Puffer deutlich vergrößern, aber ist das sinnvoll?

Vielen Dank für Eure Hilfe.
EffEff
 
Zur ersten Frage. Hast du dir das Beckhoff Beispiel im Infosys angesehen? Da wird erklärt wie du es bei vollem Puffer erreichst, dass neue Daten durch alte ersetzt werden.

Zur zweiten Frage, zeig deinen Quelltext bitte. Dies macht die Fehlersuche einfacher für uns ;)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ja, habe es z.B. mit dem Beispiel entsprechend deinem Link ausprobiert (ohne Structure-Element, einfach Integer zum speichern). bOverwrite ist auf TRUE gesetzt. Macht es aber trotzdem nicht
Hier der Code:
Globale Variable:
Code:
VAR_GLOBAL CONSTANT
    MAX_BUFFER_SIZE: INT := 10;
END_VAR

MAIN:
Code:
PROGRAM MAIN
VAR
    fbFifo         : FB_DataSetFifo := ( bOverwrite := TRUE );
    newEntry    : INT := 0;
    oldEntry    : INT := 0;
    aOut        : ARRAY [1..GVL.MAX_BUFFER_SIZE] OF INT;
    bSuccess    : BOOL;
    nCount        : UDINT;
    nLoad        : UDINT;
    bReset         : BOOL := TRUE;
    bAdd         : BOOL := TRUE;
    bGet        : BOOL := TRUE;
    bRemove        : BOOL := TRUE;
    i: INT;
END_VAR
________________________________________________________________________
IF bReset THEN
    bReset := FALSE;
    fbFifo.A_Reset(    in := newEntry, bOk=>bSuccess, nCount=> nCount, nLoad => nLoad );
END_IF

IF bAdd THEN
    bAdd := FALSE;
    FOR i := 1 TO GVL.MAX_BUFFER_SIZE DO
    newEntry := newEntry + 1;
    fbFifo.A_Add(    in := newEntry, bOk=>bSuccess, nCount=> nCount, nLoad => nLoad );
    END_FOR
END_IF

IF bGet THEN
    bGet := FALSE;
    fbFifo.A_Get( out => oldEntry, bOk => bSuccess, nCount => nCount, nLoad => nLoad );
END_IF

IF bRemove THEN
    bRemove:= FALSE;
    FOR i := 1 TO GVL.MAX_BUFFER_SIZE DO
        fbFifo.A_Remove( out => oldEntry, bOk => bSuccess, nCount => nCount, nLoad => nLoad );
        aOut[i] := oldEntry;
    END_FOR
END_IF

FB_DataSetFifo(FB):
Code:
FUNCTION_BLOCK FB_DataSetFifo
VAR_INPUT
    bOverwrite    : BOOL;
    in             : INT;
END_VAR
VAR_OUTPUT
    bOk            : BOOL;
    nCount        : UDINT;
    nLoad        : UDINT;
    out            : INT;
END_VAR
VAR
    arrBuffer     : ARRAY[1..GVL.MAX_BUFFER_SIZE] OF INT; // Buffer memory used by FB_MemRingBuffer function block
    fbBuffer    : FB_MemRingBuffer;
END_VAR
________________________________________________________________________
;

FB_DataSetFifo - A_Add(Action):
Code:
fbBuffer.A_AddTail( pWrite:= ADR( in ),
                    cbWrite:= SIZEOF( in ),
                    pBuffer:= ADR( arrBuffer ),
                    cbBuffer:= SIZEOF( arrBuffer ),
                    bOk=> bOk,
                    nCount => nCount );


IF NOT bOk THEN (* overflow ? *)
    IF bOverwrite THEN
        fbBuffer.A_RemoveHead(); (* remove one oldest entry *)
        fbBuffer.A_AddTail( bOk => bOk, nCount => nCount );
    END_IF
END_IF
nLoad := (fbBuffer.cbSize * 100) / GVL.MAX_BUFFER_SIZE;

FB_DataSetFifo (FB) - A_Get (Action):
Code:
fbBuffer.A_GetHead( pRead:= ADR( out ),
                    cbRead:= SIZEOF( out ),
                    pBuffer:= ADR( arrBuffer ),
                    cbBuffer:= SIZEOF( arrBuffer ),
                    bOk=> bOk,
                    nCount => nCount );
nLoad := (fbBuffer.cbSize * 100) / GVL.MAX_BUFFER_SIZE;

FB_DataSetFifo (FB) - A_Remove (Action):
Code:
fbBuffer.A_RemoveHead(     pRead:= ADR( out ),
                        cbRead:= SIZEOF( out ),
                        pBuffer:= ADR( arrBuffer ),
                        cbBuffer:= SIZEOF( arrBuffer ),
                        bOk=> bOk,
                        nCount => nCount );
nLoad := (fbBuffer.cbSize * 100) / GVL.MAX_BUFFER_SIZE;

FB_DataSetFifo (FB) - A_Get (Action):
Code:
MEMSET( ADR( arrBuffer ), 0, SIZEOF( arrBuffer ) ); (* reset (optional) internal buffer *)
fbBuffer.A_Reset(bOk=> bOk,nCount => nCount );
nLoad := (fbBuffer.cbSize * 100) / GVL.MAX_BUFFER_SIZE;

Danke für deine Hilfe!!!
 
Ich habe es mir mal angesehen. Dein Code funktioniert nicht, weil dein MAX_BUFFER_SIZE zu klein ist. Warum dies so ist, erfährst du hier.

cbSize: Liefert die aktuelle Anzahl der belegten Datenbytes im Puffer. Die Anzahl der belegten Datenbytes ist immer größer als die tatsächliche Anzahl der geschriebenen Value-Daten. Jeder Datensatz wird um zusätzliche Informationen ergänzt um ihn später lokalisieren zu können.

Via
Code:
nLoad := (fbBuffer.cbSize * 100) / MAX_BUFFER_SIZE;
wird die Anzahl der Bytes ermittelt für ein Element im Ringpuffer. Auf dein Beispiel bezogen sind dies 6 Bytes pro Wert. Um 10 Elemente zu speichern brauchst du somit

Code:
MAX_BUFFER_SIZE : INT := 60;
 
Danke. Genau das war das Problem beim Speichern.
Als Ringpuffer funktioniert es aber noch nicht, obwohl bOverwrite auf TRUE steht. Mal schauen...
 
Zurück
Oben