当前位置: 首页 > web >正文

西门子PLC结构化编程_水处理系统水泵多备多投

文章目录

  • 前言
  • 一、功能概述
  • 二、程序编写
    • 1. 需求分析
    • 2. 编写运行时间累计功能块
    • 3. 创建自定义数据类型
      • 1. 时间排序数据类型
      • 2. 多备多投数据类型
      • 3. 多备多投切换数据类型
    • 4. 编程
      • 1. 创建DB数据块
        • 1. 多备多投数据块
        • 2. 多备多投切换数据块
      • 2. 创建FB功能块
  • 三、程序调用
  • 总结


前言

在之前的文章中,我们讨论了通过SCL语言实现电机主备互投《西门子PLC常用底层逻辑块分享_电机主备互投》,和多台电机按时间排序均衡运行《电机主备互投功能优化_多台设备均衡运行》的方法。
但实际现场中,经常会遇见4用1备、3用2备、2用2备、2用3备等复杂情况,如果对每种情况分别编程,会使程序过于冗杂,故本文提供一种多备多投的实现方法,假设现场有5台水泵,可根据现场要求,自由选择主动泵数量和备用泵数量,实现主备泵自由切换。


一、功能概述

假设有5台水泵,5台水泵的运行逻辑如下:

  1. 具有以下几种情况:4用1备、2用2备、2用3备、3用2备、1用1备、1用4备等任意组合;
  2. 主泵同时启动,触发切换命令后,按照运行时间由小到大的顺序切换备用泵或主泵;
  3. 每台水泵都有故障信号,当某台泵出现故障或运行信号丢失时,能自动切换到其它泵;
  4. 故障出现后,水泵的运行时间需要保持不变,不能丢失;
  5. 每台水泵有3种状态:1. 作为主泵;2. 作为备用泵;3. 不投用;
  6. 有故障的水泵自动停止,并且不允许启动,直到故障解除;
  7. 可选择投用或不投用“多备多投”功能。

二、程序编写

1. 需求分析

  1. 参考文章《电机主备互投功能优化_多台设备均衡运行》的思路,根据5台电机的运行时间,计算出由小到大对应的序号,遍历1-5,每次启动都启动序号1对应的电机;
  2. 当水泵处于故障状态、不投用状态、运行状态时,可将该水泵的运行时间设置为最大值,即可跳过该水泵,启动下一台。

2. 编写运行时间累计功能块

可参考文章西门子PLC常用底层逻辑块分享_设备运行时间统计。
根据该文章可编写FC块“运行时间累计”,并新建数据类型“时钟”。具体步骤这里不再赘述。

3. 创建自定义数据类型

1. 时间排序数据类型

在这里插入图片描述
图1

2. 多备多投数据类型

在这里插入图片描述
图2

3. 多备多投切换数据类型

在这里插入图片描述
图3

4. 编程

1. 创建DB数据块

1. 多备多投数据块

在这里插入图片描述

图4

2. 多备多投切换数据块

在这里插入图片描述
图5

2. 创建FB功能块

新建FB块“水泵多备多投”,添加如下变量。
在这里插入图片描述
图6
编写如下程序:

