Join us today!
Cumulative downtime stats
Hey folks,
Looking to implement a down-time monitor for our system which will check a 1 second pulse, and increment a downtime counter if a fault exists, or an up-time counter if no fault exists.
I don’t want the cumulative error from running a 1 second repeating timer.
Is there a system flag that will give me a 1 second pulse?
Is there some other recommended way of doing this?
I see there are real-time clock commands, but it looks like these are slow to update.
I have implemented an LTON for now, and running LTIME_TO_DT to get a date_time, then DT_TO_DINT to get the seconds from the timer.
Feels a bit hacky though, so looking for suggestions.
Any help gratefully received!
Cheers
Duncan
This is what I have hacked together so far:
stats_timer(IN:=NOT stats_timer.Q, PT:=LTIME#36_500D); // timer runs for 100 years (then resets to 0) stats_timer_dt := LTIME_TO_DT(stats_timer.ET); // converts LTIME to DATE_AND_TIME stats_timer_sec := DT_TO_DINT(dTime); // gets seconds from DATE_AND_TIME stats_timer_msec := DT_TO_LINT(dTime); // gets milliseconds from DATE_AND_TIME IOAdmin.SystemSecondsPulse := stats_timer_sec <> stats_timer_sec_prev; // pulse if seconds have incremented stats_timer_sec_prev := stats_timer_sec; // store previous seconds value IF IOAdmin.SystemSecondsPulse THEN stats_timer_test := stats_timer_test + 1; END_IF;
https://github.com/runtimevic
https://github.com/TcMotion
https://www.youtube.com/playlist?list=PLEfi_hUmmSjFpfdJ6yw3B9yj7dWHYkHmQ
https://github.com/VisualPLC
You could try using FB_LocalSystemTime. This function block will continually return the time as long as bEnable is held on. Here's some code I used to return the number of seconds since 1/1/1970:
PROGRAM MAIN VAR fbTime: FB_LocalSystemTime; tStruct: TIMESTRUCT; dTime: DATE_AND_TIME; eTime_sec: DINT; END_VAR
fbTime(bEnable:=TRUE, dwCycle:=1, SystemTime=>tStruct); dTime := SYSTEMTIME_TO_DT(tStruct); eTime_sec := DT_TO_DINT(dTime);
The eTime_sec value could be compared to the value from the previous scan, as you did in your code, to trigger the one-second pulse. The dwCycle parameter lets you control how often the timer is synchronized with the system clock.
I use a self resetting clock to create pulses. Then I count the pulses to calculate elapsed time. I also use this clock to create pulsing Lights, buttons etc. You can customize it as you need. It is important to run this block in a fast task so your accuracy is high.
FUNCTION_BLOCK FB_Clock VAR_INPUT END_VAR VAR_OUTPUT Blink_1Hz : BOOL; Clock_1Hz : BOOL; Blink_10Hz : BOOL; Clock_10Hz : BOOL; END_VAR VAR Count : USINT; Timer100 : TON; END_VAR Timer100(IN := NOT Timer100.Q, PT:= T#100MS, Q => Clock_10Hz); IF Timer100.Q THEN Count := Count +1; Blink_10Hz := NOT Blink_10Hz; END_IF IF Count >= 5 THEN Blink_1Hz := TRUE; ELSE Blink_1Hz := FALSE; END_IF IF Count = 10 THEN Clock_1Hz := TRUE; Count := 0; ELSE Clock_1Hz := FALSE; END_IF
Alternatively you could use the system time to monitor machine down time. You can create a boolean tag which goes TRUE while there is an error on the machine, then monitor this tag's rising and falling edges, using my code below.
Disadvantage of that block is that you wont know the elapsed time during the alarm state. You can add a Method to see elapsed time comparing the current time with RisingTime.
FUNCTION_BLOCK FB_SignalMonitor VAR_INPUT SignalToMonitor : BOOL; END_VAR VAR_OUTPUT RisingTime : UDINT; // unit : ns FallingTime : UDINT; // unit : ns Duration : DINT; // unit : ms END_VAR VAR R_Edge : R_TRIG; F_Edge : F_TRIG; END_VAR (* ----------------------------------------------------------------------------------- FB_SignalMonitor ver1.0 Created by unchained 28/03/2023 This FB monitors the given signal and records the time of Rising Edge and Falling Edge. ------------------------------------------------------------------------------------*) R_Edge(CLK := SignalToMonitor); F_Edge(CLK := SignalToMonitor); IF R_Edge.Q THEN //Read the Rising Edge Time RisingTime := ULINT_TO_UDINT(F_GetCurDcTaskTime64() AND 16#FFFFFFFF); END_IF IF F_Edge.Q THEN //Read the Falling Edge Time FallingTime := ULINT_TO_UDINT(F_GetCurDcTaskTime64() AND 16#FFFFFFFF); Duration := (UDINT_TO_DINT(FallingTime) - UDINT_TO_DINT(RisingTime)) / 1000000; END_IF
- 17 Forums
- 267 Topics
- 924 Posts
- 1 Online
- 737 Members