Zeitverzögerte Erfassung von Messwerten

SPS_Jack

Level-1
Beiträge
11
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich möchte gerne 5 Messwerte pro Sekunde in der SPS Puffern und nach einer Sekunde auf die interne SD-Karte schreiben lassen.

Hierzu habe ich folgenden Ansatz gewählt:
-Zunächst wird die Systemzeit der SPS mittels "SysRtcGetTime( )"ausgelesen und davon die Sekunde extrahiert. Die volle Sekunde liefert mir den ersten Wert des Puffers.
- Die weiteren Werte werden mittels einer EVEN Funktion gewonnen. Diese liefert mir bei einer "geraden Sekunde" ein TRUE und bei einer "ungeraden Sekunde" ein FALSE.
- EVEN bzw. NOT(EVEN) liefert mir das Eingangssignal von insgesamt 8 Einschaltverzögerungen.
- Die Ausgänge der Einschaltverzögerungen liefern mir Impulse für die weiteren Werte des Puffers (200ms, 400ms, 600ms, 800ms)

hierzu der Codeausschnitt des Programmes:
Code:
Timer_200ms(IN:=EVEN, PT:= t#200ms, Q=>Takt1 , ET=> );
Timer_400ms(IN:=EVEN, PT:=t#400ms , Q=>Takt2 , ET=> );
Timer_600ms(IN:=EVEN, PT:= t#600ms, Q=>Takt3 , ET=> );
Timer_800ms(IN:=EVEN, PT:=t#800ms , Q=>Takt4 , ET=> );

Timer2_200ms(IN:=NOT(EVEN) , PT:= t#200ms, Q=>Takt1_2 , ET=> );
Timer2_400ms(IN:=NOT(EVEN) , PT:=t#400ms , Q=>Takt2_2 , ET=> );
Timer2_600ms(IN:=NOT(EVEN) , PT:= t#600ms, Q=>Takt3_2 , ET=> );
Timer2_800ms(IN:=NOT(EVEN) , PT:=t#800ms , Q=>Takt4_2, ET=> );

Flanke_Takt1(CLK:=Takt1 OR Takt1_2 , Q=> );
Flanke_Takt2(CLK:=Takt2 OR Takt2_2, Q=> );
Flanke_Takt3(CLK:=Takt3 OR Takt3_2, Q=> );
Flanke_Takt4(CLK:=Takt4 OR Takt4_2, Q=> );


Gibt es eine Möglichkeit diese zeitlich verzögerten Taktsignale einfacher zu generieren?
 
Ich möchte gerne 5 Messwerte pro Sekunde in der SPS Puffern und nach einer Sekunde auf die interne SD-Karte schreiben lassen.
...

Gibt es eine Möglichkeit diese zeitlich verzögerten Taktsignale einfacher zu generieren?
Ich hätte über die Verwendung des 5Hz-Taktmerkers nachgedacht und mit jeder seiner P-Flanken in der SPS und jeder 5. (oder der 1Hz-Taktmerker-P-Flanke) auf die Karte gespeichert.

BTW @all,
hab' ich mir noch nie Gedanken drüber gemacht oder gar getestet: Kommen die 1Hz- und die 5. 5Hz-Flanke eigentlich synchron?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich würde alles aus nur einem einzigen Uhrzeit-unabhängigen und Zykluszeit-unabhängigen Taktsignal ableiten (z.B. aus einem 5Hz/200ms-Taktmerker) und einen Zähler oder ein Bit-Schieberegister ansteuern. Macht nur ca. 1 Taktflanke, 1 Zähler/Schieber, 2 bis 6 Decodier-Verknüpfungen. Eine Taktverarbeitung in einem Weckalarm mit festem Zeitraster ist eventuell sinnvoll.

Sind das 5 verschiedene Messwerte oder soll immer der gleiche Messwert alle 200ms aufgezeichnet werden? Auch bei verschiedenen Messwerten würde ich alle 5 beim selben Takt aufzeichnen (Konsistenz zueinander, gleiche Zeitstempel).

Jede Sekunde auf die SD-Karte schreiben finde ich nicht gut. Wieviele Schreibzyklen verträgt die SD-Karte?
Ich würde 5...15 Minuten in einem remanenz-gesicherten Speicherbereich puffern und erst danach schreiben. Dann hat man auch die Chance, die SD-Karte im laufenden Betrieb zu wechseln, falls das die verwendete CPU zuläßt.

Kann das Schreiben auf die SD-Karte länger als 200ms dauern? Dann braucht man zur Konsistenzsicherung zwei Puffer (2 abwechselnd genutzte Aufzeichnungspuffer, oder einen Schreibzeit-Überbrückungs-Zwischenpuffer, oder eine Schnappschuss-Schreibpuffer-Kopie).

Harald
 
Hast Du den Vorschlag von Chräshe ausprobiert?
Ich meine, der war bestechend einfach, was das Timing betrifft.

Bezüglich des häufigen Schreibzugriffs auf die SD hatte ich meine Meinung gesagt.
 
Hi,

ich würde das ganze so lösen:
Code:
FUNCTION_BLOCK Datenlog
VAR_INPUT
    Messwert:REAL;                (*Eingang für Messwert ... keine Funktion*)
    LOG_ms:INT:=100;            (*Logvorgänge alle xxx millisekunden*)
    ZYKL_ZEIT:INT;                (*Zykluszeit für Fehlererkennung*)
END_VAR
VAR_OUTPUT
    LOG_ERROR:DINT;            (*Fehlerzähler Zykluszeit >Logzeit*)
END_VAR
VAR
    POS_TAKT:BOOL;            (*Positive Flanke Takt*)
    POS_TAKT_ALT:BOOL;        (*Merker Takt*)
    SEK_ALT:INT;                    (*Merker für Sekunde*)
    ANZ_LOG_sek:INT;            (*Anzahl für Logvorgänge je Sekunde*)

    Zeit:TIME;                        (*Zeit auslesen*)
    CT:INT;                        (*Vielfachen Zähler*)
    Ms_INT:INT;                    (*Millisekunde im Integer Format*)
    sek_INT: INT;                    (*Sekunde im Integer Format*)
    MS: ARRAY [1..10]OF INT ;    (*Array für Millisekundenwerte // nur zum debuggen*)
    sek: ARRAY [1..10]OF INT ;    (*Array für Millisekundenwert // nur zum debuggen*)
    INDEX:INT:=1;                    (*Arrayindex*)
END_VAR

#########################################################################################################
Zeit:=TIME();                                                                                (*SPS Uhrzeit *)
ms_INT:=DWORD_TO_INT(TIME_TO_DWORD(ZEIT) MOD 1000);                        (*millisekunden in Integerformat umwandeln*)
sek_INT:=DWORD_TO_INT(TIME_TO_DWORD(ZEIT) MOD 10000) / 1000;            (*Sekunden in Integer Format umwandeln*)
ANZ_LOG_sek:=1000 / LOG_MS;                                                        (*Anzahl der Logvorgänge pro Sekunde berechnen*)

(*Takt für Logvorgang bilden*)
POS_TAKT:=(MS_INT>= CT * LOG_MS OR sek_INT <>sek_ALT) AND NOT POS_TAKT_ALT;    (*Takt für Logvorgang, wenn aktuelle ms das vielfache der Abtastrate überschritten hat, oder Sekunde null erreicht**)
POS_TAKT_ALT:=(MS_INT>= CT * LOG_MS OR sek_INT <>sek_ALT);                            (*Takt für Logvorgang merken, um positive Flanke zu erkennen*)
Sek_ALT:=sek_INT;                                                                                    (*"alte Sekunde" merken*)

(*Positive Flanke auswerten*)
IF Pos_TAKT THEN                                                                                    (*Wenn Positive Flanke von Takt kommt dann....*)
    MS[INDEX]:=ms_INT;                                                                                (*millisekunde im Array speichern //nur zum debuggen*)
    sek[INDEX]:=sek_INT;                                                                            (*sekunde im Array speichern //nur zum debuggen*)
    CT:=CT+1;                                                                                            (*vielfaches um 1 erhöhen*)
    INDEX:=INDEX +1;                                                                                (*Arrayindex um 1 erhöhen //nur zum debuggen*)
    (* Ab hier Messwerte in csv speicher usw.............*)
END_IF;

(*Fehler zählen, wenn Zykluszeit die Logzeit überschreitet*)
IF ZYKL_ZEIT > LOG_ms THEN
    LOG_Error:=Log_Error +1;
END_IF;

(*Vielfaches normieren*)
IF CT>ANZ_LOG_sek THEN                                                                            (*Wenn Zähler für Vielfaches, Anzahl der Logvorgänge je Sekunde überschritten...*)
    CT:=1;                                                                                                (*vielfaches wieder auf 1 schreiben*)
END_IF;

(*Arrayindex normieren*)
IF INDEX >10 THEN
    INDEX:=1;
END_IF;


Hat den Vorteil, dass man die Abtastrate noch variieren kann. Für z.B. alle 100ms ein Messwert muss am Eingang "LOG_ms" der wert 100 angegeben werden.
Weiterhin wird überprüft, ob die Zykluszeit, die Abtastrate überschritten hat. Fehler werden am Ausgang LOG_ERROR ausgegeben.

Gruß
 
Zurück
Oben