ST怎么写计数器累加:IF SensorEdge THEN Count := Count + 1; END_IF;

发布于 2026-03-15 03:33:00 · 浏览 2 次 · 评论 0 条

在结构化文本(ST,Structured Text)编程中实现计数器累加,是电气自动化系统中最基础也最频繁使用的逻辑之一。它广泛应用于PLC(可编程逻辑控制器)控制场景:例如统计输送线上通过的工件数量、记录设备启停次数、累计故障报警频次、或作为步进流程的阶段判据。其核心语句 IF SensorEdge THEN Count := Count + 1; END_IF; 看似简单,但若未深入理解执行机制、边沿检测原理、数据类型约束、并发风险与工程健壮性设计,极易在实际运行中出现漏计、重计、溢出甚至程序崩溃等隐蔽故障。

以下内容不依赖任何特定品牌PLC(如西门子S7-1200/1500、罗克韦尔ControlLogix、倍福TwinCAT),而是紧扣IEC 61131-3国际标准,逐层拆解该语句从语法到工程落地的全部关键环节,提供可直接复用的实操方案。


一、语句语法解析:每个符号都承担明确语义

IF SensorEdge THEN Count := Count + 1; END_IF;

这是一条完整的ST条件赋值语句,严格遵循IEC 61131-3语法规范。我们逐词解析:

  1. IF:条件判断关键字,后接布尔表达式。
  2. SensorEdge:一个布尔型(BOOL)变量,其值必须为 TRUEFALSE。它不能是传感器原始信号(如DI_01)本身,而必须是经边沿检测处理后的“上升沿标志位”。这是初学者最常踩的坑——误将物理输入点直接用于计数判断。
  3. THEN:关键字,表示当条件为 TRUE 时执行后续语句。
  4. Count := Count + 1;
    • := 是ST中的赋值运算符(非等号 =),表示将右侧计算结果写入左侧变量;
    • Count 是被累加的整数变量,必须声明为整型(如 INTDINTUINT);
    • Count + 1 是算术表达式,要求 Count 支持加法运算(即不能是 BOOLSTRING)。
  5. END_IF;:语句块结束标记,分号 ; 不可省略。

✅ 正确示例(变量已正确定义):

VAR
    SensorRaw : BOOL;      // 传感器原始输入(硬件映射)
    SensorEdge : BOOL;     // 上升沿检测输出(软件生成)
    Count : DINT := 0;      // 计数器,初始值设为0更安全
END_VAR

// 边沿检测逻辑(必须独立存在)
SensorEdge := SensorRaw AND NOT SensorRaw[1];

// 计数逻辑(本行独立存在)
IF SensorEdge THEN Count := Count + 1; END_IF;

❌ 典型错误(导致严重缺陷):

  • IF DI_01 THEN Count := Count + 1; END_IF;
    → 错在 DI_01 是持续有效的电平信号,一个物料通过时可能保持 TRUE 多个扫描周期,造成一次触发多次累加。
  • Count = Count + 1;
    → 错在使用 =(比较运算符),语句变为恒假判断,无赋值效果。
  • Count := Count + 1.0;
    → 错在混合整型与实型(REAL),多数PLC编译器报错或隐式转换引发精度丢失。

二、边沿检测:计数准确性的唯一前提

SensorEdge 不是凭空产生的变量,它必须通过边沿检测逻辑从原始输入信号中提取。IEC 61131-3不提供内置“上升沿指令”(如STEP 7的R_TRIG),因此需手动实现。核心原理是:利用前一扫描周期的信号状态与当前状态做逻辑比对

标准上升沿检测代码(推荐)

VAR
    SensorRaw : BOOL;
    SensorRaw_Prev : BOOL;  // 存储上一周期值,需保持(RETAIN可选)
    SensorEdge : BOOL;
END_VAR

// 在每次扫描周期开头执行(通常放在主程序POU首行)
SensorEdge := SensorRaw AND NOT SensorRaw_Prev;
SensorRaw_Prev := SensorRaw;  // 立即更新历史值,供下一周期使用
  • 执行顺序不可颠倒:必须先计算 SensorEdge,再更新 SensorRaw_Prev。若顺序反了,则 SensorEdge 始终为 FALSE
  • SensorRaw_Prev 必须是保持型变量:否则每次扫描重启时被清零,导致无法记忆上一周期状态。在大多数PLC中,声明时添加 RETAIN 属性(如 SensorRaw_Prev : BOOL RETAIN;)即可;若不支持,需确保其位于全局变量区或带保持属性的数据块中。

