Messwerte in Array fortlaufend schreiben

stehmi

Level-2
Beiträge
13
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

ich habe bereits diverse Foren durchsucht aber noch nicht das richtige gefunden.
Ich muss dazu sagen, das ich blutiger Anfänger bin was Codesys angeht.

Ich habe folgendes Problem bzw. Aufgabe,

Ich möchte Messwerte eines Analogen und bereits normierten Sensors fortlaufend in ein Array schreiben und aus diesen dann einen Mittelwert berechnen.
Mit dem Mittelwert muss ich mich noch einlesen, habe Meridian, gleitender Mittelwert, Bubblesort und Quicksort gefunden.
Aber zunächst geht es mir erst mal darum ein Array mit Messwerten zu füllen.

Könnt Ihr mir dazu einen Tipp geben, wie ich das angehen kann??
 
Hi,
ich hatte mir vor einiger Zeit einen solchen Baustein geschrieben, weil ich genau so eine Lösung suchte...
Anbei das Beispiel

Viel Erfolg
Shrimps
Code:
FUNCTION_BLOCK _fbAVG_INT16
VAR_INPUT
    iSignal    : INT;    (* Eingangswert *)
    tZeit    : TIME := t#8s;    (* Abtastzeit gesamt *)
END_VAR
VAR_OUTPUT
    iAVG    : INT;    (* Der Mittelwert *)
END_VAR
VAR
    Timer     : TON;    (* Timer *)
    tTakt    : TIME;    (* 1/16 von tZeit *);
    iData     : ARRAY [0..15] OF INT;    (* Die Daten *)
    Summe    : DINT;    (* Summenzaehler *)
    Index    : INT;    (* Index für Array *)
    init    : BOOL := TRUE;    (* Start *)
END_VAR
(* FB ermittelt einen gleitenden Mittelwert aus *)
(* 16 Integerwerten welche in einem vorgebbaren *)
(* Zeitinterval als FILO gespeichert werden *)
IF init THEN
    FOR Index := 0 TO 15 DO
        iData[Index] := iSignal;
    END_FOR
    init := FALSE;
    iAVG := iSignal;
END_IF

tTakt := tZeit / 16;

Timer(IN := NOT Timer.Q, PT := tTakt);

IF Timer.Q THEN
    Summe := 0;
    FOR Index := 15 TO 1 BY -1  DO
        iData[Index] := iData[Index - 1];
        Summe := Summe + iData[Index];
    END_FOR
    iData[0] := iSignal;
    Summe := Summe + iSignal;
    iAVG := DINT_TO_INT(summe / 16);
END_IF

END_FUNCTION_BLOCK
 
Hey Shrimps,

mir ist bei deinem Code-Ausschnitt aufgefallen, dass du einzelne Zeilen auskommentierst.
Hat das einen gesonderten Sinn?
Code:
(* FB ermittelt einen gleitenden Mittelwert aus *)
(* 16 Integerwerten welche in einem vorgebbaren *)
(* Zeitinterval als FILO gespeichert werden *)

Wieso nicht so:

Code:
(* FB ermittelt einen gleitenden Mittelwert aus
16 Integerwerten welche in einem vorgebbaren
Zeitinterval als FILO gespeichert werden *)

Mich interessiert nur, warum du das so machst, vielleicht wusstest du auch nicht, dass man nicht jede einzelne Zeile auskommentieren musst und
du kannst dir so etwas Zeit sparen :D

Ansonsten danke für den Ansatz, ist für mich eventuell auch brauchbar!

Gruß,
Flo
 
getakteter Ringpuffer

Könnt Ihr mir bei meinem neuen Problem auch helfen.

Ich möchte alle 0,5 s einen Wert in ein Array schreiben [0..30] und den Index um eins erhöhen.
Wenn Index 30 erreicht hat, den Inhalt dieses Arrays in ein anderes Array speichern, danach den Index auf 0 und wieder von vorne beginnen.

Könnt Ihr mir da auch mit einem Beispiel helfen bitte.
Ich kann trotz Internet nichts passendes finden
 
Hallo stehmi,
das Internet erledigt auch nicht meine Arbeit :cool:

Wenn ich erfahren dürfte warum du es genauso haben willst, kann ich es schnell runtertippen aber ggf. ist eine Lösung ganz anders wenn man die Aufgabe kennt !

