一、在倍福PLC里,获取系统时间,首先要添加库 Tc2_system,因为需要用到GETCPUCOUNTER功能块
二、实例化功能块
FUNCTION F_TIME_V1_0_0 : TIME
VAR
fbSystemTick :FW_GetCpuCounter;(* Instance of function block for time measuring *)
udiTemp_TimeLow :UDINT;(* Low DW of Timestamp *)
udiTemp_TimeHigh :UDINT;(* High DW of Timestamp*)
dwTemp_TimeHighDW :DWORD;(* temp variable for reset of 19 Bit of High DWORD *)
udiTemp_TimeHighCalc :UDINT;(* temp variable for the value of Bits in ms*)
udiTemp_TimeSum :UDINT;(* temp variable for added systemticks in ms *)
udiTemp_Calc :UDINT;(* temp variable for computing sytemticks in ms *)
END_VAR
(*All VAR_IN_OUT variables have been moved to the end of the declaration due to compatibility reasons*)
VAR_IN_OUT
END_VAR
三、以下代码实现了将系统高精度时钟转换为可读的时间格式(毫秒级),解决因数据类型限制导致的时间溢出问题。
(* Call of function block *)
fbSystemTick( dwCpuCntLo => udiTemp_TimeLow,
dwCpuCntHi => udiTemp_TimeHigh);
(* Overflow of LowWord each 7 Minutes! Therefor take for used time both DW *)
(* Change first Bits of HighDW von 100ns to 1ms *)
udiTemp_Calc := 4294967295 / 10000;
(* Length of UDINT Variable is not lage enough. Therefore delete first 19 Bit of High DW *)
dwTemp_TimeHighDW := UDINT_TO_DWORD(udiTemp_TimeHigh);
dwTemp_TimeHighDW := SHL(dwTemp_TimeHighDW, 19);
dwTemp_TimeHighDW := SHR(dwTemp_TimeHighDW, 19);
udiTemp_TimeHighCalc := DWORD_TO_UDINT(dwTemp_TimeHighDW);
(* Whole Ticks is sum of LowDW and High DW*)
udiTemp_TimeSum := (udiTemp_TimeLow/10000)+(udiTemp_TimeHighCalc * udiTemp_Calc);
(* Output of Timestamp as TIME in ms *)
F_TIME_V1_0_0 := UDINT_TO_TIME(udiTemp_TimeSum);
3.1、代码分析
3.1.1 系统时钟读取
fbSystemTick( dwCpuCntLo => udiTemp_TimeLow,
dwCpuCntHi => udiTemp_TimeHigh);
- 功能:调用系统功能块
fbSystemTick
获取高精度时钟计数。 - 输出参数:
udiTemp_TimeLow
(低 32 位):存储时钟计数的低字部分(单位:100ns)。udiTemp_TimeHigh
(高 32 位):存储时钟计数的高字部分(单位:100ns)。
- 问题:低字部分每约 7 分钟(2^32 × 100ns ≈ 429 秒)溢出一次,需结合高字计算完整时间。
3.1.2. 高字数据预处理
udiTemp_Calc := 4294967295 / 10000; // 常量:429,496.7295
dwTemp_TimeHighDW := UDINT_TO_DWORD(udiTemp_TimeHigh);
dwTemp_TimeHighDW := SHL(dwTemp_TimeHighDW, 19); // 左移19位
dwTemp_TimeHighDW := SHR(dwTemp_TimeHighDW, 19); // 右移19位(清除低19位)
udiTemp_TimeHighCalc := DWORD_TO_UDINT(dwTemp_TimeHighDW);
- 目的:处理高字数据,消除低精度位的干扰。
- 关键操作:
- 位运算:通过
SHL
和SHR
清除高字数据的低 19 位(保留高 13 位有效信息)。 - 精度转换:将高字部分从 100ns 精度转换为 1ms 精度(通过
udiTemp_Calc
常量缩放)。
- 位运算:通过
3. 1.3 组合高低字并转换单位
udiTemp_TimeSum := (udiTemp_TimeLow/10000)+(udiTemp_TimeHighCalc * udiTemp_Calc);
F_TIME_V1_0_0 := UDINT_TO_TIME(udiTemp_TimeSum);
- 时间计算逻辑:
- 低字部分:
udiTemp_TimeLow/10000
将 100ns 转换为 ms(1ms = 10,000 × 100ns)。 - 高字部分:
udiTemp_TimeHighCalc * udiTemp_Calc
将高字缩放为 ms 单位。 - 合并结果:两部分相加得到总毫秒数。
- 低字部分:
- 输出:通过
UDINT_TO_TIME
转换为标准TIME
类型变量F_TIME_V1_0_0
。
3.2 关键技术点
-
溢出处理:
- 利用高字数据扩展时间范围,避免每 7 分钟溢出。
- 实际有效时间范围:约 2^45 × 100ns ≈ 35.7 年(高 13 位 + 低 32 位)。
-
精度与性能平衡:
- 清除高字低 19 位:减少计算量,同时保留足够精度(误差 < 0.5ms)。
- 常量
udiTemp_Calc
预计算:优化运行时性能。
-
数据类型适配:
- 使用
DWORD
中间变量处理位运算(SHL
/SHR
仅支持DWORD
)。 TIME
类型最大值为 24 天 20 小时 31 分钟 23.647 秒,适用于大多数工业场景。
- 使用
3.3 应用场景
- 高精度计时:测量设备响应时间、循环周期。
- 长时间监控:记录设备累计运行时间(避免频繁重置计数器)。
- 事件追溯:生成精确到毫秒级的时间戳,用于故障诊断。