梯形图编程中,CNTR(计数器)指令的复位条件若与计数输入存在时序重叠,极易引发复位信号与计数脉冲在同一个扫描周期内同时有效,造成计数值跳变——例如本应从 99 → 0 的正常复位,却偶然出现 99 → 100 → 0 或 99 → 0 → 1 等异常跃变。该现象本质是复位条件竞争(Reset Race Condition),在PLC扫描机制下无法通过单纯增加延时或调整触点顺序彻底规避。以下为可直接落地、无需修改硬件、不依赖特定品牌PLC的通用消除方案。
一、先确认你是否真的遇到了复位条件竞争
不是所有计数值“跳变”都源于此。请按顺序执行以下诊断步骤:
-
启用PLC在线监控,将
CNTR指令的当前值寄存器(如CNTR.V)、复位线圈(如CNTR.R对应的软元件)、计数输入触点(如I0.1)全部加入变量表,并设置采样周期 ≤ 10 ms(远小于PLC扫描周期,确保捕获单个扫描内的状态变化)。 -
触发一次计数过程,观察连续3~5次复位动作发生时的时序快照。重点关注以下三组信号在同一PLC扫描周期内的逻辑电平组合:
- 计数输入触点
X:ON(上升沿或持续ON均可能触发计数) - 复位线圈
R:ON - 当前计数值
V:是否等于预设值PV(即复位阈值)
- 计数输入触点
-
若发现任一扫描周期内同时满足:
X == ONR == ONV == PV
则100%确认存在复位条件竞争。此时PLC在该扫描周期内会先执行计数(
V = V + 1),再执行复位(V = 0),但因内部执行顺序不可控或受优化影响,部分PLC可能先清零再加1,导致V在一个扫描内经历两次变更。
✅ 正确理解:这不是PLC“故障”,而是梯形图逻辑在扫描周期边界处的确定性行为缺陷。IEC 61131-3标准未规定同一网络中多个输出线圈的执行先后顺序,厂商实现各异,故必须通过逻辑重构规避。
二、根本解决原理:分离“判断”与“动作”,用双锁存机制切断竞争路径
核心思想:绝不允许复位信号 R 和计数输入 X 在同一逻辑网络中直接驱动同一计数器。需将“是否达到复位条件”的判断,与“何时执行复位”的动作,在时间上强制错开至少一个扫描周期。
具体拆解为两个独立环节:
- 环节A(条件锁存):在计数值
V首次等于PV的扫描周期,仅置位一个专用锁存标志M_RST_TRIG,且该标志一旦置位,必须保持至复位完成。 - 环节B(动作执行):在
M_RST_TRIG == ON的下一个扫描周期,才真正激活CNTR.R;并在CNTR.R执行后,立即清除M_RST_TRIG。
这样,X 和 R 永远不会在同一扫描中同时为 ON——因为 R 的激活严格滞后于 V == PV 的判定。
三、四步实操:手把手搭建抗竞争计数器网络
以下以通用梯形图符号描述(适配西门子S7-1200/1500、三菱FX5U、欧姆龙NJ/NX系列等主流PLC)。所有元件名使用标准标识,括号内注明典型地址示例。
步骤1:声明必要软元件(全局DB或M区)
| 元件类型 | 名称 | 地址示例 | 说明 |
|---|---|---|---|
INT |
CNTR_PV |
DB1.DBW2 |
预设值(如100) |
INT |
CNTR_V |
DB1.DBW4 |
当前值(CNTR指令自动更新) |
BOOL |
CNT_INPUT |
I0.1 |
计数脉冲输入(建议接上升沿触点) |
BOOL |
M_RST_TRIG |
M10.0 |
复位触发锁存标志(关键!) |
BOOL |
M_RST_EXEC |
M10.1 |
复位执行标志(单周期脉冲) |
⚠️ 注意:
CNT_INPUT必须使用硬件滤波后的上升沿检测(如P_TRIG功能块),禁止直接用常开触点。否则机械抖动或噪声会伪造多个计数脉冲,掩盖真实问题。
步骤2:构建“条件锁存”网络(独立梯级)
|----[ CNT_INPUT ]-------------------( SET )----[ M_RST_TRIG ]
| |
|----[ CNTR_V == CNTR_PV ]-----------|
- 解释:当
CNT_INPUT为ON且CNTR_V等于CNTR_PV时,SET线圈激活,M_RST_TRIG置位并自锁(梯形图中SET具备锁存特性)。 - 关键设计:此处
CNT_INPUT触点必须与CNTR_V == CNTR_PV串联。这意味着只有在脉冲到来的同一扫描内恰好V达到PV,才会触发锁存。这正是我们要捕获的“临界点”。
步骤3:构建“动作执行”网络(下一梯级,严格隔离)
|----[ M_RST_TRIG ]--------------------( R )----[ M_RST_EXEC ]
| |
|----[ NOT M_RST_EXEC ]-------------------------( SET )----[ CNTR.R ]
- 解释:
- 第一行:
M_RST_TRIG为ON时,将M_RST_EXEC复位(R线圈)。注意这是清除操作,目的是让M_RST_EXEC在后续扫描中能重新置位。 - 第二行:
M_RST_EXEC为OFF时(即上一扫描未执行过复位),SET线圈激活CNTR.R。 - 效果:
CNTR.R仅在M_RST_TRIG为ON的第二个扫描周期被激活,且只维持一个扫描周期(因下一扫描M_RST_EXEC变为ON,第二行条件失效)。
- 第一行:
步骤4:重构原始CNTR指令(关键!)
原始写法(❌ 危险):
|----[ CNT_INPUT ]----[ CNTR_PV ]----( CNTR )
改为(✅ 安全):
|----[ CNT_INPUT ]----[ NOT M_RST_TRIG ]----( CNTR )
- 解释:在
M_RST_TRIG为ON(即已判定需复位)后,立即禁止后续计数。这防止在M_RST_TRIG == ON到CNTR.R == ON的一个扫描延迟期内,新的脉冲再次进入计数器,导致V超调(如100 → 101)。 - 同时,
CNTR.R线圈由步骤3独立控制,不再与CNT_INPUT共存于同一网络。
四、验证效果:用三组数据对比说明
假设 CNTR_PV = 3,输入脉冲序列为 ON, ON, ON, ON(第4个脉冲应触发复位):
| 扫描周期 | CNT_INPUT |
CNTR.V(原逻辑) |
CNTR.V(新逻辑) |
关键状态 |
|---|---|---|---|---|
| 1 | ON |
1 |
1 |
— |
| 2 | ON |
2 |
2 |
— |
| 3 | ON |
3 |
3 |
M_RST_TRIG = ON(步骤2触发) |
| 4 | ON |
0 或 4(跳变!) |
3(被禁止计数) |
CNTR.R = ON(步骤3执行),M_RST_EXEC = ON |
| 5 | OFF |
0 |
0 |
CNTR.R 已完成复位,M_RST_TRIG 被步骤3第二行隐含清除(因 CNTR.R 执行后 CNTR.V=0 ≠ PV,且无新触发) |
✅ 结果:新逻辑下,
CNTR.V严格遵循0→1→2→3→0,无任何中间跳变。第4周期因计数被禁,V停留在3;第5周期R生效,V清零。
五、进阶加固:应对多计数器协同与断电保持
场景1:同一设备有多个CNTR需同步复位(如包装机的袋长计数+热封次数)
- 禁止为每个计数器单独做上述四步——会导致复位时刻微秒级偏移,破坏同步性。
- 正确做法:共用一套
M_RST_TRIG/M_RST_EXEC逻辑,但为每个CNTR单独添加NOT M_RST_TRIG使能条件:|----[ CNT_INPUT_1 ]----[ NOT M_RST_TRIG ]----( CNTR_1 ) |----[ CNT_INPUT_2 ]----[ NOT M_RST_TRIG ]----( CNTR_2 ) - 复位时,所有
CNTR.R线圈由同一M_RST_EXEC控制,确保原子性。
场景2:计数值需断电保持(如累计运行小时)
- 将
CNTR.V存储到带保持属性的DB块(如S7的DBx.DBW4设为Retentive),但绝对不可对M_RST_TRIG和M_RST_EXEC做保持。 - 理由:断电重启后,若
M_RST_TRIG仍为ON,将立即触发复位,丢失已计数值。 - 解决方案:在启动组织块(OB100)中插入初始化网络:
|----[ SM0.1 ]----( R )----[ M_RST_TRIG ] | +----( R )----[ M_RST_EXEC ]SM0.1是CPU上电第一个扫描周期为ON的特殊标志位,确保每次上电后锁存标志清零。
六、为什么不用定时器延时?——揭露常见误区
工程师常尝试如下方案(❌ 无效):
|----[ CNTR.V == PV ]----( TON )----[ T1.Q ]----( CNTR.R )
其中 T1 设定时间为 100 ms。
失败原因:
TON定时器本身也受扫描周期影响,其Q输出并非精确100 ms,而是100 ms ± 1个扫描周期;- 更致命的是:若
CNTR.V == PV持续多个扫描周期(如因输入触点粘连),TON会反复启停,Q输出抖动; - 根本未解决
CNT_INPUT与CNTR.R的同周期冲突——只要CNT_INPUT在T1.Q == ON时再次出现,竞争依旧。
结论:延时是“掩耳盗铃”,锁存+错时才是“釜底抽薪”。
七、代码级验证模板(SCL语言,用于自动化测试)
将以下SCL代码放入测试功能块,可批量验证逻辑鲁棒性:
// 输入模拟:按需切换CNT_INPUT电平
IF Sim_Pulse_Count > 0 THEN
CNT_INPUT := TRUE;
Sim_Pulse_Count := Sim_Pulse_Count - 1;
ELSE
CNT_INPUT := FALSE;
END_IF;
// 核心逻辑(与梯形图完全等效)
IF CNT_INPUT AND (CNTR_V = CNTR_PV) THEN
M_RST_TRIG := TRUE;
END_IF;
IF M_RST_TRIG THEN
IF NOT M_RST_EXEC THEN
CNTR_R := TRUE; // 触发复位
M_RST_EXEC := TRUE;
END_IF;
ELSE
CNTR_R := FALSE;
M_RST_EXEC := FALSE;
END_IF;
// 计数使能:仅在未触发复位时允许
IF CNT_INPUT AND NOT M_RST_TRIG THEN
CNTR_V := CNTR_V + 1;
END_IF;
// 复位动作(在CNTR_R为TRUE的扫描周期执行)
IF CNTR_R THEN
CNTR_V := 0;
END_IF;
运行时注入1000次随机脉冲序列,监控 CNTR_V 最大值。合格标准:最大值恒为 CNTR_PV,且复位后必为 0,无其他值出现。
八、最后检查清单(部署前逐项打钩)
- [ ]
CNT_INPUT已通过P_TRIG或硬件滤波,确认无抖动; - [ ]
CNTR.V和CNTR_PV数据类型一致(均为INT或DINT),避免比较异常; - [ ]
M_RST_TRIG和M_RST_EXEC使用非保持型布尔量(勿勾选Retentive); - [ ] 所有
CNTR指令的R线圈均由M_RST_EXEC统一驱动,无任何直接触点连接; - [ ] 在首次上线前,用强制功能将
CNTR.V设为CNTR_PV - 1,手动触发一个脉冲,用监控确认V是否严格变为0且无跳变。
完成以上,即可永久消除CNTR复位跳变。

暂无评论,快来抢沙发吧!