Ansonsten zum lernen:
--- pseudocode---
Gleicher Kram wie von mir, nur wenn array voll dann via memcopy in anderes identisch deklariertes Array und ab von vorne
--------

Viel Spaß
Shrimps
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo schrimps
ich suche ja nicht nach einer kompletten Lösung obwohl das natürlich schön wäre aber finde auch nichts was mich bis jetzt weiter gebracht hat.
Meine Aufgabe ist eigentlich, das ich Wie zu beginn schon geschrieben von einem Sensor aufzeichnen möchte.
Das mit dem ARRAY und Mittelwert habe ich verstanden, nun möchte ich aber auch noch bestimmen können, in welchem Takt er die Werte vom Sensor
in das ARRAY schreibt.
Ich möchte im Prinzip alle x Sekunden einen Wert in das ARRAY_1 schreiben.
Wenn der Index bzw. wenn ich 30 Werte erreicht habe möchte ich diese Werte in ARRAY_1 in ein anderes ARRAY_2 übergeben und ARRAY_1 wider von vorne beginnen.
Ich hoffe ich konnte dir mein Problem schildern.
 
Zuletzt bearbeitet:
So,
habe ein Beispiel fertig.
Habe möglichst viel Kommentiert !
Schau mal, ob das so deinen Wünschen entspricht.
Den Aufruf meines FB kannst du ja logischerweise auch in FUP machen, ist dir das Klar ?
LG
Shrimps
PS: Solltest du den Memcpy nicht finden, so muss alles durch eine For-Schleife erledigt weden...(LIBs suchen...)

@KingHelmer: Das komische Einrücken hat mich immer beim übertragen in andere Systeme gestört, im TwincatEditor sieht es perfekt aus...

Code:
FUNCTION_BLOCK _fbDumpArray
VAR_INPUT
    iWert        : INT;    (* Der zu speichernde Int *)
    tTaktzeit        : TIME;    (* Die gewünschte Taktzeit *)
END_VAR
VAR_OUTPUT
    aData         : ARRAY [0..29] OF INT;    (* Das gesicherte Ergebniss *)
    bReady        : BOOL;                    (* Wir haben einen Zyklus fertig *)
END_VAR
VAR
    bInit             : BOOL     := TRUE;        (* Immer wieder sauber neustart *)
    aData1         : ARRAY [0..29] OF INT;    (* Der Interne Puffer *)
    aDataInit     : ARRAY [0..29] OF INT := 30(0);    (* Faulheit für Init *)
    Timer        : TON;                    (* Unser Takt *)
    Counter        : INT;                    (* Zaehler *)
END_VAR

IF bInit THEN        (* Immer wenn eine Zyklus fertig ist oder Neustart *)
    (* Das Nullen wäre auch it eine FOR-Schleife gegangen, egal entweder Zeit oder Speicher*)
    MEMCPY(ADR(aData1), ADR(aDataInit), 30*2) ;    (* Internes Array mit 0 vorbelegen *)
    Counter     := 0;            (* Zaehler reset *)
    bInit         := FALSE;    (* Init hat fertig *)
    bReady     := FALSE;    (* Zyklus ist nicht fertig *)
END_IF

Timer(IN := NOT Timer.Q, PT := tTaktzeit);    (* Takt starten *)

IF Timer.Q THEN        (* Zeit erreicht ? *)

    aData1[Counter]     := iWert;            (* Wert übernehmen *)
    Counter             := Counter + 1;        (* Zaehler erhoehen *)

    IF Counter   > 29 THEN                (* Zaehler Fertig ? *)
        MEMCPY(ADR(aData), ADR(aData1), 30*2) ;    (* Daten speichern *)
        bReady    := TRUE;                (* Wir haben einen Zyklus ! *)
        bInit         := TRUE;                (* Sauber machen, siehe init *)
    END_IF

END_IF
Hier der Aufruf
Code:
PROGRAM MAIN
VAR
    Wert        : INT;
    Zufall        : DRAND;
    fbDumpArray    : _fbDumpArray;
    aMydata        : ARRAY [0..29] OF INT;
END_VAR

Zufall(SEED := 0);
Wert := REAL_TO_INT(Zufall.Num * 100);

