尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
PLC跨小时统计选型:R_TRIG边界检测为何比T#5S定时扫描更可靠?
做自动化项目的兄弟应该都有印象“跨小时统计”这四个字看着不起眼做起来却最容易在验收时翻车。产量、能耗、流量累积客户都是按小时拉着Excel对账的一旦0点前后的数据对不齐现场工程师的耳朵就要遭罪。最近技术交流群里又有人问跨小时统计用T#5S稳还是用R_TRIG稳问的人显然是被边界数据折磨过。先把结论放在前头如果你的目标是“准确裁定哪个事件属于哪个小时”那别犹豫用R_TRIG配合系统时间比较来检测小时边界比T#5S定时扫描稳得多。T#5S不是不能用但它天生带着一个最长5秒的归属模糊窗口用在边界判定上就是隐患。下面我会把误差来源、实现方式、踩坑经验全部拆开讲不管你是梯形图老法师还是ST爱好者应该都能抄点作业。1. 先把场景讲清楚跨小时统计到底难在哪1.1 统计对象决定方案跨小时统计最常见的对象有三类产线上的产量计数光电传感器、接近开关、公用工程的能耗统计电表脉冲、瞬时功率以及水处理和热网的流量累积。它们表面上看都是“每小时出一个数”但对信号的处理方式截然不同。产量和电表脉冲属于离散事件一个一个的脉冲每个脉冲代表一个产品或者一个固定能量单位。这类信号必须逐事件捕捉漏一个就少一个没有任何“插值”的说法。瞬时流量和瞬时功率是连续量随时间变化需要周期采样再积分才能得到累积值。很多工程师把这两类搞混用5秒定时去“数脉冲”或者试图用边沿触发去“积分”方向一反稳定性自然没保证。所以你先要问自己一个问题我要统计的是离散事件还是连续量这个问题想清楚方案就定了大半。想不清楚后面的选型都是扯淡。另外还要考虑MES报表通常需要给每个小时记录打上明确的时间标签这个标签是按起始时间命名还是按结束时间命名直接影响到跨小时时数据到底塞进哪个小时段这一步在程序里就得定死别等报表端再来猜。1.2 跨小时切换的三个标准动作不管统计对象是什么跨小时统计在程序里都逃不过三个动作锁存、清零、启动。锁存是把上一小时累计值从工作寄存器存到历史记录区清零是把当前小时累计计数器归零启动是刷新小时起始时间戳让新一小时的累计从零开始。这三个动作必须在同一个触发信号下连续完成而且不能被打断。比如先清零再锁存锁存读到的就是零上一小时的数据直接丢了先锁存再清零但忘了刷新时间戳下一轮边界判断的基准还是旧小时整个程序就会循环错位。这不仅是逻辑顺序问题更是你有没有一个“可靠的、只发生一次的边界信号”的问题。很多现场报错的数据问题最后查下来根本不是累加逻辑错了而是触发切换的那个信号本身不可靠。1.3 边界裁定是灵魂不能靠运气跨小时统计的核心不是累计逻辑本身而是“什么时候执行锁存、清零、启动这三个动作”。一秒不差、不多不少恰好在这个扫描周期里发现了整点然后执行切换。这句话听起来简单做起来最难。有些程序写得很随意PLC上电后启动一个5秒定时器定时到就执行统计逻辑逻辑里比较当前小时和上一小时变了就切换。表面上看小时一变最多5秒内就能发现好像没什么问题。但问题恰恰就出在这个“最多5秒”上。你愿意接受你的产品归属存在一个最长5秒的不确定窗口吗如果甲方愿意接受我也不拦着。在实际产线上5秒可能意味着几十个产品归属不清报表上一多一少特别明显。2. T#5S方案误差模型和局限性2.1 常见写法用T#5S做跨小时统计梯形图里大概是这么个意思TON定时器定为5秒定时到Q输出一个脉冲触发统计逻辑统计逻辑里读当前时间的小时字段和上次记录的小时值比较不等就执行切换执行完重置定时器。ST里写出来大概是这样TON_inst(IN : NOT TON_inst.Q, PT : T#5S); IF TON_inst.Q THEN current_hour : READ_HOUR_REALTIME(); IF current_hour last_hour THEN history[last_hour] : product_count; product_count : 0; last_hour : current_hour; END_IF; TON_inst(IN : FALSE); END_IF;这种写法看起来很合理5秒检查一次一小时720次误差最多5秒听起来可以接受。这也是很多项目敢用它做边界裁定的原因。但把误差模型拆开看问题比想象的多。接下来我逐个分析。2.2 相位误差定时器不是从整点开始的T#5S定时器和小时整点之间没有任何相位同步关系。PLC上电后定时器从某个时刻开始计时它下一次触发时刻完全由启动时刻决定。举个例子假设这个定时器上次触发是23:59:58那下一次触发就是00:00:03。执行跨小时判断时实际时间已经是00:00:03。这5秒间隔里发生了什么23:59:58到00:00:00这2秒内通过的产品物理上属于上一小时但计数器还没来得及锁存00:00:00到00:00:03这3秒内通过的产品物理上属于下一小时却已经被算进了当前累计值。如果你采用“先锁存再清零”锁存时刻是00:00:03会把0点后3秒的数据一起记进上一小时如果用“先清零再锁存”0点后3秒的数据就被直接清掉了。无论哪种写法都存在一个上一小时和下一小时之间归属模糊的窗口这个窗口最长就是5秒。2.3 定量算一笔账假设产线每秒通过1个产品最坏情况下归属误差是5秒乘以每秒1个等于5个产品。如果产线每秒通过10个那就是50个。5000瓶/小时的包装线0点前后的统计误差可以达到正负50瓶报表上直接体现为一小时多几十瓶、另一小时少几十瓶。现场对账的时候这几十瓶的差异很难解释因为你觉得程序逻辑没问题但数据就是不对。流量场景更直观。假设瞬时蒸汽流量是10吨/小时5秒窗口对应的归属误差就是10吨除以3600秒再乘以5秒大约14公斤。如果连续统计24小时由于定时器相位是固定的某些小时会持续偏多、某些持续偏少MES报表上的小时流量曲线会出现规律性锯齿。这种锯齿一旦被客户看到第一反应就是你采集程序有问题解释成本极高。2.4 扫描周期叠加的触发延迟T#5S的定时精度本身还行不少PLC的定时器使用系统时基5秒不会差太多。但定时时间到之后Q信号要到下一次程序扫描时才会被逻辑读取并执行切换。这个“下一次扫描”就是额外延迟。如果扫描周期稳定在10ms影响不大。但现场程序里往往挂着PID、通信、配方管理扫描周期可能波动到几十毫秒。一旦通信卡顿扫描周期可能到100ms以上边界切换时刻会比真实整点晚100ms以上。这个误差虽然比5秒小但它是随机的、不确定的排查起来比固定相位误差更恶心。因为固定误差还能通过逻辑修正随机延迟你根本没法补偿。2.5 定时采样的积分截断误差如果统计对象是连续量用T#5S做采样积分是另一个常见做法每5秒读一次瞬时流量乘以5秒然后累加。问题在于T#5S的采样时刻不会恰好落在整点上。上一小时最后一次采样可能是23:59:57按采样时刻归属23:59:57采到的瞬时值乘以5秒这5秒区间会覆盖到00:00:02其中0点后2秒的流量被算进了上一小时下一小时的积分起点从00:00:02开始相当于少了2秒。积分边界被截断而且截断量随定时器相位不同而不同。这种截断误差在每个小时交界处都会出现短时间看影响不大累积起来会让人觉得数据总有那么一点说不清的偏差。3. R_TRIG方案为什么更稳3.1 R_TRIG的本质和两种用法R_TRIG是上升沿检测功能块输入信号clk从FALSE变TRUE时输出Q会输出一个扫描周期的TRUE脉冲。它的核心价值是捕捉“状态从0到1的跳变瞬间”而不是周期性的时间到达。在跨小时统计里R_TRIG有两种典型用法正好对应前面说的两类统计对象。第一种是检测系统时间的小时值变化裁定自然小时边界第二种是检测传感器脉冲信号上升沿逐事件计数。下面分开讲清楚。3.2 用法一检测小时边界通过系统时间函数读取当前小时字段每个扫描周期和上一次的值比较。不一样了说明系统时间跨过了整点。这里有个很容易犯的错直接用比较结果这个电平信号去触发锁存和清零。问题在于比较结果会持续TRUE一个甚至多个扫描周期如果直接拿来当触发器程序每个扫描周期都会执行一遍锁存清零累计值永远攒不起来。正确做法是用R_TRIG把这个“小时变化”电平信号转换成单周期脉冲current_hour : READ_HOUR_REALTIME(); hour_changed : current_hour last_hour; R_TRIG_hour(clk : hour_changed); IF R_TRIG_hour.Q THEN history[last_hour] : product_count; product_count : 0; last_hour : current_hour; END_IF;这里的hour_changed就是current_hour不等于last_hour的比较结果。R_TRIG保证切换动作只执行一次而且执行时机和真实整点只差一个扫描周期。扫描周期10ms就是10ms扫描周期1ms就是1msT#5S的5秒模糊窗口在这里被压缩了500倍以上。这个精度在现场是完全够用的。3.3 用法二逐脉冲计数如果统计对象是离散事件比如产品通过光电传感器的脉冲每个脉冲都要加1。程序写法R_TRIG_sensor(clk : sensor_signal); IF R_TRIG_sensor.Q THEN product_count : product_count 1; END_IF;只要传感器脉冲宽度大于扫描周期每个脉冲都会被捕捉。扫描周期10ms脉冲宽度20ms以上就不会漏。如果脉冲太快就要上硬件中断或者高速计数通道那属于另一个话题。跨小时时脉冲计数和边界锁存两个功能要配合平时R_TRIG_sensor负责对每个脉冲加1当R_TRIG_hour的Q为TRUE时先把product_count锁存到历史记录再清零然后开始新小时累计。脉冲计数本身不会被T#5S的采样间隔影响因为它是逐事件处理的天然就没有“采样点错过整点”这个问题。3.4 从误差模型看为什么稳整理一下R_TRIG方案的误差来源。边界检测误差是一个扫描周期毫秒级脉冲捕捉误差只要脉宽合规零漏计数连续量积分用循环中断或系统累积功能不依赖普通定时器时间基准是系统实时时钟与程序执行节奏无关。这套方案的本质是事件驱动。程序只对“边界事件”和“脉冲事件”反应扫描周期波动只会延迟检测不会产生归属错误。就算某个扫描周期发生了100ms延迟跨小时的判断也只是晚了一个周期该属于上一小时的数据始终在计数器里不会因为采样相位而错分。这一点是T#5S方案做不到的。T#5S是时间驱动它只知道自己“该干活了”至于现在离真实整点差多少一无所知。3.5 别忽视系统时间的前提R_TRIG方案稳有一个硬前提系统时间必须准。实时时钟电池、上电自动同步、外部时钟源这些都要到位。如果PLC时间在运行中跳变不管是手动校时还是时间同步造成的跳变小时字段的反复变化都会触发假边界。建议在程序里做时间有效性判断读取小时字段前先检查系统时间是否有效、年份是否合理。时间无效时宁可保持原状也不要执行清零。有一次现场校时时间从23:59:58直接跳到00:00:00如果边界逻辑没做防抖统计会被连续触发两次清零。这个细节听起来小真踩上的时候特别冤。4. 选型建议和实操要点4.1 对比表对比维度T#5S定时扫描R_TRIG边界检测触发本质时间周期触发状态跳变触发边界精度相位相关最差5秒扫描周期级毫秒离散事件计数不适合会漏脉冲逐脉冲捕捉连续量积分可用但有截断误差不适合直接积分受扫描周期波动影响大触发延迟漂移小仅延迟检测实现复杂度低中建议角色周期快照、趋势记录边界锁存、事件计数4.2 我验证过的组合方案我个人推荐跨小时统计按下面这套组合来做几个项目用下来没有因为边界问题被甲方找过边界裁定系统时间小时字段比较R_TRIG负责锁存、清零、启动。离散事件统计R_TRIG逐脉冲累加计数器用保持型变量。连续量统计用循环中断做等周期积分周期根据工艺定比如100ms或1s不建议用普通TON定时器做积分。历史快照MES如果还需要过程趋势可以另用T#5S做5秒快照但快照数据只用于趋势展示不参与小时归属判定。这套方案里T#5S退回到它擅长的“周期采样”角色边界这种需要精确裁定的活全部交给R_TRIG和系统时间。连续量统计不用TON定时器是因为TON定时器的触发时刻依赖扫描周期而循环中断有自己的硬件时基积分更均匀跨小时截断误差也更小。4.3 一个可抄的ST示例完整的一个小时切换逻辑ST风格写出来是这样// 周期块中每个扫描周期执行 current_hour : READ_HOUR_REALTIME(); hour_changed : current_hour last_hour; R_TRIG_hour(clk : hour_changed); IF R_TRIG_hour.Q THEN // 1 锁存上一小时累计值 history[last_hour] : product_count; // 2 给上一小时记录打上时间段标签 history_hour[last_hour] : CONCAT(INT_TO_STRING(last_hour), :00-, INT_TO_STRING(current_hour), :00); // 3 清零当前累计 product_count : 0; // 4 刷新小时基准 last_hour : current_hour; END_IF; // 脉冲计数每个扫描周期执行 R_TRIG_sensor(clk : sensor_signal); IF R_TRIG_sensor.Q THEN product_count : product_count 1; END_IF;注意第2步的小时标签用起始时间命名比如“17:00-18:00”这样报表端能清楚区分每个小时区间避免“23点那段到底是23点还是0点”的歧义。如果不打标签隔几天再回看历史数据很容易把上一小时和下一小时搞混。4.4 写代码的常见注意点锁存、清零、启动的顺序一定要写在注释里未来维护的人会感谢你。当前小时累计值用掉电保持变量防止断电丢累计锁存后的历史记录区也建议用保持区或者第一时间上传MES别让数据在PLC里裸奔。R_TRIG的Q只保持一个扫描周期如果同一扫描周期里有多个逻辑都要用这个边界信号最好在Q为TRUE时置位一个中间变量其他逻辑读取这个中间变量而不是重复调用R_TRIG输出。调试的时候把边界信号拉出来接到一个HMI指示灯或者示波器通道验收时心里有底数据对不上时也能快速判断边界触发是否正常。5. 踩过的坑和排查记录5.1 坑一锁存和清零的顺序写反某个项目的产量统计0点后报表显示上一小时产量为0。查代码发现工程师先写了product_count清零再写的锁存history赋值。清零在前锁存自然锁了个0。这类问题不看代码很难发现因为程序逻辑本身没有报错数据看起来也有规律就是每个整点后上一小时产量都是0。排查时第一件事就是检查锁存和清零的相对顺序别先怀疑传感器和计数器。5.2 坑二用字符串比较时间导致偶发失灵有工程师用字符串方式读取系统时间做小时比较遇到格式对齐问题“0:00:00”和“00:00:00”看起来一样比较结果却可能不同边界信号就会漏发。漏一次那个小时的统计就整体偏移了。后来改成读取整数小时字段做比较问题消失。这也是我坚持“比较整数不比较字符串”的原因。字符串比较在不同平台上的实现细节差异很大正经做统计逻辑远离它。5.3 坑三脉冲宽度小于扫描周期漏计数传感器脉冲持续时间只有1ms扫描周期10msR_TRIG一次都捕捉不到。排查时先确认脉冲宽度和扫描周期这两个数再谈方案。如果脉冲太窄把信号接到带硬件锁存或中断功能的输入通道。现场没有条件改硬件时也可以用影子位方案输入为TRUE就置位一个影子位程序周期性检测到影子位后计数加1再复位但前提是脉冲宽度大于一个扫描周期否则连影子位都采不到。如果产线速度极高脉冲频率每秒几千个R_TRIG这条路就不该走了直接上高速计数器。5.4 坑四断电重启导致假边界实时时钟电池失效或者PLC没有时间同步源重新上电后系统时间回到初始值小时字段从某个值跳到初始值比较结果变化触发一次假跨小时把统计清零。恢复逻辑建议加上时间有效性判断读到的年份小于某个基准年时不执行清零只等待时间同步完成。统计值本身也要用保持寄存器断电重启后继续原来的累计。5.5 坑五时区切换日的23小时和25小时有些PLC系统配置了时区自动切换在切换日会出现23个小时或者25个小时的情况。小时数值不会简单地从23跳到0可能跳到别的值也可能出现相同小时值连续出现两次。跨小时统计逻辑如果只按“小时值变化”判断切换日的数据会出现缺失或重复。这种场景虽然属于少数但一旦碰上就很头疼。建议使用当日分钟数或者秒数做连续性判断而不是用小时字段的非连续跳变来判断。比如计算当前时间换算成“当日第几分钟”和上一周期的分钟数比较差值大于1就说明出现了时间跳变再结合跳变方向决定是否切换统计段。5.6 坑六T#5S方案的特征现象如果现场已经用T#5S方案部署想确认是否踩了相位坑可以做一个小实验连续记录一周每个小时头尾5秒的产量增量然后把相邻两小时的数据合并起来看。你会发现单小时数据高低起伏但两小时合并总量基本守恒。这是典型的边界窗口归属模糊特征。解决办法就是把边界裁定从T#5S手里拿出来换成系统时间加R_TRIG。改完之后再记录一周单小时数据的起伏会明显减小相邻小时也没有那种“你一多我就一少”的关联性了。这个实验既简单又直观拿来判断问题根源很好用。5.7 排查速查表现象可能原因排查方法相邻小时数据一多一少合并守恒T#5S边界窗口归属模糊统计头尾5秒增量0点数据整体归零清零先于锁存检查锁存清零顺序偶发漏计数脉冲过窄或扫描周期过大测脉宽查扫描周期断电后统计错乱时钟失效或变量非保持查时钟电池、保持属性切换日小时数据重复或缺失时区切换导致小时非连续改用分钟或秒级连续性判断校时后统计被清零时间跳变触发假边界加时间有效性判断我在实际项目里的习惯很简单把“边界裁定”和“数据采集”彻底分开。数据采集该用定时器就用定时器该用中断就用中断但所有涉及“哪个小时的数据”的判断一律交给系统时间加R_TRIG不让普通定时器参与边界裁定。这套逻辑从调试到运维基本没有因为跨小时统计被甲方找过麻烦。最后再分享一个小技巧切换动作最好用边沿触发后的单周期脉冲来做不要在同一个扫描周期里既判断又操作还到处读写扫描周期一旦波动数据错位就会从这种拥挤的操作里冒出来。如果你现在正在为“T#5S还是R_TRIG”纠结我的建议很简单——边界归R_TRIG采样随便选别让5秒定时器做它不擅长的裁判。
RELATED

