TIA LGF_FIFO - zyklisches ein- und auslesen

DCDCDC

Level-3
Beiträge
3.588
Reaktionspunkte
1.038
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

V18 - alle Updates
1212C DCDCDC - aktuellste V18 Firmware
--

Hat schon mal jemand den Fifo Baustein von Siemens aus der Lgf Bib verwendet? Ich würde gerne meine Mqtt Nachrichten zum versenden wegspeichern und dann auch parallel dazu wieder den Fifo leeren.. es sind schon viele Nachrichten, da ich zyklisch über 15s verteilt Messwerte versenden/wegspeichern muss.

Mein Aufbau aktuell:
Aufrufe aller globalen Funktionen findet im FB_Global statt:
Screenshot 2025-01-09 100309.png

In meiner Sequenz mit CASE hab ich dann hier den Schritt der Messung:
Code:
#CONST_STEP_MEAS_START: // Start measurement
            
            // Publish value pressure sensor 01
            "FC_FifoEnqueue"(iMessage := "FC_REAL_TO_STRING"(#tempRng01),
                             iTopic := CONCAT(IN1 := #CONST_PUB_TOPIC_PRE, IN2 := #CONST_PUB_TOPIC_VALUE_01));
            "DB_Fifo".Control.Enqueue := 0;
            // Publish value pressure sensor 02
            "FC_FifoEnqueue"(iMessage := "FC_REAL_TO_STRING"(#tempRng02),
                             iTopic := CONCAT(IN1 := #CONST_PUB_TOPIC_PRE, IN2 := #CONST_PUB_TOPIC_VALUE_02));
            "DB_Fifo".Control.Enqueue := 0;
            // Publish value pressure sensor difference
            "FC_FifoEnqueue"(iMessage := "FC_REAL_TO_STRING"(#tempRngDiff),
                             iTopic := CONCAT(IN1 := #CONST_PUB_TOPIC_PRE, IN2 := #CONST_PUB_TOPIC_VALUE_DIFF));
            "DB_Fifo".Control.Enqueue := 0;
            IF #statTimerMeasurement.Q THEN
                #statMeasurementStart := 0;
                #statMeasurementStop := 1;
                // Publish timestamp measurement stop
                "FC_FifoEnqueue"(iMessage := #iTime,
                                 iTopic := CONCAT(IN1 := #CONST_PUB_TOPIC_PRE, IN2 := #CONST_PUB_TOPIC_TIMESTAMP_STOP));
                "DB_Fifo".Control.Enqueue := 0;
                // Publish measurement start signal
                "FC_FifoEnqueue"(iMessage := "FC_BOOL_TO_STRING"(#statMeasurementStart),
                                 iTopic := CONCAT(IN1 := #CONST_PUB_TOPIC_PRE, IN2 := #CONST_PUB_TOPIC_SIGNAL_START));
                "DB_Fifo".Control.Enqueue := 0;
                // Publish measurement stop signal
                "FC_FifoEnqueue"(iMessage := "FC_BOOL_TO_STRING"(#statMeasurementStop),
                                 iTopic := CONCAT(IN1 := #CONST_PUB_TOPIC_PRE, IN2 := #CONST_PUB_TOPIC_SIGNAL_STOP));
                "DB_Fifo".Control.Enqueue := 0;
                #ioStep := #CONST_STEP_PUMP_FINISHED;
            END_IF;

FC_FifoEnqueue sieht so aus:
Code:
"DB_Fifo".ItemWork.Message := STRING_TO_WSTRING(#iMessage);
"DB_Fifo".ItemWork.Topic := STRING_TO_WSTRING(#iTopic);
"DB_Fifo".Control.Enqueue := 1;

Aus dem Puffer entfernen sieht so aus, im Mqtt Baustein:
Code:
ELSIF NOT "DB_Mqtt".Client.Busy AND NOT "DB_Mqtt".Client.Done AND ("DB_Fifo".Control.ElementCount <> 0) AND NOT ("DB_Fifo".Control.Enqueue) THEN
    "DB_Fifo".Control.Dequeue := 1;
    "DB_Mqtt".Client.ParameterPub.publishMessageData := "DB_Fifo".ItemWork.Message;
    "DB_Mqtt".Client.ParameterPub.publishTopic := "DB_Fifo".ItemWork.Topic;
    "DB_Fifo".Control.Dequeue := 0;
    //nochmal prüfen, ob überhaupt was in der Variable drinsteht..
    IF "DB_Mqtt".Client.ParameterPub.publishMessageData <> "WSTRING_EMPTY" THEN
        //prüfen ob  aktuelle message  <> letzte message
        //IF "MQTT_DATA".mqttDataPublish.publishMessageData <> "MQTT_FIFO".last_send_payload THEN
        "DB_Mqtt".Client.ParameterPub.publishMessage := 1;
        // END_IF;
    END_IF;

Irgendwie will das gar nicht so wie ich wollte gestern nach 17 Uhr.. wenn ich die Bits im Datenbaustein für Einreihen und Entfernen triggere, funktioniert das.. ansonsten nicht.. liegts einfach nur an der mehrfachen Zuweisung der Enqueue und Dequeue Signale?

Ich würde gerne beide Funktionen "parallel" verwenden, da der Arbeitsspeicher der 1212C recht klein ist und ich nicht so viele Nachrichten zwischenspeichern kann.. aktuell sinds 20 Fächer im Puffer.

Danke soweit!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich wäre davon ausgegangen das du bezüglich Lesen und Schreiben das Statusbit des LGF auswerten musst.
Mir war der Baustein zu kompliziert.Es ist auch kein FIFO sondern ein Buffer.Es gibt einen alten s7 Klassibausten den habe abgeschrieben.
Der hat aber am Eingang jeweils einen Schreibimpuls und Leseimpuls.Der Impuls wird intern gebildet.
Schreiben und Lesen wird man wohl gegeneinander verreigeln müssen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Doch der geht.Ich konnte ihn zwar nicht direkt importieren.
Ich habe den programmcode ihn einfach aus der Textquelle kopiert.Die Variablen habe ich händisch angelegt.
Nur die Buffergrenze lies er nicht als Variable zu.
 
Mit welcher TIA Version arbeitest du ?
Ich habe mal was geschrieben um aus der Anwendung beliebig ein oder mehrere Werte als MQTT MSG abzusetzen. Die gehen in einen Ringspeicher und der MQTT Client arbeitet ihn kontinuierlich ab. Am Anfang habe ich auch mit dem LGF_FIFO versucht aber ein FIFO als Ringspeicher hat da schon seine Vorteile.
Dann habe ich keine Anzahl Telegramme im Puffer sondern Byte Telegramme beliebiger Länger. (Len,Data,Len,Data,Len,Data,....)
Enthalten sind auch Standard Funktionen für den Zusammenbau und Konvertierung der verschiedenen Datentypen für das Telegramm.

Der Aufruf um eine MSG abzusetzen sieht zum Beispiel so aus:
1736418323798.png

Wenn du willst, kann ich dir das Projekt mal schicken (Wurde aber leider vor Vollendung auf OPC-UA umgestellt, daher nicht weiter verfolgt), wenn du versprichst ein Feedback zu geben und mich an deinen Ergebnissen teilhaben lässt.

Der zugehörige Programmteil sind so aus:
1736418570777.png

Gruß
Thomas
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Mit welcher TIA Version arbeitest du ?
Ich habe mal was geschrieben um aus der Anwendung beliebig ein oder mehrere Werte als MQTT MSG abzusetzen. Die gehen in einen Ringspeicher und der MQTT Client arbeitet ihn kontinuierlich ab. Am Anfang habe ich auch mit dem LGF_FIFO versucht aber ein FIFO als Ringspeicher hat da schon seine Vorteile.
Dann habe ich keine Anzahl Telegramme im Puffer sondern Byte Telegramme beliebiger Länger. (Len,Data,Len,Data,Len,Data,....)
Enthalten sind auch Standard Funktionen für den Zusammenbau und Konvertierung der verschiedenen Datentypen für das Telegramm.

Der Aufruf um eine MSG abzusetzen sieht zum Beispiel so aus:
Anhang anzeigen 84490

Wenn du willst, kann ich dir das Projekt mal schicken (Wurde aber leider vor Vollendung auf OPC-UA umgestellt, daher nicht weiter verfolgt), wenn du versprichst ein Feedback zu geben und mich an deinen Ergebnissen teilhaben lässt.

Der zugehörige Programmteil sind so aus:
Anhang anzeigen 84491

Gruß
Thomas
Hey hey, ist ein Bestandsprojekt in welches neue Funktionen für ein anderes Produkt integriert werden, weswegen ich beim optimieren versuche so viel möglich zu übernehmen..

Davor war auch schon eine Art Ringspeicher vorhanden.. selbst gebastelt, der aber immer wieder Einträge verschluckt hat, weswegen ich jetzt den Fifo integriere.. da mein Arbeitsspeicher jetzt schon stark an der Grenze ist, versuche so wenig wie möglich an neuen Funktionen zu implementieren.. die 1212C ist da leider sehr begrenzt. Ich kann auch nicht auf die neueste Mqtt Version vom Baustein umstellen, das würde viel zu viel Arbeit nach sich ziehen.

Eine weitere Hürde die ich auch noch sehe ist, dass sich Enqueue und Dequeue das gleiche InOut Item teilen und das nicht separat ausgegeben wird, evtl kann ich das im Baustein anpassen
 
Dann kann ich dir noch ein Projekt anbieten (V16) als Beispiel. bzw. Quelle FC ctrlRingFiFo, der macht genau das, Lesen und schreiben gleichzeitig.
Er arbeitet mit einer ctrlStruktur (Instanzdaten), die du dir in den Buffer DB legen kannst. Kannst du ev. noch abspecken, da es auch eine Visu Schnittstelle hat, um den Fifo in der Visu anzeigen und bearbeiten zu können.

1736422314656.png
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Eine weitere Hürde die ich auch noch sehe ist, dass sich Enqueue und Dequeue das gleiche InOut Item teilen und das nicht separat ausgegeben wird
Ich verwende den LGF_FIFO nicht und kenne ihn nicht genau, doch kann man den nicht beliebig oft im Zyklus aufrufen? Das Einspeichern oder Auslesen eines Items sollten simple Funktionen sein, die sofort nach Aufruf fertig sind. (jedenfalls implementiere ich das bei meinen selbstprogrammierten FIFOs so)
 
Aktueller Stand und evtl auch die Roadblock ist, dass nur die letzten Werte der Cases in den Fifo übernommen werden.

Aufrufreihenfolge
Code:
MAIN (OB1) > FB_Global > FB_Fifo
                         FB_Mqtt
                         FB_Sequence_Mqtt
                         FB_Sequence_Measurement

FB_Fifo
Code:
#ioControl.Enqueue := 0;
#ioEnqDone := 0;
IF (#ioItemEnq <> #statItemEnqOld) AND (NOT #ioControl.Dequeue) AND (#ioControl.Status = "FIFO_STATUS_IDLE") THEN
    #ioControl.Enqueue := 1;
    #statItemEnqOld := #ioItemEnq;
    #ioEnqDone := 1;
END_IF;
...
LGF_FIFO Aufruf steht hier

FB_Sequence_Measurement
Code:
#CONST_STEP_MEAS_START: // Start measurement
       
            // Publish value pressure sensor 01
            IF NOT "DB_FIFO".EnqDone THEN
                "FC_FifoEnq"(iMessage := "FC_REAL_TO_STRING"(#tempRng01),
                             iTopic := CONCAT(IN1 := #CONST_PUB_TOPIC_PRE, IN2 := #CONST_PUB_TOPIC_VALUE_01));
            END_IF;
            // Publish value pressure sensor 02
            IF NOT "DB_FIFO".EnqDone THEN
                "FC_FifoEnq"(iMessage := "FC_REAL_TO_STRING"(#tempRng02),
                             iTopic := CONCAT(IN1 := #CONST_PUB_TOPIC_PRE, IN2 := #CONST_PUB_TOPIC_VALUE_02));
            END_IF;
            // Publish value pressure sensor difference
            IF NOT "DB_FIFO".EnqDone THEN
                "FC_FifoEnq"(iMessage := "FC_REAL_TO_STRING"(#tempRngDiff),
                             iTopic := CONCAT(IN1 := #CONST_PUB_TOPIC_PRE, IN2 := #CONST_PUB_TOPIC_VALUE_DIFF));
            END_IF;
            IF #statTimerMeasurement.Q THEN
                #statMeasurementStart := 0;
                #statMeasurementStop := 1;
                // Publish timestamp measurement stop
                IF NOT "DB_FIFO".EnqDone THEN
                    "FC_FifoEnq"(iMessage := #iTime,
                                 iTopic := CONCAT(IN1 := #CONST_PUB_TOPIC_PRE, IN2 := #CONST_PUB_TOPIC_TIMESTAMP_STOP));
                END_IF;
                // Publish measurement start signal
                IF NOT "DB_FIFO".EnqDone THEN
                    "FC_FifoEnq"(iMessage := "FC_BOOL_TO_STRING"(#statMeasurementStart),
                                 iTopic := CONCAT(IN1 := #CONST_PUB_TOPIC_PRE, IN2 := #CONST_PUB_TOPIC_SIGNAL_START));
                END_IF;
                // Publish measurement stop signal
                IF NOT "DB_FIFO".EnqDone THEN
                    "FC_FifoEnq"(iMessage := "FC_BOOL_TO_STRING"(#statMeasurementStop),
                                 iTopic := CONCAT(IN1 := #CONST_PUB_TOPIC_PRE, IN2 := #CONST_PUB_TOPIC_SIGNAL_STOP));
                END_IF;
                #ioStep := #CONST_STEP_PUMP_FINISHED;

FC_FifoEnq
Code:
"DB_FIFO".ItemEnq.Message := STRING_TO_WSTRING(#iMessage);
"DB_FIFO".ItemEnq.Topic := STRING_TO_WSTRING(#iTopic);

FB_Sequence_Mqtt
Code:
"DB_FIFO".Control.Dequeue := 0;
IF NOT "DB_Mqtt".Client.Busy AND "DB_Mqtt".Client.Done THEN
 
    "DB_Mqtt".Client.ParameterPub.publishMessage := 0;
    "DB_Mqtt".Client.ParameterPub.publishMessageData := "WSTRING_EMPTY";
    "DB_Mqtt".Client.ParameterPub.publishTopic := "WSTRING_EMPTY";
 
ELSIF NOT "DB_Mqtt".Client.Busy AND NOT "DB_Mqtt".Client.Done AND ("DB_FIFO".Control.ElementCount <> 0) AND (NOT "DB_FIFO".Control.Enqueue) AND ("DB_FIFO".Control.Status = "FIFO_STATUS_IDLE")THEN
    "DB_FIFO".Control.Dequeue := 1;
    IF "DB_FIFO".ItemDeq <> #statItemDeqOld THEN
        #statItemDeqOld := "DB_FIFO".ItemDeq;
        "DB_Mqtt".Client.ParameterPub.publishMessageData := #statItemDeqOld.Message;
        "DB_Mqtt".Client.ParameterPub.publishTopic := #statItemDeqOld.Topic;
    END_IF;
    IF "DB_Mqtt".Client.ParameterPub.publishMessageData <> "WSTRING_EMPTY" THEN
        "DB_Mqtt".Client.ParameterPub.publishMessage := 1;
    END_IF;
END_IF;

Wahrscheinlich kommt er nicht hinterher den Buffer zu entleeren während er gefüllt werden sollte
 
Zuletzt bearbeitet:
Zurück
Oben