更健壮的工业级写法(防抖+防误触发)

实际现场中,机械振动、接触器弹跳、线路干扰会导致传感器信号产生毫秒级抖动,可能生成多个虚假边沿。加入软件滤波:

VAR
    SensorRaw : BOOL;
    FilterTimer : TON;           // 定时器,类型TON(On-Delay Timer)
    SensorStable : BOOL;         // 滤波后稳定信号
    SensorEdge : BOOL;
    SensorRaw_Prev : BOOL RETAIN;
END_VAR

// 1. 信号滤波:延时确认有效
FilterTimer(IN := SensorRaw, PT := T#20ms);  // 20ms去抖
SensorStable := FilterTimer.Q;

// 2. 上升沿检测(基于滤波后信号)
SensorEdge := SensorStable AND NOT SensorRaw_Prev;
SensorRaw_Prev := SensorStable;

⚠️ 注意:T#20ms 是时间常量,格式为 T#<数值><单位>,单位支持 mssmhTON 是标准定时器功能块,所有符合IEC 61131-3的PLC均支持。


三、计数器变量声明:类型、范围与初始化

Count 的声明直接影响系统长期运行的可靠性。

类型 范围 适用场景 风险提示
INT −32,768 到 +32,767 小批量计数(如单班次零件数≤1万) 溢出后变为−32,768(有符号整数回绕),导致逻辑反转
DINT −2,147,483,648 到 +2,147,483,647 主流推荐,覆盖绝大多数工业场景 占用内存略大,但现代PLC无压力
UDINT 0 到 4,294,967,295 仅需非负计数,且需更大范围(如总产量统计) 若误赋负值会溢出为极大正数

强制实践规范

  • 始终显式初始化Count : DINT := 0;
    避免PLC上电后变量为随机值。
  • 禁止使用 BYTEWORD:范围过小(255 / 65535),且部分PLC对字节型算术支持不一致。
  • 不推荐 REAL:浮点数存在精度误差(如 123456789.0 + 1.0 可能仍显示 123456789.0),且运算速度慢。

四、多任务环境下的并发安全:避免竞态条件

在具有多任务(Task)或循环中断(Cyclic Interrupt)的PLC中,若多个任务同时读写 Count,可能发生竞态条件(Race Condition)
例如,任务A读取 Count=100 → 任务B也读取 Count=100 → A计算 100+1=101 并写入 → B计算 100+1=101 并写入 → 实际只累加1次,而非2次。

解决方案:原子操作或临界区保护

  1. 首选:使用PLC厂商提供的原子计数器功能块
    如西门子 CTU(Count Up)、罗克韦尔 CTU 指令,其内部已实现硬件级保护,无需额外同步。

  2. 通用ST方案:禁用中断 + 手动临界区(适用于无专用功能块的PLC)

    VAR
        Count : DINT := 0;
        CriticalSectionLock : BOOL := FALSE;  // 互斥锁标志
    END_VAR
    
    // 在需要累加处(确保此段代码不被中断打断)
    IF NOT CriticalSectionLock THEN
        CriticalSectionLock := TRUE;
        Count := Count + 1;
        CriticalSectionLock := FALSE;
    END_IF;

    ⚠️ 此方法依赖PLC是否支持禁用中断。更稳妥做法是将全部计数相关逻辑集中在一个高优先级、无中断干扰的任务中执行。


五、工程增强:复位、限值、存储与诊断

生产环境中,单一累加远远不够。以下是必须集成的增强功能:

1. 安全复位机制

IF ResetButton THEN
    Count := 0;
    // 同时复位边沿检测历史
    SensorRaw_Prev := FALSE;
END_IF;
  • 务必同步复位 SensorRaw_Prev,否则下次触发可能立即生成边沿。

2. 计数上限保护(防溢出+工艺约束)

IF SensorEdge THEN
    IF Count < 100000 THEN  // 设定工艺上限
        Count := Count + 1;
    ELSE
        Alarm_MaxCountReached := TRUE;  // 触发报警
    END_IF;
END_IF;

3. 断电保持(掉电不丢数)

  • Count 变量声明于带保持属性的数据块(DB) 中;
  • 或使用PLC的 RETAIN 关键字:Count : DINT RETAIN := 0;
  • 对于S7-1200/1500,还需在DB属性中勾选“优化的块访问”并设置保持性。

4. 运行状态诊断

// 检测计数器是否“卡死”(长时间无变化)
CountWatchdogTimer(IN := (Count <> Count_Prev), PT := T#30s);
IF CountWatchdogTimer.Q THEN
    Alarm_CountStuck := TRUE;
END_IF;
Count_Prev := Count;  // 每周期更新

六、完整可运行示例(ST程序段)

以下为一个可直接粘贴至TIA Portal、Codesys或GX Works3的完整计数模块(含注释):

// =============================================
// 模块名称:ProductCounter_V2
// 功能:带滤波、保持、限值、诊断的工件计数器
// =============================================
PROGRAM ProductCounter_V2
VAR
    // --- 输入信号 ---
    SensorInput : BOOL;          // 硬件输入点(如I0.0)

    // --- 内部变量 ---
    SensorFiltered : BOOL;
    SensorPrev : BOOL RETAIN;
    SensorRisingEdge : BOOL;
    Count : DINT RETAIN := 0;
    CountPrev : DINT RETAIN := 0;

    // --- 滤波定时器 ---
    FilterTON : TON;

    // --- 诊断定时器 ---
    WatchdogTON : TON;

    // --- 输出/报警 ---
    CountValue : DINT;           // 供HMI读取的镜像值
    AlarmMaxReached : BOOL;
    AlarmStuck : BOOL;

    // --- 控制信号 ---
    ResetCmd : BOOL;
END_VAR

// ====== 主逻辑执行顺序(自上而下)======
// 1. 信号滤波(20ms防抖)
FilterTON(IN := SensorInput, PT := T#20ms);
SensorFiltered := FilterTON.Q;

// 2. 上升沿检测
SensorRisingEdge := SensorFiltered AND NOT SensorPrev;
SensorPrev := SensorFiltered;

// 3. 计数逻辑(带限值保护)
IF SensorRisingEdge THEN
    IF Count < 999999 THEN
        Count := Count + 1;
    ELSE
        AlarmMaxReached := TRUE;
    END_IF;
END_IF;

// 4. 复位逻辑(下降沿触发,防误操作)
IF ResetCmd AND NOT ResetCmd[1] THEN  // 使用ResetCmd边沿
    Count := 0;
    SensorPrev := FALSE;
    AlarmMaxReached := FALSE;
END_IF;
ResetCmd[1] := ResetCmd;  // 更新ResetCmd历史位

// 5. 卡滞诊断(30秒无变化即报警)
WatchdogTON(IN := (Count <> CountPrev), PT := T#30s);
IF WatchdogTON.Q THEN
    AlarmStuck := TRUE;
ELSE
    AlarmStuck := FALSE;
END_IF;
CountPrev := Count;

// 6. 输出镜像(供其他POU安全读取)
CountValue := Count;

七、调试与验证要点

  • 仿真测试:在PLC编程软件中启用强制(Force)功能,手动切换 SensorInput 电平,观察 SensorRisingEdge 是否仅在上升沿瞬间为 TRUE(持续1个扫描周期)。
  • 监控变量:同时打开 SensorInputSensorFilteredSensorRisingEdgeCount 四个变量在线监控,验证滤波延迟与边沿对应关系。
  • 压力测试:用高速脉冲发生器(≥100Hz)注入信号,确认无漏计、无重计。
  • 掉电测试:强制断电再上电,检查 Count 值是否保持不变。

IF SensorEdge THEN Count := Count + 1; END_IF; 不是一行孤立的代码,而是一个精密机电系统中数字世界的“心跳捕捉器”。它的每一处细节——从布尔变量的边沿来源,到整数类型的溢出边界,再到多任务下的写入安全——都直指自动化系统的鲁棒性本质。把这一行写对,不是编程的终点,而是让机器真正可信运转的起点。

评论 (0)

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

扫一扫,手机查看

扫描上方二维码,在手机上查看本文