REGION 功能已启用、已停止IF #PumpSwitch.StaCmd THEN#PumpSwitch.Running := 1;ELSIF#PumpSwitch.StpCmd THEN#PumpSwitch.Running := 0;END_IF;END_REGIONREGION 调用程序"运行时间累计"(Start := #PumpControl[1].Run,Clock_1Hz := #Clock_1Hz,"Time" := #PumpControl[1].RunTime);"运行时间累计"(Start := #PumpControl[2].Run,Clock_1Hz := #Clock_1Hz,"Time" := #PumpControl[2].RunTime);"运行时间累计"(Start := #PumpControl[3].Run,Clock_1Hz := #Clock_1Hz,"Time" := #PumpControl[3].RunTime);"运行时间累计"(Start := #PumpControl[4].Run,Clock_1Hz := #Clock_1Hz,"Time" := #PumpControl[4].RunTime);"运行时间累计"(Start := #PumpControl[5].Run,Clock_1Hz := #Clock_1Hz,"Time" := #PumpControl[5].RunTime);END_REGIONREGION 计算运行时间FOR #PumpSwitch.N[0] := 1 TO 5 DO#PumpSwitch.Set[#PumpSwitch.N[0]]."Time" :=#PumpControl[#PumpSwitch.N[0]].RunTime.Day * 86400 +#PumpControl[#PumpSwitch.N[0]].RunTime.Hour * 60 * 60 +#PumpControl[#PumpSwitch.N[0]].RunTime.Min * 60 +#PumpControl[#PumpSwitch.N[0]].RunTime.Second; // 程序判断用时间#PumpSwitch.TimeOut[#PumpSwitch.N[0]] := #PumpSwitch.Set[#PumpSwitch.N[0]]."Time"; // 实际显示时间END_FOR;END_REGIONREGION 计算主泵、备泵、运行泵数量#NumMinPump := 0;FOR #PumpSwitch.N[1] := 1 TO 5 DOIF #PumpControl[#PumpSwitch.N[1]].ControlWord = 1 THEN#NumMinPump := #NumMinPump + 1;END_IF;END_FOR;#PumpSwitch.NumMinPump := #NumMinPump; // 计算主泵数量#NumBackupPump := 0;FOR #PumpSwitch.N[2] := 1 TO 5 DOIF #PumpControl[#PumpSwitch.N[2]].ControlWord = 2 THEN#NumBackupPump := #NumBackupPump + 1;END_IF;END_FOR;#PumpSwitch.NumBackupPump := #NumBackupPump; // 计算备泵数量#NumRun := 0;FOR #PumpSwitch.N[3] := 1 TO 5 DOIF #PumpControl[#PumpSwitch.N[3]].Run THEN#NumRun := #NumRun + 1;END_IF;END_FOR;REGION 泵切换命令IF #NumRun < #PumpSwitch.#NumRun THEN#SwitchPump := 1;ELSE#SwitchPump := 0;END_IF;#SwitchPumpR_TRIG(CLK := #SwitchPump); // 如果此刻运行泵数量小于上一时刻运行泵数量,则说明有泵停机,触发泵切换信号END_REGION#PumpSwitch.#NumRun := #NumRun; // 计算运行泵数量REGION 运行泵数量不足报警IF (#PumpSwitch.#NumRun < #PumpSwitch.NumMinPump) AND #PumpSwitch.Running THEN#PumpSwitch.NumFlt := 1;ELSE#PumpSwitch.NumFlt := 0;END_IF;END_REGIONEND_REGIONREGION 无设备运行时,复位启动命令IF #PumpSwitch.#NumRun = 0 THENFOR #PumpSwitch.N[6] := 1 TO 5 DO#PumpSwitch.Pump[#PumpSwitch.N[6]] := 0;END_FOR;END_IF;END_REGIONREGION 故障停机FOR #PumpSwitch.N[12] := 1 TO 5 DOIF #PumpControl[#PumpSwitch.N[12]].Flt OR(#PumpControl[#PumpSwitch.N[12]].ControlWord = 3)THEN#PumpSwitch.Pump[#PumpSwitch.N[12]] := 0;END_IF;END_FOR;END_REGIONREGION 按时间顺序计算序号REGION 故障处理FOR #PumpSwitch.N[8] := 1 TO 5 DOIF #PumpControl[#PumpSwitch.N[8]].Flt OR(#PumpControl[#PumpSwitch.N[8]].ControlWord = 3) OR#PumpControl[#PumpSwitch.N[8]].RunTHEN#PumpSwitch.Set[#PumpSwitch.N[8]]."Time" := 4294967295; // UDInt的最大值为4294967295END_IF;END_FOR; // 将故障泵和没有投用和正在运行的泵时间设为最大值END_REGION// 初始化序号数组FOR #PumpSwitch.I := 1 TO 5 DO#PumpSwitch.Set[#PumpSwitch.I].Sequence := 1; // 初始序号为1END_FOR;// 计算每个元素的序号FOR #PumpSwitch.I := 1 TO 5 DOFOR #PumpSwitch.J := 1 TO 5 DOIF #PumpSwitch.Set[#PumpSwitch.J]."Time" < #PumpSwitch.Set[#PumpSwitch.I]."Time" THEN#PumpSwitch.Set[#PumpSwitch.I].Sequence := #PumpSwitch.Set[#PumpSwitch.I].Sequence + 1; // 遇到更小的数,序号增加ELSIF(#PumpSwitch.Set[#PumpSwitch.J]."Time" = #PumpSwitch.Set[#PumpSwitch.I]."Time") AND (#PumpSwitch.J < #PumpSwitch.I) THEN#PumpSwitch.Set[#PumpSwitch.I].Sequence := #PumpSwitch.Set[#PumpSwitch.I].Sequence + 1; // 处理相同数值的情况,按顺序递增序号END_IF;END_FOR;END_FOR;FOR #PumpSwitch.N[13] := 1 TO 5 DO// 将启动顺序放入存储区,便于上位机显示#PumpSwitch.SequenceOut[#PumpSwitch.N[13]] := #PumpSwitch.Set[#PumpSwitch.N[13]].Sequence;END_FOR;END_REGIONREGION 根据时间顺序切换IF NOT #PumpSwitch.StpCmd THENCASE #PumpSwitch.Step OF0:IF #PumpSwitch.StaCmd AND #PumpSwitch.EnSwitch THEN#PumpSwitch.Step := 1;END_IF;#PumpSwitch.Pump[1] := 0;#PumpSwitch.Pump[2] := 0;#PumpSwitch.Pump[3] := 0;#PumpSwitch.Pump[4] := 0;#PumpSwitch.Pump[5] := 0;1:FOR #PumpSwitch.N[7] := 1 TO 5 DOIF #PumpControl[#PumpSwitch.N[7]].ControlWord = 1 THEN#PumpSwitch.Pump[#PumpSwitch.N[7]] := 1;END_IF;END_FOR; // 所有主泵同时启动#PumpSwitch.Step := 2;2:REGION 触发泵切换命令IF #SwitchPumpR_TRIG.Q AND #PumpSwitch.EnSwitch THENFOR #PumpSwitch.N[9] := 1 TO 5 DOIF (#PumpSwitch.SequenceOut[#PumpSwitch.N[9]] = 1) ANDNOT #PumpControl[#PumpSwitch.N[9]].Flt ANDNOT #PumpControl[#PumpSwitch.N[9]].Run ANDNOT (#PumpControl[#PumpSwitch.N[9]].ControlWord = 3) THENEXIT; // 找到启动顺序为1对应的泵的序号#PumpSwitch.N[9]END_IF;END_FOR;#PumpSwitch.Pump[#PumpSwitch.N[9]] := 1;END_IF;END_REGIONEND_CASE;ELSE#PumpSwitch.Pump[1] := 0;#PumpSwitch.Pump[2] := 0;#PumpSwitch.Pump[3] := 0;#PumpSwitch.Pump[4] := 0;#PumpSwitch.Pump[5] := 0;#PumpSwitch.N[9] := 0;#PumpSwitch.Step := 0;#PumpSwitch.EnSwitch := 0;END_IF;END_REGIONREGION 赋值FOR #PumpSwitch.N[11] := 1 TO 5 DOIF #PumpSwitch.Clear THEN#PumpControl[#PumpSwitch.N[11]].RunTime.Clear := 1;ELSE#PumpControl[#PumpSwitch.N[11]].RunTime.Clear := 0;END_IF;END_FOR;IF NOT "AlwaysFALSE" THEN#PumpSwitch.StaCmd := 0;#PumpSwitch.StpCmd := 0;#PumpSwitch.Clear := 0;END_IF;END_REGION

