首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >PLC Control with ST,V3版本学习笔记08—变量赋值(除零问题,数据类型转换问题,Real类型的精度问题等)

PLC Control with ST,V3版本学习笔记08—变量赋值(除零问题,数据类型转换问题,Real类型的精度问题等)

作者头像
Hello工控
发布2025-12-23 14:08:48
发布2025-12-23 14:08:48
1080
举报
文章被收录于专栏:Hello工控Hello工控

变量是编程的重要组成部分。本章将介绍变量赋值的基础知识,以及在操作时的重要信息和提示。在某些PLC类型中,变量被称为标签或PLC标签

变量指向(链接)内存中的一个存储空间,该存储空间含可以写入数值的位置。存储空间的大小取决于数据类型,这一点非常重要。那么,变量赋值,实际就是往这个空间里写入具体值!

变量赋值

下面的示例展示了名为VarA的变量如何获取变量VarB中存在的数值副本。这意味着VarA被赋值为VarB所持有的值。

代码语言:javascript
复制
VarA:= VarB;

注意的是:符号 :=;(冒号:、等号=和分号;)的使用。

如果往VarB里面赋值:

代码语言:javascript
复制
VarB := 17.6 ;

如果VarB为INT类型,大部分PLC基本上会提示报错:

默认有小数点的数值当作是LREAL类型,所以报错:不能把LREAL类型直接转为INT类型。

当然原作者在这里举例HeartBeat:

代码语言:javascript
复制
Count:= Count + 1;
IF Count > 99 THEN //To avoid overrun
Count:= 0; //Reset counter
END_IF;

利用Count的赋值判断程序是否在运行中,这个是很好的机制,常常用来判断PLC是否是在正常运行中,或者该程序、FB等在执行!

同样的,这种方式也可以用来做延时,由于每个周期会执行+1的操作,如果一个周期是1ms,当Count=100的时候,说明执行了100次循环,也可以精准的做延时!

除零问题

接下来主要介绍赋值里面几种问题,首先最开始的是除零问题:

出现这类问题,就是致命的故障!基本上程序只要有一处,PLC就会死机,从RUN模式自动切换到STOP模式!所以,除零是必须要在程序设计时候避免掉的!

代码语言:javascript
复制
VarC:= VarA / Temperature;

书中主要用温度来举例说明,把传感器的值链接到Temperature变量,但是这类变量也确实存在Temperature为0的情况,一旦出现,PLC运行内核就会故障而STOP!

当然,也有解决的办法:

方法1:加条件判断

代码语言:javascript
复制
//Ensure temperature is not zero when calculating
IF Temperature <> 0 THEN
VarC:= VarA / Temperature;
END_IF;

方法2:强制赋值一个不为0的值

代码语言:javascript
复制
//Ensure temperature is not zero when calculating
IF Temperature = 0 THEN
Temperature:= 0.0001;
END_IF;
VarC:= VarA / Temperature;

需要注意的是:LN (x) and LOG (x)这两类数学函数的参数x不能为0.

图片
图片

INT和REAL实数类型的转换

在PLC编程中,既可以使用整数(INT)也可以使用浮点数(REAL)进行计算。当需要进行两个整数的除法运算时,必须特别注意变量的数据类型以及运算的执行方式。

下面简单举例说明:(三个INT变量类型的变量做除法运算)

我们预期的结果正常是8.8,由于iVar这个目标结果变量是INT类型,所以最终的结果是8.相当于对8.8做了取整数操作,只是这个是隐式结果,实际上显示的过程:

要得到预期结果,并不是把iVar类型定义为REAL就能成功的:

上图的rVar已经是REAL类型,但是结果依然是8.所以,我们正确的做法是:

这种方式实际就是把赋值中的表达式中其中一个变量iVar2,强制转换为REAL类型,最后参与到除法运算中!

还需要注意的是,下图的写法:

这种直接用数字做除法运算,默认和我们上面提到的定义两个INT类型数据结果是一样的,解决方法很简单:

所以,PLC里面的数学计算和我们日常的计算是不一样的,务必在进行交付前进行校验和调试!

REAL类型的精度

当使用REAL(浮点)数据类型进行计算时,有时会出现结果并非整数的情况。例如,预期变量结果应为规整的整数(如11),但实际计算结果却显示为10.999999。这种现象源于计算机底层只能处理整数数据类型,而REAL值实际上是经过调整的近似值。

关于REAL类型的数据怎么存储在计算机内部的演示视频,这里以圆周率Π来进行示例演示,详情请点击下述视频:

那了解到这个原理后,在处理下面类似这种应用的时候,就要避免这种情况导致非预期的结果:

这种写法,我们知道可能Sensor这个值不会刚好是11.0;所以,Lamp1的状态不会置TRUE。怎么解决呢?请看下面的例子:

当然,还有一种方式可以使用TRUNC转换成整数再比较。

数据传输问题

在设计自动化解决方案时,经常需要将变量传输至其他计算机设备。本章重点阐述与变量数据传输相关的关键问题。

浮点数精度问题

不同设备在传输REAL(实数)型变量时可能产生问题,无论是传输至其他PLC、工控机、电气设备还是自动化仪表。这是由于不同计算机系统对REAL/FLOAT(浮点数)值的定义存在差异(计算机本质上更精确处理整数运算)。此外,不同编程版本、16/32/64/128位系统对浮点数的处理方式差异也会引发问题。

解决方案是将所有数值转换为整数传输:发送方可将数值乘以100转换为保留两位小数的整数,接收方再除以100还原原始值。具体的步骤:

代码语言:javascript
复制
VAR CONSTANT
    DecimalFactor : REAL := 100; //10 for 1 digits, 100 for 2 digits,1000 for 3 digits
    RealNumberBegin : REAL := 50.7172;
