Reputation: 3
The SYS_TIME function in ABB PLC / codesys programming returns a DWORD indicating the number of milliseconds since the PLC was turned on. (or perhaps hard reset / other event? Cannot find documentation of this.)
The max size of a DWORD in Codesys is 232-1 = 4,294,967,295.
This means SYS_TIME overflows after only 49.7 days!
Can anyone confirm exactly what the SYS_TIME function returns after 49.7 days has elapsed? Does it integer overflow and start counting from zero again?
This has important ramifications for using SYS_TIME for functions such as warning how long it is since some event occurred. (e.g. a read of a remote device via modbus).
Assuming it is just an integer overflow and SYS_TIME resets to zero, then the programmer can deal with this by e.g. resetting the variable they are using to record the last known event time:
(* Assuming now, last_event_time are suitably declared DWORDs *)
now := SYS_TIME(TRUE);
IF last_event_time > now THEN
last_event_time := 0;
END_IF
(* continue, performing check of how long since last event occurred etc.... *)
I'm hoping there is something I have missed that offers an alternative approach.
However - This is a GOTCHA that could trip up a PLC programmer who hadn't thought of this, causing an apparently fully functioning PLC program that has been tested extensively to fail after 49 days of use in the field.
Would be very helpful if there was an alternative to SYS_TIME that returns an LWORD, good for 5 billion years of uninterrupted service :-)
NB - I believe this function may be specific to the ABB AC500 range of PLCs, rather than a standard Codesys function, so this question is mostly directed at ABB & ABB PLC programmers.
Upvotes: 0
Views: 1217
Reputation: 1424
There are few options, but I would use either one of the following
Read system date and time and keep it updated. You will get 1 second resolution when using DT. It's easy to do comparison between DTs when you convert them to DWORD first (epoch time). See my old answer for Codesys time update. Note that if you calculate something like DT1-DT2, you will get a result of TIME -> Same overflow problem is possible. That's why DT_TO_DWORD would be good idea.
Make your own time. Your PLC has a cycle time, that should always be precise the same. Use it for you calculation.
This is a simple example with different data types.
Note that it's also possible to read cycle time using some Codesys library if required, not sure which one though. See for example this.
PROGRAM PRG_Time
VAR CONSTANT
TASK_CYCLE_TIME_MS : WORD := 10; //Update this!
END_VAR
VAR_OUTPUT
Total : LREAL;
TotalMilliseconds : LWORD;
TotalSeconds : DWORD;
Milliseconds : WORD;
END_VAR
Total := Total + TASK_CYCLE_TIME_MS / 1000.0;
TotalMilliseconds := TotalMilliseconds + TASK_CYCLE_TIME_MS;
Milliseconds := Milliseconds + TASK_CYCLE_TIME_MS;
//Calculate seconds
IF Milliseconds >= 1000 THEN
TotalSeconds := TotalSeconds + 1;
Milliseconds := Milliseconds - 1000;
END_IF
The LREAL
is precise enough for milliseconds. So basically here is a SYS_TIME as LWORD (the TotalMilliseconds
)
Upvotes: 0
Reputation: 3
Looking further into this, I have confirmed two things:
The second part of my question (what is the best way of handling this?) remains open...
Upvotes: 0