fbDumpArray(iWert := Wert, tTaktZeit := t#250ms);

IF fbDumpArray.bReady THEN
    aMydata := fbDumpArray.aData;
END_IF
 
Zuletzt bearbeitet:
Hallo schrimps,
hatte Gestern mal Zeit deinen Funktionsblock zu testen, aber leider unterstützt meine Steuerung Schneider-Electric M258 die MEMCPY Funktion nicht.
Eine andre Frage, kennst Du Dich mit Pointern aus?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi stehmi,
ich bau dir ne Version ohne memcpy...

Pointer kenne ich, wenn ich diese benötige, weiss ich wie ich sie verwende, aber aktiv mache ich mit denen nichts.
Mir hatte am Anfang der SPS-Kontakte mal jemand gesagt, das Pointer eine recht kritische Sache ist...

Was für ein Problem hast du denn ?

LG
Shrimps
 
Hi stehmi,
ich bau dir ne Version ohne memcpy...

Pointer kenne ich, wenn ich diese benötige, weiss ich wie ich sie verwende, aber aktiv mache ich mit denen nichts.
Mir hatte am Anfang der SPS-Kontakte mal jemand gesagt, das Pointer eine recht kritische Sache ist...

Was für ein Problem hast du denn ?

LG
Shrimps
 
Wie versprochen, hier die Version ohne memcpy:

LG
Shrimps

Code:
FUNCTION_BLOCK _fbDumpArray
VAR_INPUT
    iWert        : INT;    (* Der zu speichernde Int *)
    tTaktzeit        : TIME;    (* Die gewünschte Taktzeit *)
END_VAR
VAR_OUTPUT
    aData         : ARRAY [0..29] OF INT;    (* Das gesicherte Ergebniss *)
    bReady        : BOOL;                    (* Wir haben einen Zyklus fertig *)
END_VAR
VAR
    bInit             : BOOL     := TRUE;        (* Immer wieder sauber neustart *)
    aData1         : ARRAY [0..29] OF INT;    (* Der Interne Puffer *)
(*    aDataInit     : ARRAY [0..29] OF INT := 30(0);    (* Faulheit für Init *) *)
    Timer        : TON;                    (* Unser Takt *)
    Counter        : INT;                    (* Zaehler *)
    Index        : USINT;                    (* index *)
END_VAR
IF bInit THEN        (* Immer wenn eine Zyklus fertig ist oder Neustart *)
    (* Das Nullen wäre auch it eine FOR-Schleife gegangen, egal entweder Zeit oder Speicher*)
    (* MEMCPY(ADR(aData1), ADR(aDataInit), 30*2) ;    (* Internes Array mit 0 vorbelegen *) *)
    FOR Index := 0 TO 29 DO
        aData1[Index] := 0;
    END_FOR
    Counter     := 0;            (* Zaehler reset *)
    bInit         := FALSE;    (* Init hat fertig *)
    bReady     := FALSE;    (* Zyklus ist nicht fertig *)
END_IF

Timer(IN := NOT Timer.Q, PT := tTaktzeit);    (* Takt starten *)

IF Timer.Q THEN        (* Zeit erreicht ? *)

    aData1[Counter]     := iWert;            (* Wert übernehmen *)
    Counter             := Counter + 1;        (* Zaehler erhoehen *)

    IF Counter   > 29 THEN                (* Zaehler Fertig ? *)
        (* MEMCPY(ADR(aData), ADR(aData1), 30*2) ;    (* Daten speichern *) *)
        FOR Index := 0 TO 29 DO
            aData[Index] := aData1[Index];
        END_FOR

        bReady    := TRUE;                (* Wir haben einen Zyklus ! *)
        bInit         := TRUE;                (* Sauber machen, siehe init *)
    END_IF

END_IF

PROGRAM MAIN
VAR
    Wert        : INT;
    Zufall        : DRAND;
    fbDumpArray    : _fbDumpArray;
    aMydata        : ARRAY [0..29] OF INT;
END_VAR

Zufall(SEED := 0);
Wert := REAL_TO_INT(Zufall.Num * 100);

fbDumpArray(iWert := Wert, tTaktZeit := t#250ms);

IF fbDumpArray.bReady THEN
    aMydata := fbDumpArray.aData;
END_IF
 
Zurück
Oben