ABBPLC/codesys编程中的SYS_TIME函数返回一个DWORD,指示自PLC打开以来的毫秒数。(或者也许是硬重置/其他事件? 找不到这方面的文档。
Codesys 中 DWORD 的最大大小为 232-1= 4,294,967,295。
这意味着SYS_TIME仅在 49.7 天后就会溢出!
任何人都可以确切确认 49.7 天后 SYS_TIME 函数返回的内容?它是否整数溢出并再次从零开始计数?
这对于将SYS_TIME用于诸如警告自某些事件发生以来多长时间之类的功能具有重要影响。(例如,通过 Modbus 读取远程设备(。
假设它只是一个整数溢出并且SYS_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.... *)
我希望我错过了一些东西,可以提供另一种方法。
然而 - 这是一个陷阱,可能会绊倒一个没有想到这一点的 PLC 程序员,导致一个明显功能齐全的 PLC 程序在现场使用 49 天后经过广泛测试后失败。
如果有SYS_TIME的替代方案返回LWORD,将非常有帮助,适用于50亿年的不间断服务:-(
注意:我相信这个功能可能是ABB AC500系列PLC特有的,而不是标准的Codesys功能,所以这个问题主要针对ABB和ABB PLC程序员。
选项很少,但我会使用以下选项之一
-
读取系统日期和时间并保持更新。使用 DT 时,您将获得 1 秒的分辨率。当您首先将DT转换为DWORD(纪元时间(时,很容易在DT之间进行比较。请参阅我对代码系统时间更新的旧答案。请注意,如果您计算类似 DT1-DT2 的东西,您将获得 TIME -> 可能出现相同的溢出问题。这就是为什么DT_TO_DWORD是个好主意。
-
腾出自己的时间。您的 PLC 有一个循环时间,应该始终精确相同。用它来计算。
这是一个具有不同数据类型的简单示例。
请注意,如果需要,也可以使用一些 Codesys 库读取周期时间,但不确定是哪一个。例如,请参阅此内容。
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
LREAL
精确到毫秒。所以基本上这里有一个SYS_TIME作为LWORD(TotalMilliseconds
(
进一步研究这个问题,我确认了两件事:
- SYS_TIME绝对是ABB AC500的特定功能,包含在库SysInt_AC500_V10.lib中。
- 引用ABB AC500在线帮助:"49天后达到溢出。在此之后,计数器在 0."。 因此,这回答了有关函数行为的部分。
我问题的第二部分(处理这个问题的最佳方法是什么?(仍然开放......