三、程序调用

在主程序中调用FB块“水泵多备多投”。
在这里插入图片描述
图7
程序分析:

  1. 实际应用时,#PumpControl[1].Run - #PumpControl[5].Run关联水泵1 - 5的运行反馈信号,#PumpSwitch.Pump[1] - #PumpSwitch.Pump[5]关联水泵1 - 5的启动命令,#PumpControl[1].Flt - #PumpControl[5].Flt关联水泵1 - 5的故障信号;
  2. 变量EnSwitch作为使能信号,只有EnSwitch置1时,功能才会正常投用,否则就算按下StaCmd启动按钮也不会实现主备互投;
  3. EnSwitch复位后,主备互投功能取消,此时可自由启停任意水泵;
  4. 按下StpCmd停止按钮后,所有水泵停止运行,EnSwitch自动复位;
  5. 当实际运行泵的数量小于应该运行的数量,会触发NumFlt运行泵数量不足报警,提醒操作员及时处理故障;
  6. 可在上位机画面中为每台泵添加“选择框控件”,关联ControlWord变量,ControlWord=1表示作为主泵,ControlWord=2表示作为备泵,ControlWord=3表示该泵不投用;
  7. 程序会根据选择的主泵数量和备泵数量,自动判断当前的主备互投模式。

总结

本文提供了一种结构化的水泵多备多投方法,可作为标准块应用于生产实际中。

http://www.xdnf.cn/news/2728.html

相关文章:

  • Linux中的shell脚本练习
  • 在线图书管理系统的结构化需求分析过程讲解
  • 【Git】项目多个分支开发、维护与优化处理 -- 还未实测 记录初
  • PCL实时动态加载显示点云功能以及laslib配置
  • 使用Python在excel里创建柱状图
  • 如何搭建spark yarn 模式的集群集群
  • uniapp利用生命周期函数实现后台常驻示例
  • auto(x) decay copy
  • 一键叠图工具
  • 浏览器存储
  • 服务器文件同步工具有哪些?
  • 经典数仓架构深度解析与演进:从离线处理到新型架构对比
  • 实战篇:在QEMU中编写和调试VHost/Virtio驱动
  • 从数据到决策:如何使用Python进行自动驾驶数据分析
  • 利用Python打印有符号十进制数的二进制原码、反码、补码
  • 问题 ERROR: for jobmanager ‘ContainerConfig‘ 原因及解决
  • ComfyUI 学习笔记:安装篇及模型下载
  • 2025-4-27-C++ 学习 数组(2)
  • springboot项目文件上传到服务器本机,返回访问地址
  • 高级数据库对象全面解析:视图、存储过程与触发器
  • Express.js 框架教程:从入门到精通
  • 【“星瑞” O6 评测】 — llm CPU部署对比高通骁龙CPU
  • T-BOX应用 NXP S32K148控芯片搭配 SD NAND(嵌入式SD卡)存储的完美结合
  • 设计模式(状态模式)
  • 【力扣刷题实战】丢失的数字
  • vue代码规范管理
  • BeeWorks企业内部即时通讯软件支持国产化,已在鸿蒙系统上稳定运行
  • 【Altium】自定义菜单显示名称
  • C++23 std::bind_back:一种调用包装器 (P2387R3)
  • Matlab自学笔记五十二:变量名称:检查变量名称是否存在或是否与关键字冲突