我正在开发一个应用程序,在这个应用程序中,我使用"F_GetSystemTime“标记高精度数据。此函数返回自1601年1月1日以来的100 1st间隔数。
我还通过NTP服务器将本地Windows时间同步到全球网络时钟。这确保了日历系统时间不会长期漂移。
然而,我遇到了一个问题,"F_GetSystemTime“似乎与Windows时间不同步。在几周的时间里,我的"F_GetSystemTime“出现了明显的漂移。
有没有办法让"F_GetSystemTime“和我的视窗时间保持同步?
发布于 2019-09-21 20:32:57
你可以用你的任务周期的精度来构建一个内部计数器。假设你有一个10ms的plc周期,你可以用10ms的时间戳记录你的数据。如果您想要更精确,您可以使用主plc任务的周期时间下降,或者创建一个周期更快的单独任务。
另一种可能性是使用具有过采样的快速IOs,如el1262。
下面是如何定义内部计数器的原始示例:
声明部分:
PROGRAM MAIN
VAR
bInit : BOOL;
nTime : UINT;
tBufferTime : TIME;
dtBufferDT : DT;
nCalcBuffer : UDINT;
sMs : STRING;
sLogTime : STRING;
sLogTimeWithMs : STRING;
stSystemTime : TIMESTRUCT;
fbLocalTime : FB_LocalSystemTime;
END_VAR实现部分:
fbLocalTime(bEnable := TRUE);
IF NOT bInit
THEN
dtBufferDT := SYSTEMTIME_TO_DT(fbLocalTime.systemTime);
IF fbLocalTime.bValid
THEN
bInit := TRUE;
END_IF
ELSE
nTime := nTime + 1;
tBufferTime := UINT_TO_TIME(nTime*10);
IF tBufferTime = T#1S
THEN
//Add a second to your system time
ntime := 0;
nCalcBuffer := DT_TO_UDINT(dtBufferDT)+1;
dtBufferDT := UDINT_TO_DT(nCalcBuffer);
sLogTime := DT_TO_STRING(dtBufferDT);
sLogTimeWithMs := sLogTime;
ELSE
//Add ms string time-stamp
sMs := TIME_TO_STRING(tBufferTime);
sLogTimeWithMs := CONCAT(sLogTime,sMs);
END_IF
END_IFsLogTimeWithMs将显示如下内容:
‘'DT#2019-09-21-14:30:28T#530ms’
为您提供10ms精度的正确时间,无需进一步同步。
然后,您可以擦亮字符串,以清除不需要的字符,如DT#、T#或ms。
发布于 2019-09-26 15:47:28
按照Filippos answer中的说明使用FB_LocalSystemTime功能块。它以毫秒为单位提供当前时间,并每隔dwCycle秒同步到Windows时钟。通过这种方式,代码块在被调用时总是给出当前时间,并保持自身同步。我不认为你需要任何缓冲区计算等,只要在每个PLC周期运行这段代码就可以了。
如果你的周期是10ms,那么每次调用输出都会改变10ms。当然,这可能不是99%的准确,但应该可以做到这一点。当时间同步到Windows时间时,前一个值和当前值之间的增量当然会有一些变化。如果不确定,则将同步间隔增加到更小或更高的值。
输出是TIMESTRUCT,它包含日期和时间以及毫秒。只需使用SYSTEMTIME_TO_DT进行转换即可。请记住,毫秒在该转换中是四舍五入的,因此它可能会更改秒数。您可以在SYSTEMTIME_TO_DT之前将毫秒设置为0,以保持秒数不变。
//...
VAR
LocalSystemTime : FB_LocalSystemTime;
FirstTimeUpdateOK : BOOL; //True after the time was synced OK at least once
EmptyDateAndTime : TIMESTRUCT := (wYear := 1970, wMonth := 1, wDay := 1);
END_VAR
VAR_OUTPUT
SyncedTime : TIMESTRUCT;
END_VAR
//First, set current time to 1970 if not updated yet.
IF NOT FirstTimeUpdateOK THEN
SyncedTime := EmptyDateAndTime;
END_IF
//Call the time sync block
LocalSystemTime(
bEnable := TRUE, //Keep as TRUE always
dwCycle := 5 //Sync with windows clock every 5 seconds (change to smaller/higher value to prevent small changes every 5 seconds)
);
IF LocalSystemTime.bValid THEN
//Everything OK, we have valid time
FirstTimeUpdateOK:= TRUE;
SyncedTime := LocalSystemTime.systemTime;
ELSIF FirstTimeUpdateOK THEN
//We have once had the valid time, but not now. Show error?
//...
END_IFhttps://stackoverflow.com/questions/58035625
复制相似问题