Ereignisse mit einer Struktur aufzeichnen

Hallo bone666,
ich hatte gerade Langeweile und hab da mal was vorbereitet. Einige Variablen (z.B. die Konstanten) im FB müssten noch woanders hin verschoben werden, ich habe die nur alle darein gepackt, damit ich hier nicht so viele Codeschnipsel posten muss.
Zunächst einmal die Strukturen:
Code:
TYPE ST_InverterErrors :
STRUCT
 SCU   : BOOL;
 overcurrent_peak : BOOL;
 overcurrent_rms : BOOL;
END_STRUCT
END_TYPE


TYPE ST_ReportCollection :
STRUCT
 sTimestamp : STRING;
 sInverter  : STRING;
 sReport  : STRING;
END_STRUCT
END_TYPE

Dann der FB:
Code:
FUNCTION_BLOCK FB_InverterErrors
VAR_INPUT
END_VAR
VAR_OUTPUT
END_VAR
VAR
 arstReportCollection : ARRAY[0..255] OF ST_ReportCollection;       (* Array for error reports *)
 bReportCounter  : BYTE := 0;             (* Counter for report position *)
 arstInverterErrors  : ARRAY[1..MAX_INVERTER] OF ST_InverterErrors;    (* Array for inverter errors *)
 arxTriggerInvErr  : ARRAY [1..MAX_INVERTER, 1..MAX_INVERTER_ERR] OF R_TRIG; (* Array for error triggers *)
 bInverterCount  : BYTE;              (* Counter for current processed inverter *)
END_VAR
VAR CONSTANT
 MAX_INVERTER   : BYTE := 10;          (* Maximum number of connected inverter *)
 MAX_INVERTER_ERR : BYTE := 3;           (* Maximum number of errors per inverter *)
END_VAR


FOR bInverterCount := 1 TO MAX_INVERTER DO
 arxTriggerInvErr[bInverterCount, 1](CLK := arstInverterErrors[bInverterCount].SCU);
 IF arxTriggerInvErr[bInverterCount, 1].Q THEN
  arstReportCollection[bReportCounter].sTimestamp := TIME_TO_STRING(TIME());
  arstReportCollection[bReportCounter].sInverter  := BYTE_TO_STRING(bInverterCount);
  arstReportCollection[bReportCounter].sReport  := 'error: SCU';
  bReportCounter := bReportCounter + 1;
 END_IF
 arxTriggerInvErr[bInverterCount, 2](CLK := arstInverterErrors[bInverterCount].overcurrent_peak);
 IF arxTriggerInvErr[bInverterCount, 2].Q THEN
  arstReportCollection[bReportCounter].sTimestamp := TIME_TO_STRING(TIME());
  arstReportCollection[bReportCounter].sInverter  := BYTE_TO_STRING(bInverterCount);
  arstReportCollection[bReportCounter].sReport  := 'error: overcurrent peak';
  bReportCounter := bReportCounter + 1;
 END_IF
 arxTriggerInvErr[bInverterCount, 3](CLK := arstInverterErrors[bInverterCount].overcurrent_rms);
 IF arxTriggerInvErr[bInverterCount, 3].Q THEN
  arstReportCollection[bReportCounter].sTimestamp := TIME_TO_STRING(TIME());
  arstReportCollection[bReportCounter].sInverter  := BYTE_TO_STRING(bInverterCount);
  arstReportCollection[bReportCounter].sReport  := 'error: overcurrent rms';
  bReportCounter := bReportCounter + 1;
 END_IF
END_FOR
Du kannst die Aufrufe der Trigger auch alle zusammen direkt unter das For schreiben, das ist Geschmackssache. Dummerweise werden im Forum Tabs durch Leerzeichen ersetzt, darum sieht der Code optisch etwas würg :sm12: aus. Ach ja, und Time() habe ich nur aus Bequemlichkeit genommen, weil mir das mit SYSTEMTIME auf die Schnelle zu umständlich war.

Gruß

Oliver
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Bei 33 möglichen Fehlern kann man schon überlegen, sie anstatt in einzelne Bool-Variablen in 2 DWORDS (TC2) oder 1 LWORD (TC3) zu packen, z. B.
Code:
VAR_GLOBAL CONSTANT
   bitSCU:USINT:=0;   (* Bittposition 0: SCU *)
   bitOverCurrentPaek:USINT:=1;   (* Bitposition 1: Over current peak *)
   bitOverCurrentRMS:USINT:=2;   (* Bitposition 2: Over current RMS *)
   (* usw. *)
END_VAR

TYPE stInverterErrors :
STRUCT
   Input:DWORD;   (* Aktuelle Fehler von Inverter-HW *)
   Trigger:DWORD;   (* Fehler Trigger *)
   Last:DWORD;   (* Fehler in letztem PLC-Zyklus *)
END_STRUCT
END_TYPE

(* Code *)
(* Aktuelle Fehler eintragen, wenn der Inverter die Fehler wirklich als Bools meldet *)
arInverter[bInverterCount].stErrors.Input.bitSCU:=arInverter[bInverterCount].SCU;
arInverter[bInverterCount].stErrors.Input.bitOverCurrentPeak:=arInverter[bInverterCount].OverCurrentPeak;
arInverter[bInverterCount].stErrors.Input.bitOverCurrentRMS:=arInverter[bInverterCount].OverCurrentRMS;
(* Meldet der Inverter die Fehler als Bits in Status-Worten, wird die Sache vielleicht noch einfacher, so in der Art
   arInverter[bInverterCount].stErrors.Input:=arInverter[bInverterCount].HWStatus; *)
(* 32 Fehler Trigger auf einen Streich *)
arInverter[bInverterCount].stErrors.Trigger:=arInverter[bInverterCount].stErrors.Input AND NOT arInverter[bInverterCount].stErrors.Last;
arInverter[bInverterCount].stErrors.Last:=arInverter[bInverterCount].stErrors.Input;
(* Dann noch die Meldetexte für "sReport" in ein ARRAY[0..31] OF STRING packen,
   um die Meldungen auch in einer Schleife behandeln zu können *)
FOR bErrorCount:=0 to 31 DO
   IF (arInverter[bInverterCount].Trigger AND SHL(DWORD#1,bErrorCount))>0 THEN
      stReportCollection[bReportCounter].sTimeStamp:=SYSTEMTIME_TO_STRING(FB_Systemtime.systemTime);
      stReportCollection[bReportCounter].sInverter:=BYTE_TO_STRING(bInverterCount);
      stReportCollection[bReportCounter].sReport:=arReportTexts[bErrorCount];
      bReportCounter:=bReportCounter+1;
   END_IF
END_FOR
Hm, ist spät geworden, also keine Garantie für nichts.
 
Zurück
Oben