返回
SCL PLC 编程教程第三篇 变量、数据类型与地址概念:SCL 程序为什么不能乱定义变量
学 PLC 的时候,很多人一开始接触的是输入点、输出点、中间位、定时器、数据寄存器这些概念。
比如:
I0.0 是启动按钮
I0.1 是停止按钮
Q0.0 是电机接触器
M0.0 是内部运行位
DB 里存配方参数
AIW 里有模拟量原始值
这种思路没有错,而且在梯形图时代,它非常直观。
但当你进入 SCL 之后,会慢慢发现一个变化:
你眼前看到的,不再只是地址,而更多是“变量名”。
比如你不再只是盯着 I0.0,而是更习惯写成:
StartPB
你不再只是盯着 Q0.0,而是写成:
MotorRun
你也不再只把模拟量看成一个字,而是可能定义成:
TankLevel
TemperaturePV
PressureRaw
FlowSetpoint
这时候,很多初学者就会出现一个误区:
“反正就是起个名字而已,差不多就行。”
实际上,完全不是这样。
在 SCL 里,变量定义得对不对、变量类型选得准不准、变量作用范围清不清楚,会直接决定:
程序能不能正常编译
逻辑能不能稳定运行
数据会不会算错
后续维护会不会越来越乱
模块能不能复用
工程能不能做大
所以这一篇,我们就不急着往复杂语法冲,而是把最根上的东西讲清楚:
变量到底是什么
为什么 PLC 里不能乱定义变量
变量有哪些分类
数据类型有什么区别
地址和变量名到底是什么关系
为什么有些程序一运行,数据就莫名其妙错掉了
这一篇吃透了,后面你再学判断、循环、数组、功能块时,底会稳很多。
一、先把最核心的一句话记住:变量不是“名字”,而是“有类型、有作用、有边界的数据容器”
初学者最容易把变量理解成“随便起的一个标签”,这是不够的。
更准确的理解应该是:
变量是程序里用来存放和传递数据的容器,它不仅有名字,还有数据类型、作用范围、读写方式以及生命周期。
这句话听起来有点像书面定义,但它非常重要。
比如同样一个变量,看上去只是个名字:
MotorSpeed
但实际上,这个变量背后至少还有这些问题:
它是整数还是实数
它是输入变量还是输出变量
它是当前块临时使用的,还是需要长期保存
它是来自现场采集,还是程序内部计算结果
它是某个功能块专属的,还是全局共享的
它存的是速度设定值,还是实际反馈值
也就是说,变量从来不是“随便取个名”。
它其实是整个程序逻辑的承载单位。
你以后写 SCL 程序时,必须慢慢建立这种意识:
程序的本质,不只是写判断和循环,更是在组织变量之间的关系。
二、为什么很多 SCL 程序一开始就乱?往往不是逻辑乱,而是变量乱
很多项目后期不好维护,表面看是程序越来越大,实际上根源往往是变量体系从一开始就没建好。
常见的混乱有这些:
1. 变量命名随意
例如:
A1
Temp1
Bbb
RunX
Value2
TestOK1
M_Run_2_New
这些名字当时自己也许知道什么意思,但两个月后再看,往往就糊了。
更别说别人来接手。
2. 同一种意义的数据,到处命名不统一
比如有的地方叫:
StartPB
另一个块里又写:
StartBtn
还有的地方叫:
PB_Start
再有地方叫:
RunCmdInput
如果都是同一类信号,命名风格乱掉后,程序阅读成本会迅速上升。
3. 类型乱选
比如一个带小数的温度值,结果定义成 INT;
一个本来只是开关状态的变量,却拿 DINT 去存;
一个会超过 32767 的计数值,还在用 INT;
一个字符串报码被当成数字处理。
这类问题在小项目里也许一时看不出来,但一旦运行条件变复杂,就会开始出错。
4. 临时值、设定值、反馈值混在一起
比如:
Speed
Speed1
Speed2
SpeedNew
光看变量名,谁也不知道哪个是设定,哪个是反馈,哪个是滤波后的结果,哪个是限幅后的结果。
5. 不清楚变量该保留还是该临时使用
有些变量只是在本次扫描周期中参与计算,算完就可以丢。
有些变量则必须长期保存,比如:
当前步骤号
故障锁存状态
上次运行结果
累计计数值
配方参数
如果这两类变量不分清,程序就会出现一种很常见的问题:
“怎么我这个值刚算出来,下一扫又没了?”
所以你会发现,SCL 程序写得稳不稳,第一步不是看逻辑多高级,而是看变量体系有没有章法。
三、变量在 PLC 程序里,到底承担什么角色
你可以把 PLC 程序想成一间工厂里的信息中转站。
变量就在里面承担不同角色。
1. 有的变量负责“接收现场信息”
比如按钮、限位、传感器、故障接点:
StartPB
StopPB
HomeSensor
OverloadAlarm
TankLevelRaw
这些变量很多时候来自输入采集。
2. 有的变量负责“存放控制结果”
比如:
MotorRunCmd
ValveOpenCmd
AlarmLamp
BuzzerOn
这些变量通常最终会输出到设备执行端。
3. 有的变量负责“中间计算”
比如:
LevelScaled
TempFiltered
SpeedLimitResult
AlarmPermit
StartConditionOK
它们不一定直接对应现场点位,但对逻辑非常重要。
4. 有的变量负责“保存程序状态”
比如:
StepNo
AlarmLatched
AutoCycleBusy
LastProductCode
BatchCount
这些变量往往决定程序是否能保持连续性和记忆性。
所以从工程角度讲,变量不是附属品。
变量本身就是程序结构的一部分。
四、SCL 中变量最常见的几种分类
不同平台在界面和叫法上会有差别,但从编程思想上,你可以先把变量理解为下面几大类。
1. 输入变量
输入变量通常是这个程序块“拿进来用”的数据。
它们往往由外部传入,供当前逻辑判断和计算。
例如一个电机控制功能块,输入可能有:
启动命令
停止命令
自动模式
故障信号
热继电器状态
这些输入变量的特点是:
它们是本块逻辑的依据
本块通常主要读取它们
它们的值往往来自上层调用或现场映射
你可以把它理解成:
别人把材料递给你,你在块里加工。
2. 输出变量
输出变量通常是当前块处理完后,要“交出去”的结果。
比如:
电机运行命令
就绪状态
故障状态
当前步骤完成信号
允许启动标志
这些变量的特点是:
它们是逻辑运算后的结果
会被上层逻辑或其他块继续使用
最终可能映射到实际输出点,或传给 HMI
可以理解成:
你处理完以后,把结果交出去。
3. 输入输出变量
有些变量既作为输入带进来,又在块内被修改后再带出去。
这类变量常见于:
累计值更新
配方结构体传递
参数块修改
某些复用处理模块
不过初学阶段建议先少用这种写法,或者至少要特别清楚变量的来龙去脉,否则很容易把数据流搞乱。
4. 临时变量
临时变量非常重要,但很多初学者最容易忽略。
它的特点是:
只在当前块执行期间参与中间计算
通常不需要长期保留
每次执行时重新计算使用
例如:
比较结果中间位
某个计算公式中的过渡值
临时索引
组合条件判断结果
比如:
StartPermit := AutoMode AND NOT Fault AND SafetyOK;
这里 StartPermit 就可能是一个中间条件变量。
它存在的意义是让逻辑更清楚,不一定非要长期保存。
但这里要注意一点:
临时变量如果用来保存“上次状态”或“跨周期状态”,通常是不合适的。
这也是很多人第一次写状态机、边沿检测、锁存逻辑时出问题的原因。
5. 静态变量或保持性变量
这类变量是很多 PLC 工程里最关键的一类变量。
它们的作用不是只在本次扫描中用一下,而是要 记住程序之前发生过什么。
例如:
当前步骤号 StepNo
故障锁存 AlarmLatched
运行累计次数
上次按钮状态
上个周期的测量值
滤波历史值
已确认但未清除的报警标志
这类变量的特点是:
不应每次扫描都重新清零
必须在程序运行过程中持续保存
很多顺控、状态机、边沿判断都离不开它们
你以后写 SCL 时,一定要养成一个习惯:
每定义一个变量,都先问自己:
这个变量只是本扫临时计算一下,还是要记住上次结果?
这个问题想清楚,很多逻辑错误会提前消失。
五、数据类型到底是什么,为什么它这么重要
很多初学者觉得,变量就是个名字,值放进去能用就行。
但程序不是这样工作的。
程序必须知道:
这个变量里存的到底是什么类型的数据。
因为不同类型的数据,PLC 会用不同方式去存储、计算和解释。
你可以把“数据类型”理解成给变量贴的说明书。
这个说明书告诉系统:
这个值是不是只有真和假
它是不是整数
它是不是带小数
它是不是很大的数
它是不是时间
它是不是文本
如果类型选错了,哪怕变量名再漂亮,程序也可能算错。
六、SCL 里最常见的数据类型,必须先吃透这几种
1. BOOL:布尔量
这是最基础的一种类型。
BOOL 只有两种状态:
TRUE
FALSE
它最适合表示“是或否”“有或无”“开或关”“成立或不成立”。
典型用途:
按钮状态
电机运行状态
故障标志
条件是否成立
阀门开到位
安全门是否关闭
例如:
IF StartPB AND NOT Fault THEN
MotorRun := TRUE;
END_IF;
这里的 StartPB、Fault、MotorRun 一般都应该是 BOOL。
不要把 BOOL 想小了。
虽然它只是真假两态,但 PLC 里大量逻辑判断的基础都靠它。
2. INT:整数
INT 适合表示不带小数的整数值。
常见用途:
步骤号
报警编号
小范围计数
简单设定值
小范围下标
例如:
StepNo = 10
AlarmCode = 3
RetryCount = 5
但这里一定要记住:
INT 不是无限大的。
如果你拿 INT 去做很大的累计计数,后面可能会溢出。
所以它适合“范围不太大且不需要小数”的值。
3. DINT:长整数
当整数范围可能比较大时,往往就要考虑 DINT。
它常用于:
累计产量
总运行时间计数
大范围脉冲累计
较大的设备编号或索引值
很多初学者一开始只会用 INT,后面计数一大就出事。
这就是没有建立“值的范围意识”。
所以你定义变量时,不只要看“它是不是整数”,还要看:
它未来可能会增长到多大。
4. REAL:实数
REAL 是带小数的数,工程里使用非常多。
尤其在这些场景里几乎绕不开:
温度
压力
流量
液位
速度
比例系数
模拟量工程值
PID 相关参数
例如:
23.5℃
0.78MPa
4.2m
50.0Hz
如果你的数据本身有小数,或者计算过程中会出现小数,通常就应考虑 REAL。
例如模拟量换算:
LevelMeter := REAL_TO_REAL(LevelRaw) * 5.0 / 27648.0;
虽然具体转换函数后面还会详细讲,但这里你先记住一个大原则:
凡是涉及工程量、比例、滤波、平均值、模拟量换算的场景,REAL 通常非常常见。
5. TIME:时间类型
PLC 不是普通计算器,它经常要处理时间。
比如:
延时启动
延时停机
报警保持时间
动作超时
节拍统计
间隔触发
这些时候,TIME 类型就很重要。
比如:
T#5s
T#100ms
T#2m30s
时间不是普通整数,它有自己的表达和处理规则。
所以不要简单把“5000毫秒”永远都当整数思考,很多时候更合适的做法是用 TIME。
6. STRING:字符串
只要涉及文字、文本、条码、设备名称、报警描述,STRING 就会出现。
例如:
产品型号
条码内容
批次号
报警文字
配方名称
很多 PLC 工程师前期接触 STRING 不多,但等到 HMI、扫码、报文解析、配方管理做多了,就会越来越常见。
七、同样是“数字”,为什么 INT 和 REAL 不能乱混
这个问题非常常见。
很多人觉得:
10 就是 10
10.0 也是 10
差不多吧
从人眼看,好像差不多;
但从程序角度,它们不是同一回事。
例如:
10 可能是整数
10.0 可能是实数
当你用它们参与计算时,结果类型、计算方式、精度表现都可能不同。
这就是为什么有时候程序会报:
类型不匹配
不能直接赋值
运算对象不兼容
比如一个 REAL 变量去接收 INT 结果,有时候需要系统自动转换,有时候则需要你明确处理。
所以你一定要建立这种意识:
变量不仅有值,还有“值的类型”。
而程序是很较真的。
你脑子里觉得“都差不多”的东西,它不一定认。
八、地址是什么?SCL 都写变量名了,为什么还要懂地址
这是很多初学者的一个疑问。
既然 SCL 里都写的是:
StartPB
MotorRun
TempPV
StepNo
那我还需要懂 I、Q、M、DB 这些地址概念吗?
答案是:
当然需要,而且必须懂。
因为变量名只是“人看的名字”,而 PLC 最终还是要落到实际的数据存放位置和信号来源上。
你可以把它理解成这样:
1. 地址是 PLC 实际存放和访问数据的位置
例如:
输入区
输出区
内部存储区
数据块
保持区
这些都和实际地址有关。
2. 变量名是给这个数据位置起的“工程名字”
例如:
I0.0 这个输入点,可以起名为 StartPB
Q0.0 这个输出点,可以起名为 MotorContactor
DB10.DBD4 这块数据,可以起名为 TankLevelSetpoint
也就是说:
地址解决“它放在哪儿”,变量名解决“它叫什么、拿来干什么”。
如果你只知道变量名,不理解背后的地址和数据区,工程上会有几个问题:
不知道信号来自哪里
不知道数据是否保持
不知道掉电后是否会丢
不知道是否和 HMI、通信、其他块共用
不知道变量为什么明明改了却没生效
所以,SCL 虽然让你更多使用符号变量,但并不意味着地址概念可以丢掉。
恰恰相反,你要做到的是:
表面上用变量名写得清楚,脑子里仍然知道它背后属于哪一类地址和存储区域。
九、地址思维和变量思维,正确关系到底是什么
这个关系非常值得讲透。
你可以把 PLC 编程分成两个层面:
第一层:物理和存储层
这里关注的是:
输入点接在哪儿
输出点接在哪儿
模拟量放在哪个区
数据存在什么块里
哪些数据掉电保持
哪些数据是临时的
这是地址思维。
第二层:逻辑和功能层
这里关注的是:
这个信号在程序里代表什么
这个值是设定值还是反馈值
这个状态是允许启动还是运行中
这组数据属于哪个模块
这个变量该不该长期保存
这是变量思维。
成熟的 PLC 工程师,不是只会其中一种,而是两种都要有。
因为真正好用的工程程序,必须同时满足:
现场映射清楚
逻辑表达清楚
如果只有地址,没有变量名,程序很难读。
如果只有名字,不清楚背后存储区和来源,程序就容易飘。
十、为什么有些变量“看起来有值”,实际却不稳定
这也是实际工程里常见的问题。
很多初学者会说:
“我这个变量明明刚才算出来了,怎么下一次又不对了?”
背后常见原因有几类。
1. 用了临时变量去保存应该长期记住的状态
比如边沿检测、本周期和上周期比较、步骤保持、故障锁存,这些都不能只靠临时变量草草一放。
2. 没搞清变量是否被别处覆盖
同一个变量可能在:
主程序里写了一次
子程序里又写一次
HMI 又能改
通信也能改
结果看起来值在变,其实是被多处同时操作。
3. 数据类型不对,计算结果被截断
比如:
你算出来 23.8
但变量定义成 INT
最后只剩 23
或者某些比例运算本来该带小数,结果整个计算过程都是整数,精度直接丢掉。
4. 地址或映射关系不清楚
变量名很好看,但背后实际没正确关联到你以为的那个信号区,也会出现“看似有值、实际不对”的情况。
所以你以后排查 SCL 程序时,不要只看逻辑语句。
很多问题其实是变量层面的问题。
十一、变量命名为什么这么重要,甚至比你想象得更重要
很多人会觉得,命名只影响好不好看。
其实它影响的是 可维护性、出错率和协作效率。
例如下面这两组变量:
第一组:
X1
Temp2
RunA
DataNew
Flag5
第二组:
StartPB
ReactorTempPV
ConveyorRunCmd
RecipeDataValid
AlarmResetReq
你不用想都知道,第二组更好维护。
好的命名至少有几个好处:
1. 读变量名就知道用途
不需要来回翻注释和监控表。
2. 不容易误用
比如 PressurePV 和 PressureSP 一眼就能区分反馈值和设定值。
3. 更容易批量查找和整理
项目大了之后,统一命名风格特别重要。
4. 便于和 HMI、文档、电气图对应
程序不是孤立的,命名越清楚,跨部门协作越轻松。
所以从现在开始,你就应该慢慢建立一种习惯:
变量名不是随便取的,它是工程表达的一部分。
十二、给初学者一个非常实用的变量命名思路
不用一开始追求特别复杂,但至少可以遵循这几个原则。
1. 先体现对象,再体现含义
比如:
Motor1_RunCmd
Valve2_OpenFB
Tank1_LevelPV
Heater_Enable
这样比:
Run1
Open2
Value3
清楚太多。
2. 设定值、反馈值、命令值、状态值尽量区分
例如:
SpeedSP:设定值
SpeedPV:实际值
StartCmd:启动命令
RunFB:运行反馈
AlarmAct:报警活动中
AlarmAck:报警已确认
3. 布尔量尽量让人一眼看出真假含义
例如:
AutoMode
FaultExist
StartPermit
ValveOpenFB
TempHighAlarm
布尔量命名越像一句成立与否的话,后面写 IF 越顺。
十三、初学 SCL 时,变量定义最容易犯的几个错误
错误一:所有数字都先用 INT
这是很典型的“先凑合”思路。
但一到模拟量、比例、平均值、滤波,就会出问题。
错误二:需要长期保存的量,当成临时量
状态机、边沿检测、锁存逻辑最容易中招。
错误三:同一个意义的量,不同地方叫法完全不同
时间一长,自己都会看晕。
错误四:只知道变量名,不知道它来自哪里、去向哪里
写的时候很顺,调试时一头雾水。
错误五:把设定值和实际值混用
比如:
温度设定和温度反馈都叫 Temp
速度命令和速度反馈都叫 Speed
这在项目里非常危险。
十四、初学阶段该怎么建立“变量思维”
这里给你一个非常实用的习惯。
以后每定义一个变量,都在脑子里问自己这五个问题:
1. 它存的是什么意义的数据
是按钮状态、温度值、步骤号,还是报警标志?
2. 它是什么类型
是 BOOL、INT、DINT、REAL、TIME,还是 STRING?
3. 它从哪里来
来自输入采集、HMI 设定、通信报文,还是程序中间计算?
4. 它要到哪里去
给输出、给别的块、给 HMI 显示,还是仅本块内部使用?
5. 它需不需要跨扫描周期保留
只本次计算一下,还是必须记住以前的状态?
这五个问题问清楚,变量定义基本就不会太离谱。
十五、从工程角度看,变量定义其实就是在搭程序骨架
很多人以为程序骨架是流程图、功能块图。
实际上,变量体系本身就是骨架的一部分。
因为程序最终靠什么运行?
靠的是:
输入进来
中间处理
结果输出
状态保留
数据传递
而这些全都落在变量身上。
所以一个好的 SCL 程序,往往在你还没写复杂逻辑前,它的变量表就已经透露出结构感了。
你看一眼变量表,就能大致猜出:
这个模块是干什么的
它有哪些输入条件
它会输出什么结果
它有没有状态保持
它是不是处理模拟量
它是不是做步骤控制
这就是为什么成熟工程师看程序,不只看代码,也很看重变量表。
十六、这一篇最后,给你一个很实在的理解方式
你可以这样理解:
地址,是 PLC 世界里的“房间号”;
变量名,是你给这个房间住户起的“名字”;
数据类型,是告诉你这个住户到底是什么身份、能做什么事。
如果只有房间号,没有名字,程序能运行,但很难看懂。
如果只有名字,不清楚房间号和存储区,工程就容易失控。
如果名字和身份说明都不清楚,后面逻辑再复杂也会越来越乱。
所以,SCL 学到这里,你最应该建立起来的,不是某个单独语法点,而是这套意识:
变量不是随手写的
数据类型不是随便选的
地址概念不能丢
是否保持、是否临时、是否输入输出,都要想清楚
变量体系越清楚,程序后面越稳
小结
这一篇你至少要记住下面这些核心点:
变量不是简单的名字,而是有类型、有作用范围、有生命周期的数据容器。
SCL 程序乱,很多时候不是判断语句乱,而是变量体系乱。
常见变量可以分为输入、输出、输入输出、临时变量、静态或保持性变量。
BOOL 适合开关量,INT 适合普通整数,DINT 适合较大整数,REAL 适合带小数的工程量,TIME 处理时间,STRING 处理文本。
数据类型不能乱选,否则会出现截断、溢出、精度丢失或类型不匹配。
SCL 虽然更多写变量名,但地址概念仍然必须懂,因为变量最终还是对应实际数据区和现场信号。
好的变量命名和清晰的数据分类,会直接决定程序后期是否容易维护。
下载资料前请先绑定手机号码