END_VAR
VAR
    INTNumber: INT; 
    RealNumber: REAL ;
END_VAR

RealNumberRealNumber:= RealNumberBegin;
IF DecimalFactor > 0 THEN //Avoid division by zero (0)
    RealNumber:= (RealNumber * DecimalFactor) + 0.5; //+ 0.5 to round up #1)
    INTNumber:= REAL_TO_INT(RealNumber); // Convert tointeger #2)
    RealNumber:= INT_TO_REAL(INTNumber); // Convert todecimal #3)
    RealNumber:= RealNumber/DecimalFactor; // Add decimal #4)
END_IF;

DecimalFactor是一个常数,一般定义常数是适用于经常要用的值和变量,当然如果直接用100,也是可以的,但是,当遇到这个系数需要变更那改动的位置就太多了,工作量剧增,所以用常量是一个很好的方式!

字符串(STRING)传输问题

字符串(STRING)传输同样存在挑战,这源于不同系统对字符串的处理方式差异——包括位宽标准不同(如Unicode与ASCII字符集选择差异)。特别需要注意的是,某些编程语言的字符串起始索引为0,而另一些则从1开始。将字符串转换为字节(BYTE)数组可简化传输过程。

数据传输时应始终以字(WORD)为单位进行读取。需注意某些计算机系统会交换字的高/低字节(最低8位与最高8位互换)。

若数值以0X开头则表示十六进制值。在某些PLC系统中,布尔型(BOOL)变量可能占用16位存储空间,因此也可能被识别为整型(INT)数据。

其他问题

结构体(STRUCT)不能直接传输,因其本质是模板化的数据结构。若PLC需要接收布尔变量(如报警信号、计数值、触发信号或启动信号),通常需要在PLC程序中配置为单触发(one-shot)模式。

建议为所有跨设备传输的变量建立协议文档,形成类似I/O清单的通信文档,以确保传输过程的可追溯性。

类型转换问题

我们在上面的例子里实际已经用到了类型的转换,INT转换成REAL类型,基本的格式:

TYPE1_TO_TYPE2()

TYPE1是()里面参数的类型,转换源;

TYPE2是转换目标类型,最终返回的结果。

有些PLC提供上100多种类型转换函数,非常方便。下面是一些常用的数据类型转换:

对于最后一项角度和弧度的转换,有些PLC就没有,可以自定义。需要注意的是有些运算必须加转换,例如REAL_TO_INT,将范围空间大的变量类型转换成更小的类型,是必须显式调用相应的转换函数,但是仍然要确保这种转换是PLC所支持的。

而INT_TO_REAL这类可以不用显式写出来,可以忽略,建议初学者还是写上最好:

DATE 由 PLC 硬件内部的电子电路转换而来。该电路从 UTC 时间 1970 年 1 月 1 日 00:00:00(UTC,原子钟基准)开始以秒为单位计时。

请注意,下一次 Y2K(千年虫)类似问题 将发生在 2038 年。具体参考:

我就搞个PLC,“Y2K”(千年虫问题)是个啥?跟我有啥关系?

如何在读取整形数据中的Bit的状态

对于一些数据通信中,往往要获取WORD中的0-15个Bit位的状态,到底是TRUE或者FALSE。

我们知道WORD是由两个字节BYTE,共计16Bit组成,那么要获取每一位的状态值,可以怎么操作呢?

第一种方式最直接,用.即可:

这是最直接的方式,直接用.,后面需要第几位就写多少。本例就是MyUINT的第0位,但是代码有一处不那么仔细看的错误!留言区请给答案哦!

第二种方式是用AND指令:

实际是INT和第0位为TRUE的数值做“与”运算,如果该位的值是TRUE,那么结果自然是TRUE,反之亦然。下图应该更清晰:

明显,运算结果只有两种可能:2#0001和2#0000 ,再转换成BOOL就得出对于Bit位的结果。进一步的

除了上述两种方式,当然还有其他的实现方式,这里留给大家自行思考!

数组Array类型赋值

原书用下图示例展示了如何使用变量控制阀门矩阵。在啤酒厂和乳品厂中,阀门矩阵用于将多个储罐中的液体排入共享管道系统。本示例采用5储罐3管道的阀门矩阵配置(如图所示):

假如第2条管道的第3排罐体没有液体,那么:

上述根据实际的管道ID(1,2,3)和罐体排数(1,2,3,4,5)共同形成一个二维数组,很方便把上述15个罐体的状态指示灯的亮灭表述出来。

如果用一维数组来表述的话,可以这样的定义,下图:

但是原书下面的表述,我个人认为是有问题的:

如果仍然要获取第2条管道的第3排罐体有没有,按照上面这个表述:

PipeMatrix[3,2] := PipeMatrixUINT[3] = 2#010;

最终的结果当然也是对的,因为目前:

PipeMatrixUINT[3]:= 2#010; //Tank 3

假如是下图这种情况:

此时,

PipeMatrixUINT[3]:= 2#110; //Tank 3

如果,再用下面的表达式赋值就不对了:

PipeMatrix[3,2] := PipeMatrixUINT[3] = 2#010;

下图监控的结果是FALSE:(错误结果)

正确的做法:

PipeMatrix[3,2]:=UINT_TO_BOOL(PipeMatrixUINT[3] AND 2#010);

下图监控的结果是TRUE:(正确结果)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-07-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Hello工控 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 变量是编程的重要组成部分。本章将介绍变量赋值的基础知识,以及在操作时的重要信息和提示。在某些PLC类型中,变量被称为标签或PLC标签。
  • 变量赋值
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档