相关推荐

纯软件STM32入门:零硬件仿真跑通GPIO、中断、定时器与串口

纯软件STM32入门:零硬件仿真跑通GPIO、中断、定时器与串口

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/19 1:10:01
RS485/RS422接口芯片ZCC485选型与硬件设计调试指南

RS485/RS422接口芯片ZCC485选型与硬件设计调试指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/19 1:10:01
基于蒙特卡洛法的电动汽车充电负荷计算与MATLAB仿真实现

基于蒙特卡洛法的电动汽车充电负荷计算与MATLAB仿真实现

简介:基于蒙特卡洛法的电动汽车充电负荷计算MATLAB程序,面向电力系统分析、电动汽车充电负荷预测方向的科研与工程人员,将出行时间、行驶里程、充电模式等不确定因素量化为概率分布,通过反复随机抽样模拟充电行为,以统…

📅 2026/10/19 1:10:01
MORE NEWS

更多资讯

📰

【WebSocket】 WebSocket 是否支持压缩?如何启用 permessage-deflate 扩展?

WebSocket 压缩深度解析:permessage-deflate 扩展的原理与实战应用 用户问题原文:WebSocket 是否支持压缩?如何启用 permessage-deflate 扩展? 在构建直播互动弹幕系统时,我们曾因未启用 WebSocket 压缩导致带宽成本飙升 300%,单场热门直播的 CDN 费用高达数万元。根本原…

