技术论坛

 回复:有奖【微分享】“说说我用过的功能块”

返回主题列表
作者 主题

总坛主
西门子官方工程师西门子官方工程师

经验值:23725
发帖数:3679
精华帖:8
楼主    2014-03-10 10:47:41
主题:有奖【微分享】“说说我用过的功能块”
公布获奖结果:
  • 最受欢迎【微分享】:
  • 移动电源一个
    @剑忠 精华4星 鲜花数5

  • 最佳方案:
  • 移动电源一个
    @古月游风 精华1星 鲜花数4

  • 潜力无限:
  • ipad包一个
    @信仰 精华3星 鲜花数5
    @szy868 精华1星 鲜花数1

  • 精彩分享:
  • 50金币
    @zhigao
    @-我心飞翔-
    @迷失中原
    @xkqxwhz
    @一直被模仿
    @纯属虚构
    @依然

  • 热心分享:
  • 双倍积分和金币
    所有参与探讨的网友

    实物奖品获得者将会收到管理员的获奖邮件,通过邮件领取奖品。金币和积分奖励将在2个工作日内添加至您的账户。如有任何问题,请您联系管理员:ad.cs3.slc@siemens.com

    再次感谢大家的全力支持,期待各位网友能在西门子技术论坛相互切磋,共同成长!
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    “同是西门论坛人,相逢为何不分享”。如今的工控行业风起云涌,竞争惨烈,站的住脚的、等级高的“土豪”们都是几把“刷子”在手的。
    西门子技术论坛是网路各路高手PK才艺、经验分享的大本营,在这个大本营里我们一起“长大”,慢慢“变高”。小编坚信咱工控人手里有不少“不明觉厉”的功能块,它也许披着黑色的外衣黑衣人般穿梭在每个industry的场景,却深藏着有的放矢的个性放之四海而皆准。
    现在,不论您是久经沙场满腹经验的 “大拿”,还是初来乍到技术尚浅的“菜鸟”,小编发自内心的邀您加入此次的微分享之“说说我用过的功能块”活动,晒一晒那些年现场用过的STEP7功能块,可以是STEP7自身集成的,也可以是自己创作的,简单通用、构思巧妙并且可传播性是极好的。这类功能块在满足一个特定的功能需求时,同样能适用于其它类似的场合,因为您的分享而让他们的程序结构简洁,灵活通用……
    就是现在,加入微分享之“说说我用过的功能块”吧,让那些曾经让您魂牵梦绕的、不易发觉却功力深厚的程序块现身吧,让这些闪亮的程序块在网友的一次次分享中变的更加闪亮,从而使工控小伙伴们的调试人生旗开得胜!“块”到成功!
    马上分享,大奖等着您!

    活动时间
    本【微分享】活动将分为几个阶段进行:
    1. 西门子官方详细介绍STEP 7常用功能块的使用功能块的使用,并针对您的提问答疑解惑(活动时间:2014.03.10~03.24)
    2. 有奖征集您在项目中应用的功能块和功能块的简单介绍,以及您对这些功能块的使用经验与感受以及您对这些对于功能块的使用经验与感受有奖征集您对于功能块的使用经验与感受(活动时间:2014.03.25~04.18)
    3. 版主评选入围分享置为精华帖(活动时间:2014.04.19)
    4. 为您支持的精华分享点赞(献花),投上您珍贵的一票(活动时间:2014.04.20~04.22)
    5. 公布获奖名单(公布时间:2014.04.23)

    为了方便大家查看小编的题目,在此做个索引。另外,还有一个好消息,给出本题最佳方案的网友,将加送移动电源一个! 最强大脑,行动起来吧!

    [color=blue]第一部分:首先是最简单的模式:查表
    在此我们假设已经有个表格,该表格包含了24个开灯时间(平均每个月有两个开关灯的标准时间)。那么请结合编程思路谈谈:
    a.如何将这个表的数据存储在PLC里?例如,数据类型和数据结构
    b.如何读取PLC实时时钟?采取什么样的频率?用什么样的功能块或指令?
    c.如何根据读到的时间进行查表,并最终决定路灯的状态呢?
    对PLC的性能来说,不管怎么解决这个问题,对空间和时间的要求都不值一提。但是让咱们比一比,谁的思路和代码最高效?

    第二部分:大量使用光线传感器时,如何剔除不良信号?
    如果条件复杂一些,我们需要“根据天气情况控制路灯”,其实是“根据光线条件控制路灯”,自然光线传感器是首选的方案。
    在城区路灯中选取部分采样点放置光线传感器,在实际测量中由于各采样点位置不同,所获得的检测数据存在一定的离散性,甚至在某些特殊情况下会出现个别离散性较大的数据,例如发生检测设备被泥土、污物覆盖,传感器损坏等情况,此时我们就需要将这些坏值剔除。
    假设城区设置10个光线传感器采样点,每10分钟每个采样点采集60个数据,我们用这些数据的平均值作为光线条件的结果。那么用户如何从这些数据中辨别坏值,并确定最终的实际值呢?
    这道题别着急代码,大家先聊聊思路吧。[/color]

    参赛要求
    1.分享您在工作中实际用到的STEP 7功能块,简单介绍功能块的应用以及您的使用经验与感受的功能块,简单介绍功能块的应用以及分享您在工作中实际用到的功能块,谈一谈您的使用经验与感受。字数不限,可以贴图、传附件。以真诚分享、引发共鸣为佳。
    2.参与方法:在本活动帖下跟帖,单独发布主题帖将不视为参赛。

    评选声明
    评选过程中的所有奖项均由版主及网友评出,西门子内部员工将不参与任何一个评奖环节。

    奖励机制
    [*]热心分享:
    所有参与活动 并有效留帖的网友将获得双倍发帖积分和金币[/*]
    [*]精彩分享:
    所有参与分享功能块的网友将获得50 金币额外奖励[/*]
    [*]潜力无限:
    第一轮评选后,入围优秀分享评选范围的帖子除被置为精华外,作者还将获得一份精美奖品――ipad内胆包[/*]


    [*]最受欢迎【微分享】:
    第二轮投票评选后,网友献花数最高的分享将获得大奖——移动电源[/*]





    本活动最终解释权归西门子所有
    剑忠
    奇侠

    经验值:9641
    发帖数:622
    精华帖:57
    107楼    2014-03-27 12:53:04
    精华帖  主题:回复:有奖【微分享】“说说我用过的功能块”
    看大家这段时间探讨很火热,我也来分享下几年前做的项目功能块吧!
    做过一个STEP7+WinCC系统使用CFC组合SCL工具编程的项目。为充分发挥CFC在块调用连线、程序跳转,以及监控与修改上的功能,于是用SCL编写了一套带通道故障诊断报警(Diagnostic Alarm)、限幅(Limit)、量程标度(Scale)、故障安全值替换/保持(Substitute/Hold)、通道信号仿真(Simulation)等,多功能一体的I/O模块驱动功能块,以方便调试和维护。
    尽管PCS7系统有这样一套驱动功能块,但每个块只能针对I/O模块的一个通道驱动,且不能用于非PCS7系统。我这套驱动功能块可对一个I/O模块中的所有通道驱动。这套驱动功能块按I/O信号类型分为IN_D8、OUT_D8、IN_A4、OUT_A2共4个,名称则按使用模块的类型和通道数量规则命名以方便记忆。

    一、I/O驱动功能块设计功能简介
    实现I/O驱动功能块编程的核心是使用了系统功能块SFC5[GADR_LGC],其功能是获取模块在硬件组态(HW Config)中的起始逻辑地址(Querying the Logical Base Address of a Module)。SFC5系统功能块I/O引脚使用功能如下表:

    1.模块起始逻辑地址获取
    调用SFC5功能块时,只要键入模块DP主站网络编号(SUBNETID)、DP主站机架编号(RACK),模块插槽编号(SLOT),就可在LADDR获得模块硬件组态起始逻辑地址,而模块I/O类型可在IOID中获得;模块错误信息返回值可在RET_VAL中读取。模拟量I/O通道地址计算公式如下:
    ADDR[N]:= 2 * N + L_ADDR; //获取N通道的地址
    式中:N——模块通道编号(N=0~x)[Type:INT];
    L_ADDR——模块起始逻辑地址[Type:INT];
    ADDR[N]——模块N通道地址[Type:INT]。
    2.模块通道诊断信息获取
    模块通道诊断信息获取原理是基于调用SFC5功能块时,获取RET_VAL错误信息返回值后实现的。SFC5功能块的RET_VAL错误信息返回值代码功能如下表:

    编程时先定义变量QPARF和QPERAF,判断RET_VAL返回值代码为8093/8094/8099/809A时,视为组态参数分配错误QPARF;而代码为8095/8096/8097/8098时,则可视为模块访问故障QPERAF。
    3.模拟量通道测量值限幅(Limit)设计
    本项目I/O模块为ET200S系列,AI模块为两线制4~20mADC类型。AI通道测量值量程转换及表述范围表如下:

    由此可知,传感器输入电流4~20mADC时,读取模块通道AI值的正常范围是0~27648。当27648<AI<0时,则AI值开始上/下过冲,出现异常超限;当-32768<AI<-4865时,则AI值已上/下溢出了;通常当AI=-32768时,则基本可视为传感器断线开路或未接线。
    AI/AO块限幅值建议设定值范围:低限CH_F_LL≤-5%;高限CH_F_HL≥105%。由于高/低限幅设定值使用百分比%,所以在编程进行比较判断前,需先对通道值CH_V[N]进行百分比%变换。
    4.模拟量I/O通道量程标度(Scale) 设计
    AI/AO模块的单极性转换量程范围正常是0~27648,因此只要知晓接线通道的工程单位上/下限值,就可以利用线性标度变换计算公式,编程实现AI/AO模块的通道量程变换了。以下是AI模块的线性标度变换公式(AO模块则类同):
    V[N]:= LRANGE[N] + CH_V[N] * (HRANGE[N] - LRANGE[N]) / 27648;
    式中:N——模块通道编号(N=0~x)[Type:INT];
    CH_V[N]——AI模块通道读数值[Type:INT];
    LRANGE[N]——AI模块通道工程单位下限值[Type:REAL];
    HRANGE[N]——AI模块通道工程单位上限值[Type:REAL];
    V[N]——AI模块通道工程单位转换值[Type:REAL]。
    此外,再设置POLAR[N]参数选择,用于针对有真空负压传感器测量类型时,报警提醒将工程单位上/下限设定值颠倒。
    5.模块通道信号(Simulation)功能设计
    设计模块I/O信号仿真功能,是为便于模块通道的在线/离线编程。AI/DI模块通道仿真功能主要用于CFC程序的调试;而AO/DO模块通道仿真则主要用于程序强制外部输出通道的调试。
    先为每个I/O通道设置一个“正常输出/仿真强制”切换选择开关SIM_ON[N],再将仿真强制值SIM_V[N]按工程单位进行上/下限值限幅后,送至对应外部通道即可。为防止切换为“仿真强制”模式时对外部输出通道的扰动,可再定义一个跟踪使能TRACE变量,作用是在切换为“正常输出”模式时,让仿真强制值SIM_V[N]等于正常输出值AOV[N]。SCL代码简要如下:
    IF SIM_ON[N] THEN //切换选择为仿真模式[SIM_ON[N] :BOOL]
    AOV[N]:= SIM_V[N]; //将仿真值送至外部对应通道[SIM_V[N]:REAL]
    ELSE
    IF TRACE THEN //仿真值跟踪输出值使能选择[TRACE:BOOL]
    SIM_V[N]:= AOV[N]; //让仿真值跟踪正常输出值[AOV[N]:REAL]
    END_IF;
    END_IF;
    6.道故障安全值替换/保持(Substitute/Hold)功能设计
    该功能主要用于仪表调节阀、快速切断阀、电磁阀等设备,在AO/DO模块输出通道故障时的安全处理方式选择。尽管ET200S系列I/O模块在硬件组态中有Keep last/ Substitute功能选项,但如果在正常生产中更改通道的该选项后,CPU必需停机下载才能生效,因此在一些高可靠性和不间断生产的领域使用受限。
    本功能设计则可在CPU不停机时即可实现通道故障安全值“替换/保持”选项的修改,特别是本项目使用了CFC工具,更是方便灵活。SCL代码简要如下:
    IF MCH_F[N] THEN //模块通道是否故障[MCH_F[N]:BOOL]
    IF HOLD_U[N] THEN //选择通道故障后为“保持”模式[HOLD_U[N]:BOOL]
    AOV[N]:= LAST_U[N]; //将通道故障前的正常值输出[LAST_U[N]:REAL]
    ELSE
    AOV[N]:= SUBS_U[N]; //通道故障后将预置的替换值输出[SUBS_U[N]:REAL]
    END_IF;
    END_IF;
    LAST_U[N]:= AOV[N]; //将本次输出值保存
    二、I/O驱动功能块应用体会
    1、这套Drive块无论是在项目是调试和维护阶段,都发挥了巨大作用,希望通过以上的简要介绍能对大家有益,此项目也曾将其发表于2011年SIEMENS自动化专家会议论文上。

    2、但这套Drive块需配合CFC工具才能展现它高效便捷的优势。此外由于它集多功能于一体,使得CPU的算术运算和存储容量均消耗较大,所以不建议在中低端的CPU项目上使用。
    大学之道,在明明德,在亲民,在止于至善。
    信仰
    游民

    经验值:90
    发帖数:1
    精华帖:1
    108楼    2014-03-28 13:02:16
    精华帖  主题:回复:有奖【微分享】“说说我用过的功能块”
    用过OPEN IE通讯的大侠们,有没有发现:当要与多台设备同时进行通讯时候,每个通讯都调用FB63、FB64、FB65、FB66时候很不方便。针对这个问题,本人用SCL把FB63、FB64、FB65、FB66做了个集成,生产一个功能块FB100,以后每个通讯只需要调用这一个功能块就可以了,供大家参考提议,现此功能块已经在项目中实用(用317CPU同时和8个机器人以太网通讯)。以下为SCL原文件:
    FUNCTION_BLOCK FB100
    VAR_INPUT
    CON_DATA:ANY;
    SEND_DATA:ANY;
    RCV_DATA:ANY;
    CON_REQ:BOOL;
    SEND_REQ:BOOL;
    RCV_REQ:BOOL;
    DISCON_REQ:BOOL;
    LENG_SEND:INT;
    LENG_RCV:INT;
    ID:WORD;
    END_VAR
    VAR_OUTPUT
    SEND_DONE:BOOL;
    STATUS:WORD;
    END_VAR
    VAR
    TCON:FB65;
    TSEND:FB63;
    TRCV:FB64;
    TDISCON:FB66;
    END_VAR
    BEGIN
    TCON(REQ :=CON_REQ
    ,ID :=ID
    ,CONNECT :=CON_DATA
    );
    TSEND(REQ :=SEND_REQ
    ,ID :=ID
    ,LEN :=LENG_SEND
    ,DATA :=SEND_DATA
    );
    SEND_DONE:=TSEND.DONE;
    STATUS:= TSEND.STATUS;
    TRCV(EN_R :=RCV_REQ
    ,ID :=ID
    ,LEN :=LENG_RCV
    ,DATA :=RCV_DATA
    );
    TDISCON(REQ :=DISCON_REQ
    ,ID :=ID
    );
    END_FUNCTION_BLOCK
    编译前,请先在程序里插入FB63/64/65/66,接下来会发现OPENIE通讯如此方便!
    古月游风
    侠客

    经验值:911
    发帖数:121
    精华帖:3
    143楼    2014-04-12 11:27:29
    精华帖  主题:回复:有奖【微分享】“说说我用过的功能块”
    说说第一个查表的问题吧
    一、前言:
    1、 系统能否正常工作,有个前提,即PLC的时间是要准确的,可通过手动调整时间或做时间同步。
    2、 精度到分钟即可。自动程序的运行周期不须太快,在OB3x执行,10秒左右都可。
    3、 开、关灯时间应为可设定的。
    二、查表:
    整个查表的过程分为以下几个环节:
    1) 建立时间规则表,表内包括ID、开灯时间(TimeOpen)、关灯时间(TimeClose)、开始日期(DateStart)、结束日期(DateEnd),可在一个DB(UDT)或多个DB实现。本案例暂且为24行,实际可根据情况拓展。如下表所示:
    ID TimeOpen TimeClose DateStart DateEnd
    1 18:00 09:00 07-01 07-15
    2 18:10 09:10 07-16 07-31
    3
    ...

    2) 获取系统时间,使用SFC1 READ_CLK,可获得DATA_AND_TIME,从中提取出日期和时间(INT)
    3) 确定当前应使用哪个规则。可用当前日期和规则表中的开始日期、结束日期进行比较,进而获取规则ID(获取行)
    4) 获取当前应开、应关时间。获取行ID后,将此行的开灯时间、关灯时间提取转存
    三、动作:
    1) 每个控制对象(单个灯或单组灯)建立功能块,暂且称为LCM。
    2) LCM模式:
    时间控制:自动查表时间,或手动设定的时间;
    手动控制:单体操作
    其它各种模式
    3) 由LCM根据条件,控制输出
    五、附录:引用的功能块
    System Function Blocks
    SFC1:READ_CLK 获取系统时间
    SFC0:SET_CLK 设置系统时间
    IEC Function Blocks
    FC6:DT to DATE 转换Date_And_Time类型至Date类型
    FC9:EQ_DT;FC12:GE_DT;FC14:GT_DT;FC18:LE_DT;FC23:LT_DT……比较2个Date

    四、回顾
    这个方案优点在于比较灵活,比较好扩展。当然缺点也很多。
    1、 调整时间,只需要调整时间规则表,可从HMI设定。
    2、 新增规则,只需增加规则表行数, 其它代码基本不用修改。

    条条大道通罗马,解决的方案很多,没有最好的,只有最适合的。
    szy868
    侠客

    经验值:619
    发帖数:101
    精华帖:6
    150楼    2014-04-16 10:27:49
    精华帖  主题:回复:有奖【微分享】“说说我用过的功能块”
    我也贴一个自己编写使用的功能块,油泵站双泵启停控制,具备现场/远方、手动/自动启停,故障切换,定时切换,计时功能,SCL语言。

    //电机选择开关位置判断
    IF "M1Select" THEN
    IF "M2Select" THEN
    "DBForAlarm".MotorSWError := true;
    ELSE
    "DBForInternalControl".SelMark1 := true;
    "DBForInternalControl".SelMark2 := false;
    "DBForInternalControl".AutoStatus := false;
    END_IF;
    ELSE
    IF "M2Select" THEN
    "DBForInternalControl".SelMark1 := false;
    "DBForInternalControl".SelMark2 := true;
    "DBForInternalControl".AutoStatus := false;
    ELSE
    "DBForInternalControl".SelMark1 := false;
    "DBForInternalControl".SelMark2 := false;
    "DBForInternalControl".AutoStatus := true;
    END_IF;
    END_IF;

    //使用定时器判断两台泵是否为非自动切换时的停运状态
    "DBForM1AndM2StopTimer".TON(IN:=(NOT "KM1NO" AND NOT "KM2NO"),
    PT:=100ms);

    //泵站自动运行状态的判断
    IF "DBForInternalControl".AutoStatus AND ("KM1NO" OR "KM2NO" ) THEN
    "DBForInternalControl".PSAutoRunMarker := true;
    ELSE
    IF "DBForInternalControl".AutoStatus THEN
    IF "DBForM1AndM2StopTimer".Q THEN
    "DBForInternalControl".PSAutoRunMarker := false;
    END_IF;
    ELSE
    "DBForInternalControl".PSAutoRunMarker := false;
    END_IF;
    END_IF;

    //1#泵电机启动命令,包括:
    //1、现场手动选择启动;
    //2、现场自动选择启动;
    //3、泵站自动运行状态下,定时切换启动;
    //4、泵站自动运行状态下,工作泵故障自动切换启动。此类自动启动的故障包括:过热、进口滤器堵塞、运行压力低。
    //5、远方启动命令;
    IF "StartSBNO" AND ( "DBForInternalControl".SelMark1
    OR ( "DBForInternalControl".AutoStatus AND (NOT "KM2NO") AND "DBForInternalControl".TotalRunTime1 <= "DBForInternalControl".TotalRunTime2))
    OR ( "DBForInternalControl".AutoStatus AND "DBForDataDown".StartM1 )
    OR "DBForInternalControl".PSAutoRunMarker AND ( ("DBForInternalControl".MotorAutoSwtichPattern AND "DBForInternalControl".CurrentRunTime2 >= "DBForInternalControl".SingleWorkTimeSV )
    OR "DBForAlarm".FR2Alarm
    OR "DBForAlarm".FilterClogAlarm2
    OR "DBForAlarm".PumpRunPressLowAlarm2 ) THEN
    "DBForInternalControl".StartPump1 := true;
    ELSE
    "DBForInternalControl".StartPump1 := false;
    END_IF;

    //1#泵电机停止命令
    //工作泵工作出现故障,停止工作泵。包括电机过热、进口滤器堵塞、工作油压低、工作油压高、油位低。
    IF ( NOT "StopSBNC" AND NOT "DBForInternalControl".SelMark2 )
    OR ( "DBForInternalControl".AutoStatus AND "DBForDataDown".StopM1 )
    OR ( "DBForInternalControl".PSAutoRunMarker AND "KM2NO" AND "DBForInternalControl".MotorAutoSwtichPattern AND "DBForInternalControl".CurrentRunTime1 >= "DBForInternalControl".SingleWorkTimeSV )
    OR "DBForAlarm".FR1Alarm
    OR "DBForAlarm".FilterClogAlarm1
    OR "DBForAlarm".OilLeverLowAlarm
    OR "DBForAlarm".PumpRunPressLowAlarm1
    OR "DBForAlarm".PressHighAlarm
    THEN
    "DBForInternalControl".StopPump1 := true;
    ELSE
    "DBForInternalControl".StopPump1 := false;
    END_IF;

    //2#泵电机启动命令,包括:
    IF "StartSBNO" AND ( "DBForInternalControl".SelMark2
    OR ( "DBForInternalControl".AutoStatus AND (NOT "KM1NO") AND "DBForInternalControl".TotalRunTime2 < "DBForInternalControl".TotalRunTime1))
    OR ( "DBForInternalControl".AutoStatus AND "DBForDataDown".StartM2 )
    OR "DBForInternalControl".PSAutoRunMarker AND ( ("DBForInternalControl".MotorAutoSwtichPattern AND "DBForInternalControl".CurrentRunTime1 >= "DBForInternalControl".SingleWorkTimeSV )
    OR "DBForAlarm".FR1Alarm
    OR "DBForAlarm".FilterClogAlarm1
    OR "DBForAlarm".PumpRunPressLowAlarm1 ) THEN
    "DBForInternalControl".StartPump2 := true;
    ELSE
    "DBForInternalControl".StartPump2 := false;
    END_IF;

    //2#泵电机停止命令
    IF ( NOT "StopSBNC" AND NOT "DBForInternalControl".SelMark1 )
    OR ( "DBForInternalControl".AutoStatus AND "DBForDataDown".StopM2 )
    OR ( "DBForInternalControl".PSAutoRunMarker AND "KM1NO" AND "DBForInternalControl".MotorAutoSwtichPattern AND "DBForInternalControl".CurrentRunTime2 >= "DBForInternalControl".SingleWorkTimeSV )
    OR "DBForAlarm".FR2Alarm
    OR "DBForAlarm".FilterClogAlarm2
    OR "DBForAlarm".OilLeverLowAlarm
    OR "DBForAlarm".PumpRunPressLowAlarm2
    OR "DBForAlarm".PressHighAlarm
    THEN
    "DBForInternalControl".StopPump2 := true;
    ELSE
    "DBForInternalControl".StopPump2 := false;
    END_IF;

    //1#泵控制命令输出
    IF NOT "DBForInternalControl".StopPump1 AND ("DBForInternalControl".StartPump1 OR "KM1NO" ) THEN
    "StartM1" := true;
    ELSE
    "StartM1" := false;
    END_IF;

    //2#泵控制命令输出
    IF NOT "DBForInternalControl".StopPump2 AND ("DBForInternalControl".StartPump2 OR "KM2NO" ) THEN
    "StartM2" := true;
    ELSE
    "StartM2" := false;
    END_IF;

    //创建1min定时器脉冲
    "DBForOneMinPulseTimer".TON(IN:=NOT "FirstScan",
    PT:=60s,
    Q=>"FirstScan");


    //累计1#泵运行时间
    IF "KM1NO" THEN
    IF "FirstScan" THEN
    "DBForInternalControl".TotalRunTime1 := "DBForInternalControl".TotalRunTime1 + 1;
    "DBForInternalControl".CurrentRunTime1 := "DBForInternalControl".CurrentRunTime1 + 1;
    END_IF;
    ELSE
    "DBForInternalControl".CurrentRunTime1 := 0;
    END_IF;

    //累计2#泵运行时间
    IF "KM2NO" THEN
    IF "FirstScan" THEN
    "DBForInternalControl".TotalRunTime2 := "DBForInternalControl".TotalRunTime2 + 1;
    "DBForInternalControl".CurrentRunTime2 := "DBForInternalControl".CurrentRunTime2 + 1;
    END_IF;
    ELSE
    "DBForInternalControl".CurrentRunTime2 := 0;
    END_IF;

    //1#接触器位置指示
    IF "DBForTDExchange".TestLamp OR "KM1NO" THEN
    "M1RunningLamp" := true;
    ELSE
    "M1RunningLamp" := false;
    END_IF;

    //2#接触器位置指示
    IF "DBForTDExchange".TestLamp OR "KM2NO" THEN
    "M2RunningLamp" := true;
    ELSE
    "M2RunningLamp" := false;
    END_IF;

    //计算电机总运行计时显示
    "DBForTDExchange".TotalRunningDays1 := "DBForInternalControl".TotalRunTime1 / 1440;
    "DBForTDExchange".TotalRunningDays2 := "DBForInternalControl".TotalRunTime2 / 1440;
    "DBForTDExchange".TotalRunningHours1 := "DBForInternalControl".TotalRunTime1 / 60 - "DBForTDExchange".TotalRunningDays1 * 24;
    "DBForTDExchange".TotalRunningHours2 := "DBForInternalControl".TotalRunTime2 / 60 - "DBForTDExchange".TotalRunningDays2 * 24;
    //计算电机当前运行计时显示
    "DBForTDExchange".CurrentRunningHours1 := "DBForInternalControl".CurrentRunTime1 / 60;
    "DBForTDExchange".CurrentRunningHours2 := "DBForInternalControl".CurrentRunTime2 / 60;
    "DBForTDExchange".CurrentRunningMinutes1 := "DBForInternalControl".CurrentRunTime1 - "DBForTDExchange".CurrentRunningHours1 * 60;
    "DBForTDExchange".CurrentRunningMinutes2 := "DBForInternalControl".CurrentRunTime2 - "DBForTDExchange".CurrentRunningHours2 * 60;
    您收到0封站内信:
    ×
    ×
    信息提示
    很抱歉!您所访问的页面不存在,或网址发生了变化,请稍后再试。