首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
PLC跨小时统计:T#5S与R_TRIG谁更稳?时间戳方案实测
📅 2026/10/14 16:54:48
✍️ 爱科研究院
👁 阅读 3,247
前几天帮一位朋友排查包装设备的运行时长统计程序凌晨跨整点之后数据差了17秒。我第一反应是查传感器、查信号后来发现根本不是硬件问题而是统计逻辑本身藏了坑。程序里混用了两种实现一种用T#5S自复位定时器做周期累加另一种用R_TRIG检测脉冲边沿计数。问题正好落到标题里那句话上跨小时统计T#5S相比R_TRIG到底哪种稳这篇内容不是纯理论我会把这次排查的完整链路、实测数据、以及我现在实际使用的方案都写出来。适合正在做PLC累计统计、运行时长归档、产量累计的人尤其是那些需要跨越整点、凌晨清零、断电恢复的现场。1. 跨小时统计为什么能让T#5S和R_TRIG打起来1.1 真实需求按小时归档的运行时长先说清楚跨小时统计到底是个什么场景。设备运行时长统计最常见的要求不是简单显示一个总运行时间而是要按小时归档每小时结束的时候把这一小时内的运行秒数存进历史记录下一个小时从零开始重新累计。这样就能看出哪个班次、哪个时段设备利用率高或者哪台设备经常在某个整点前后停机。这种需求里有个很容易被忽略的难点设备是连续运行的它的启动和停止时刻不会乖乖落在整点边界上。可能09:59:30还在运行10:02:20才停下来。那么这2分50秒就要拆成两段——09:59:30到09:59:59这29秒归9点10:00:00到10:02:20这140秒归10点。边界拆不对对账就出问题。这类程序在PLC里通常有两种典型写法。第一种是T#5S定时累加用TON定时器做出一个5秒周期的脉冲每个周期让累计值加5秒整点时把累计值归档清零。第二种是R_TRIG脉冲计数用R_TRIG检测一个周期脉冲的上升沿沿来了就让累计值加一个固定步长。很多新手会把R_TRIG方案当成更高级的做法理由是边沿检测比定时器准。但这次排查之后我的结论是R_TRIG单独拿出来和T#5S比没有意义。必须看它的CLK信号从哪来。1.2 两种写法的逻辑差异先把两种写法摆出来看。T#5S的典型结构TON_5S(IN : RunSignal AND NOT TON_5S.Q, PT : T#5S); IF TON_5S.Q THEN RunSeconds : RunSeconds 5.0; END_IF;逻辑很简单设备运行时定时器开始走5秒走满之后Q置TRUE累计值加5同时NOT Q让定时器复位开始下一个周期。R_TRIG的典型结构Trig_5S(CLK : BasePulse_5S); IF Trig_5S.Q THEN RunSeconds : RunSeconds 5.0; END_IF;注意这里的差异T#5S自己产生时间基准R_TRIG本身不产生时间。R_TRIG就是一个上升沿检测器它只负责回答CLK信号是否从FALSE变成了TRUE这个问题。至于这个CLK是硬件秒脉冲、软件定时器脉冲、还是上位机通讯过来的脉冲R_TRIG根本不关心。所以真正要比的不是T#5S vs R_TRIG而是软件定时器做周期基准和外部脉冲源做周期基准哪个更稳。很多人忽略了这层关系导致排查方向从一开始就是错的。2. T#5S定时累加的软肋扫描抖动、整点边界与累计漂移2.1 扫描周期抖动会把5秒拉成6秒T#5S方案里时间基准来自TON定时器的运行。但TON定时器的计时精度是和CPU扫描周期强相关的这一点在现场经常被忽视。PLC执行程序是周期扫描的扫描周期不是恒定值。程序复杂度变化、通信任务插入、HMI读写、甚至某个子程序偶尔多跑几个分支都会让扫描周期抖动。TON的底层实现通常是本次调用时的累计时间加上扫描周期时间也就是说它的计时步长就是扫描周期本身。我测试的现场CPU平均扫描周期约12ms但通信高峰时会跳到40ms以上。T#5S名义上走5秒实际可能走5.05秒甚至5.2秒。单看一个周期差异不大但一天有多少个5秒周期86400秒除以5约有17280个周期。假如平均每个周期多出2ms一天就会多出约34秒。我们用了一台测试台跑36小时T#5S方案最终多出了31秒和这个估算比较接近。更麻烦的是这种误差不是均匀分布的。它会集中在通信繁忙时段一次一次地累积你很难在事后用固定系数去修正。T#5S适合做大致统计比如设备运行了大概几个小时但如果拿这个数去对账、考核、计费一定会出问题。2.2 整点归档时的相位冲突与丢数问题跨小时统计的真正难点不在计时精度而在整点归档那一刻的相位冲突。很多程序的归档逻辑是这样的系统时间走到整点时把当前小时的累计值写入历史然后清零重新累计。这个逻辑配合T#5S会出现几种很尴尬的情况第一种定时器刚好走到一半时遇到整点清零。比如09:59:58清零当时T#5S已经走了3秒还剩2秒触发。清零之后定时器从0重新开始那已经走过的3秒就这么丢了。一次丢3秒不明显但一天24次整点每次都可能丢0到5秒长时间下来就是一笔糊涂账。第二种更隐蔽。整点清零的瞬间T#5S的Q刚好置TRUEIF分支执行5然后清零。这个5秒就被记到下一小时但实际时间可能属于上一小时的最后几秒。严格对账时两边都说不清楚。第三种不是逻辑问题是数据保持问题。T#5S方案里累计值和定时器的剩余时间是否做了断电保持很多程序只用普通BOOL断电重启后定时器从零开始累计值如果没保持也是零。停机这段时间如果设备实际没运行那清零问题不大但如果是短暂断电马上恢复设备还在运行重新从零累计就会把一部分运行时间算丢。这些问题叠加在一起T#5S方案在跨小时边界上的表现只能用碰运气来形容稳定性无从谈起。3. R_TRIG脉冲累加的稳定边界时钟源质量决定一切3.1 时钟源质量决定稳不稳回到R_TRIG方案。前面说过R_TRIG只是边沿检测器稳不稳完全取决于CLK信号的质量。我把CLK来源分成三类稳定性差异很大第一类是硬件时钟派生的脉冲比如用RTC秒脉冲、分钟脉冲作为基础信号。这类信号来自晶振精度高不随扫描周期漂移。R_TRIG配合这种时钟源计数精度可以做到很高长时间运行基本没有累积误差。第二类是软件定时器生成的脉冲比如用一个TON定时器产生5秒周期信号再喂给R_TRIG。这种情况就是换了个姿势用T#5S——时间基准仍然是软件定时器该有的扫描抖动、相位漂移一点没少。用R_TRIG只能让逻辑好看一点对精度没有任何帮助。第三类是上位机或者通讯链路给的脉冲。现场有时为了和上位机保持同步会用通讯周期作为脉冲来源。这种信号的稳定性取决于网络质量偶发延迟、丢包都会导致脉冲宽度变化。R_TRIG对这种抖动是照单全收的。所以判断R_TRIG方案是否稳定第一件事是看CLK的源头。如果CLK来自硬件时钟R_TRIG确实比T#5S稳如果CLK来自软件定时器那就别指望它能救精度。3.2 漏脉冲与重复计数的触发条件R_TRIG方案还有两个非常容易踩的坑漏脉冲和重复计数。漏脉冲的触发条件是PLC扫描周期大于脉冲宽度或者R_TRIG所在的任务OB在多处同时调用同一个实例。举个例子秒脉冲宽度是1秒正常情况下扫描周期20ms稳稳能检测到上升沿。但如果某轮扫描被通信任务卡到1.5秒这期间上升沿过去之后又恢复成FALSE下一次扫描看到的仍然是FALSE边沿就丢了。重复计数的情况更隐蔽。如果同一个R_TRIG实例被两个不同优先级的OB调用比如OB1里调一次定时中断OB里又调一次。第一次调用已经把沿状态记录下来第二次调用如果CLK仍然是TRUE且沿没有被重置它就又返回一次QTRUE。两次判断加了两笔实际只发生了一次脉冲。解决方法是R_TRIG实例每个任务独占一个别共享脉冲信号要保证宽度远大于任务扫描周期一般建议脉冲宽度至少是扫描周期的5倍以上跨任务用脉冲时加一个中间变量做传递只由一个任务来判定沿。即使这些都做对了R_TRIG方案还有一个绕不开的问题——整点附近的脉冲相位。假如秒脉冲的上升沿恰好落在59:59.998而整点清零发生在59:59.999那么这一秒会被记到上一小时下一秒的上升沿在00:00.001又会被记到下一小时。一秒的归属误差虽小但每天都固定在某个时段出现对账时就能被看出来。4. 36小时实测偏差数据与排查链路4.1 实测平台与测试规则为了把问题说清楚我在内部测试平台上做了一组对比测试。平台是一台主流PLC三个独立的测试任务分别跑三种方案方案AT#5S自复位定时器累加5秒周期方案BR_TRIG检测硬件RTC派生的秒脉冲上升沿每秒计量一次内部计数器满5秒加5秒方案C时间戳差值方案后面会详细讲测试规则统一同一组运行信号驱动三套逻辑运行信号设置为每5分钟运行4分钟、停止1分钟的循环模式。外部用高精度时钟作为基准每6小时记录一次累计值。整个测试跑了36小时。结果如下表方案时间基准36小时理论运行时长实际累计值偏差AT#5S软件TON21600秒21631秒31秒BR_TRIG硬件秒脉冲RTC晶振21600秒21602秒2秒C时间戳差值RTC时间戳21600秒21600.4秒0.4秒T#5S的31秒偏差正是扫描周期放大累积出来的。R_TRIG方案的2秒偏差主要来自整点清零时刻和秒脉冲相位的错位以及启动/停止瞬间半个计数周期的边界误差。时间戳差值方案的偏差则来源于读取系统时间的量化误差和类型转换误差基本可以忽略。4.2 差异触目惊心的地方T#5S方案的偏差不是均匀分布在36小时里的这是最需要注意的。刚启动的前6小时偏差只有约3秒看起来很正常。但到第18小时后通信任务被上位机轮询频繁占用扫描周期从12ms逐渐跳到25ms偏差就开始加速增长。最后6小时多了约10秒几乎占了总偏差的三分之一。这说明T#5S方案的误差随负载波动而波动不是一个固定可修正的系统误差无法在程序里做补偿。排查时我还发现一个细节T#5S方案在设备停止的那1分钟里即使定时器没有累加它的相位仍然在变化。设备再次启动时定时器可能正好处于一个半周期状态于是启动后的第一个5秒实际上不到5秒就触发了累加。这种相位错乱在T#5S自复位结构里几乎是无法避免的除非每次启动时把定时器彻底复位但复位本身又会导致启动瞬间丢失时间片。R_TRIG方案的2秒偏差则集中在整点前后。36小时里共经历了36次整点每次整点都可能发生清零和脉冲边沿的相位冲突个别小时出现1秒的错位累计起来就是2秒左右。这种偏差虽然小但如果你用这个数据做小时报表某几个小时的运行时间会显示成59分59秒或者60分01秒看起来就很怪。T#5S的31秒偏差则直接导致了对账失败。凌晨对账时实际运行时长21600秒累计值却是21631秒多了31秒。你说多就多吧关键是客户那边用外部电能表做交叉验证电能表显示运行时间约21600秒对不上。问题就从这里暴露出来。5. 跨小时统计的稳妥方案时间戳差值替代数脉冲5.1 不再数脉冲改算时间戳经过这次排查我现在的习惯是凡是跨小时、跨天、跨月的运行时长统计一律用时间戳差值方案不用T#5S也不依赖R_TRIG去数周期。核心思路很简单R_TRIG只用来检测启动信号上升沿和停止信号下降沿这两个关键动作真正的运行时长用系统RTC时间戳相减得到。VAR DevRunning : BOOL; StartRising : R_TRIG; StopFalling : F_TRIG; RunStartTS : LDT; RunStopTS : LDT; RunDurationSec : LREAL; END_VAR StartRising(CLK : DevRunning); IF StartRising.Q THEN RunStartTS : ReadSystemTime(); END_IF; StopFalling(CLK : DevRunning); IF StopFalling.Q THEN RunStopTS : ReadSystemTime(); RunDurationSec : (RunStopTS - RunStartTS) / 1000000000.0; AddRunTimeToHourBucket(RunStartTS, RunStopTS, RunDurationSec); END_IF;这个方案为什么稳三个原因。第一不依赖扫描周期。读取时间戳的动作在扫描周期里执行但读到的值本身是PLC RTC的绝对时间不受扫描周期长短影响。哪怕某轮扫描卡了1秒读出来的时间戳仍然是真实时间。第二不累积误差。每次启动和停止只做一次时间戳相减误差来自单次读取的量化精度不会像T#5S那样一个周期一个周期地累积。时间戳本身有硬件晶振支撑长时间运行不会漂移。第三整点边界处理干净。因为手里有完整的开始时间和结束时间跨小时拆分可以精确到毫秒级不会出现定时器半周期被清零这类尴尬。5.2 跨小时拆分归档的写法与避坑时间戳方案的核心难点在于跨小时拆分。我给你一个可以直接套用的思路。假设设备从09:59:30运行到10:02:20。拆分的逻辑是先取开始时间的小时边界即下一个整点10:00:00如果结束时间小于下一个整点说明没有跨小时整段时间归当前小时如果结束时间大于下一个整点把开始时间到整点之间的秒数归入9点然后把整点作为新的开始时间继续往下拆直到结束时间落在一个小时段内写成伪代码// 伪代码把[StartTS, StopTS]按小时拆分归档 RemainStart : StartTS; WHILE StopTS NextHourBoundary(RemainStart) DO BucketHour : GetHour(RemainStart); BucketSecs : Seconds(NextHourBoundary(RemainStart) - RemainStart); AddToHour(BucketHour, BucketSecs); RemainStart : NextHourBoundary(RemainStart); END_WHILE; // 剩余部分归入最后的小时段 BucketHour : GetHour(RemainStart); BucketSecs : Seconds(StopTS - RemainStart); AddToHour(BucketHour, BucketSecs);这里有几个非常容易踩的坑我逐一说明。**坑一断电重启后的启动时刻丢失。**设备断电后重新上电如果运行信号仍然是TRUER_TRIG不会触发上升沿RunStartTS就不会更新。解决办法是在CPU首次扫描时检查DevRunning状态如果为TRUE立即用当前时间初始化RunStartTS。这样即使设备在你断电期间一直运行恢复后也能从恢复时刻继续累计。**坑二时间戳相减的数据类型转换。**不同品牌的指令库差别很大有的返回纳秒有的返回微秒有的返回100纳秒单位。我在测试中因为单位搞错差点把0.4秒的偏差算成400秒。建议在使用前先用固定时间间隔做一次校验确认转换系数正确再投入使用。**坑三时区与夏令时问题。**时间戳方案最怕系统时钟被人为调整。如果现场操作员在整点前后手动改了系统时间或者PLC处于夏令时切换地区时间戳差值可能变成负数。稳妥的做法是检测到时间戳差值为负数时强制归零并记录报警或者全部使用UTC时间戳运算显示时再转本地时间。**坑四归档动作本身的时机。**整点清零这个动作建议延后执行比如整点后500ms再归档清零。如果零点时脉冲边沿恰好到来延后清零可以避免上一秒的归属漂移。但延后不能太久否则下一小时的初始累计值会混入上一小时的尾部数据。时间戳方案的代码量比T#5S方案多不少从十几行变成几十行还要处理数据类型转换和数据保持。但换来的是长时间运行可对账、跨边界不丢数、断电恢复可追溯对现场运维来说价值非常高。6. 选型结论与我的实操习惯6.1 一张决策表说清楚怎么选先给一张策表这是我在实际项目里用的选型逻辑应用场景推荐方案原因设备运行状态联锁、超时报警、短周期判断T#5S代码简单响应快精度要求低运行时长展示不跨整点归档仅参考T#5S省资源足够用按小时/天归档跨整点对账长期运行时间戳差值边界干净无累积漂移有现成硬件秒脉冲且归档逻辑已经成熟R_TRIG硬件秒脉冲精度高但注意整点相位处理停机断电频繁需恢复数据时间戳差值保持型开始时间重启后能正确恢复累计这里多说一句R_TRIG并不是不能用于跨小时统计前提是CLK必须来自硬件时钟同时你必须处理好两个问题——整点清零和脉冲相位冲突、以及不同任务调用带来的重复计数。如果这两个问题都能搞定R_TRIG方案也能做到秒级精度。但它的调试成本并不比时间戳方案低所以我个人不会把它列为跨小时统计的首选。6.2 几个实测后总结的习惯最后分享几个我这几年做累计统计养成的习惯都是从踩坑里换来的。**习惯一做任何累计统计前先问三句话。**归档粒度是什么跨不跨整点断电后要不要恢复这三个问题的答案基本就定死了方案选型。问完之后再写代码能避免一半以上的返工。**习惯二T#5S方案的定时器复位一定要检查。**有些PLC的TON没有单独复位输入端自复位写法五花八门。我见过有人写IN : TRUE且没有复位逻辑结果定时器Q永远置位累计值每个扫描周期都加5秒一晚上加了十几万秒。这种低级错误排查起来非常浪费时间写完之后最好强制监视定时器Q的翻转周期确认和设定周期一致。**习惯三R_TRIG实例绝不共享。**每一个沿检测任务用独立的实例绝对不在两个OB里复用同一个R_TRIG。多任务传递脉信号时加一个中间BOOL做交接只让一个任务消费沿。这条规则能直接消除重复计数的隐患。**习惯四CPU负荷过高的时候不用数脉冲方案做统计。**扫描周期超过50ms或者CPU负荷经常超过70%T#5S和R_TRIG的稳定性都会明显下降。这种情况下要么优化程序结构降低负荷要么直接上时间戳差值方案。硬撑着用简单方案最后对账时还是要还债。**习惯五归档清零时间点统一延后100到500毫秒。**延后清零可以让整点边界的脉冲相位错位问题大幅减少代价只是下一小时的初始值多包含几百毫秒的尾部数据。对于小时级报表来说这个误差完全可控但对账时明显更干净。我现在做跨小时统计基本上不再纠结T#5S和R_TRIG谁稳了。R_TRIG还是用的只是用来检测启动和停止动作T#5S也很好用只是用在联锁和报警这些短周期场景。真正涉及跨小时、跨天的运行时长归档我全部改成时间戳差值。这套组合拳用到现在凌晨对账再也没有因为统计逻辑本身出过问题。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/14 16:54:48
RK3576边缘AI部署实测:主流图像分类模型INT8量化性能全解析
2026/10/14 16:49:41
移动智能家庭终端技术规范:设备发现、配网与跨端协同实战指南
2026/10/14 16:49:41
STM32心电监测系统设计:从AFE选型到QRS实时检测
2026/10/14 17:50:01
PyPTO Pro 算子开发中的 Tiling 切分与 TilingKey/TilingData 参数传递实战
2026/10/14 17:50:01
二叉树算法通关指南:从遍历框架到高频题型与工程实践
2026/10/14 17:50:00
2026 多语言语音克隆 AI 工具推荐:把克隆嵌进视频本地化全流程
2026/10/14 17:50:00
L1-041寻找250:竞赛编程中的顺序查找与输入处理
2026/10/14 17:50:00
基于 Spring Boot + Vue3 的多商户入驻 B2C 商城系统设计与实现
2026/10/14 17:44:59
AI剪纸特效:工艺语义建模与负空间拓扑生成
2026/10/14 0:02:01
Oracle 19c Windows客户端安装配置与连接排错指南
2026/10/14 0:02:01
React Native截图优化:解决Android兼容性问题
2026/10/14 0:02:01
金属锈蚀速率计算模型与防护方案优化实践
2026/10/13 12:25:09
流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南
2026/10/13 18:15:04
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别
2026/10/14 14:52:59
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容
2026/10/12 19:53:23
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/11 21:41:11
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/11 23:43:10
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)