📰

【项目】【在线判题系统】c端:用户退出登陆与获取当前用户信息

目录一、退出登录1.1 controller1.2 service二、获取当前用户信息2.1 controller2.2 service三、修改3.1 token创建3.2 参数修改3.3 传参四、前端一、退出登录 与前面的管理员的退出登录没有区别,注销token即可。 1.1 controller oj-modules/oj-friend/src/main/…

📰

【Android面试】RecylerView专题

文章目录一、基础原理与复用缓存1. RecyclerView 与 ListView 的核心区别是什么?2. 四级缓存(mAttachedScrap、mCachedViews、mViewCacheExtension、mRecyclerPool)各自作用、优先级与降级策略,不同滑动 / 刷新场景的命中逻辑&…

📰

从数据到权重:Marigold V2两阶段训练全流程解析(SinkLoss、iREPA与单卡32GB训练秘诀)

【免费下载链接】marigold-v2-0 项目地址: https://ai.gitcode.com/hf_mirrors/huawei-bayerlab/marigold-v2-0 点击查看 免费下载 Marigold V2 是由 HUAWEI Bayer Lab 联合 EPFL 与博洛尼亚大学发布的单目深度估计模型(SIGGRAPH Asia 2026)…

📰

pythonWeb学习记录

FastAPi入门web服务启功1 ——直接点击运行符号(不用重启就能更新代码)2 -——输入 uvicorn main:app --reload(pythonweb的热启动,不用重启就能更新代码)交互文档路径后加/docs路由(Java里的controller&…

📰

EMC整改无效的根源:屏蔽与接地必须做到电连续和低阻抗

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