跳到主要内容

SCL 变量声明

SCL 的变量声明遵循 IEC 61131-3 标准,通过声明块关键字控制变量的作用域生命周期持久性可见性。正确的变量声明是编写可靠、可维护 PLC 程序的基础。

声明块总览

声明块作用域生命周期持久性可见性典型用途
VARPOU 内部FB 实例生命周期不保持POU 内读写内部状态变量
VAR_INPUTPOU 只读每次调用赋值外部传入功能块输入参数
VAR_OUTPUTPOU 可写跨调用保持 (FB)不保持外部读取功能块输出结果
VAR_IN_OUTPOU 可写引用调用方跟随调用方引用传递大数据结构引用
VAR_TEMPPOU 内部单次调用不保持POU 内读写临时计算变量
VAR_STATICPOU 内部程序运行期保持POU 内读写跨调用计数
VAR_CONSTANT全局可见编译期确定全项目只读常量定义
VAR_GLOBAL全局共享程序运行期可配置全项目读写全局数据交换
VAR_ACCESS外部接口程序运行期不保持OPC UA / 外部对外暴露变量
VAR_CONFIG实例配置编译期确定实例化时赋值参数化配置

VAR — 内部变量

VAR 块声明 POU 内部的状态变量。对于功能块,变量值在两次调用之间保持;对于函数,不跨调用保持。

FUNCTION_BLOCK FB_MotorControl
VAR
tonRamp : TON; // 内部定时器
rtStart : R_TRIG; // 边沿检测
iState : INT := 0; // 状态机状态
rRampSpeed : REAL := 0.0; // 速度斜坡值
END_VAR

VAR_INPUT — 输入参数

声明由调用方传入的只读参数。简单类型按值传递,复杂类型按引用传递。

FUNCTION_BLOCK FB_PID
VAR_INPUT
bEnable : BOOL;
rSetpoint : REAL;
rFeedback : REAL;
rKp : REAL := 1.0;
stConfig : ST_PIDConfig; // 结构体按引用传递
END_VAR

// 调用语法
fbPID(bEnable := TRUE, rSetpoint := 1500.0, rFeedback := rActSpeed);

VAR_OUTPUT — 输出参数

声明由 POU 返回给调用方的输出结果。FB 实例的输出值在两次调用之间保持。

FUNCTION_BLOCK FB_PID
VAR_OUTPUT
bInRange : BOOL; // 到达设定范围
rOutput : REAL; // PID 输出值
rError : REAL; // 当前误差
END_VAR

VAR_IN_OUT — 输入输出参数 (引用传递)

始终按引用传递,零拷贝开销。POU 内对该参数的修改直接反映到调用方的原始变量。

FUNCTION_BLOCK FB_BufferProcess
VAR_IN_OUT
stBuffer : ST_BufferData; // 引用外部结构体
arSamples : ARRAY[0..1023] OF INT; // 引用外部数组
END_VAR
注意

VAR_IN_OUT 传递的是引用而非副本。希望保护原始数据不被修改时,应使用 VAR_INPUT(复杂类型仍按引用传递,但编译器阻止写入)。

VAR_TEMP — 临时变量

仅当前调用周期内有效,每次调用重新初始化(栈分配)。使用前必须显式赋值,否则为不确定值。

FUNCTION_BLOCK FB_MatrixCalc
VAR_TEMP
i, j : INT; // 循环索引
rSum : REAL; // 中间累加
bFound : BOOL; // 查找标记
END_VAR

VAR_STATIC — 静态变量

跨调用保持但不持久化(掉电丢失)的变量,所有 FB 实例共享。

FUNCTION_BLOCK FB_ComponentManager
VAR_STATIC
siInstanceCount : SINT := 0; // 所有实例共享计数
END_VAR

VAR_CONSTANT — 常量

编译期确定、不可修改的命名常量,运行时零开销。

VAR CONSTANT
MAX_MOTOR_SPEED : REAL := 6000.0;
OVER_TEMP_THRESHOLD : REAL := 85.0;
WATCHDOG_TIMEOUT : TIME := T#500ms;
PI : REAL := 3.14159265;
DEG_TO_RAD : REAL := 0.01745329;
END_VAR
提示

常量全大写、下划线分隔。不要用魔法数字散落在代码中,统一在 POU 顶部 VAR CONSTANT 集中管理。

VAR_GLOBAL — 全局变量

全项目可见的全局变量,在全局变量表或全局 POU 中定义。建议加 g 前缀。

VAR_GLOBAL
giBatchCount : DINT := 0;
gbMachineReady : BOOL := FALSE;
gbEmergencyStop : BOOL := TRUE;
grTargetTemp : REAL := 120.0;
gstProduction : ST_ProductionData;
END_VAR

在 POU 中通过 VAR_EXTERNAL 引用全局变量:

FUNCTION_BLOCK FB_Station1
VAR_EXTERNAL
gbMachineReady : BOOL;
gbEmergencyStop : BOOL;
giBatchCount : DINT;
END_VAR

VAR_ACCESS — 访问变量

对外暴露的变量,用于 OPC UA、DarraLink 远程访问或 HMI 通讯。

VAR_ACCESS
Machine_Status : BOOL := gbMachineReady;
Batch_Count : DINT := giBatchCount;
Temperature_Actual : REAL := grActualTemp;
END_VAR

VAR_CONFIG — 配置变量

在实例化时覆盖 FB 内部 VAR 的初始值,为不同实例配置不同参数。

VAR
fbConveyor1 : FB_Conveyor;
fbConveyor2 : FB_Conveyor;
END_VAR

VAR_CONFIG
fbConveyor1.iMaxSpeed := 3000;
fbConveyor2.iMaxSpeed := 1500;
fbConveyor1.tAccelTime := T#500ms;
fbConveyor2.tAccelTime := T#1s;
END_VAR

命名约定 (匈牙利前缀)

前缀数据类型示例
bBOOLbStart, bReady
byBYTEbyStatus
wWORDwControl
dwDWORDdwErrorCode
siSINTsiLevel
iINTiCount, iIndex
diDINTdiPosition
liLINTliUptime
uiUINTuiVoltage
udiUDINTudiTotalPulses
rREALrTemperature
lrLREALlrAngle
sSTRINGsName
wsWSTRINGwsDisplayText
tTIMEtDelay
a / arARRAYaiBuffer, arMatrix
stSTRUCTstMotorData
e枚举eState, eMode
fbFB 实例fbPID, fbAxis
pPOINTER TOpBuffer
rfREF_TOrfData

前缀组合规则

修饰前缀示例
全局变量g + 类型前缀giBatchCount, grTemperature
RETAIN 变量r + 类型前缀riTotalParts, rrCalibOffset
常量全大写 + 下划线MAX_SPEED, TIMEOUT_MS
VAR
iIndex : INT; // 局部
rTemperature : REAL;
bFault : BOOL;
fbPID : FB_PIDController; // FB 实例
END_VAR

VAR RETAIN
riTotalCount : DINT; // RETAIN 前缀 r
rrCalibOffset : LREAL;
END_VAR

初始值

默认初始化

数据类型默认初始值
BOOLFALSE
BYTE, WORD, DWORD, LWORD0
SINT, INT, DINT, LINT0
USINT, UINT, UDINT, ULINT0
REAL, LREAL0.0
TIMET#0ms
STRING'' (空字符串)
ARRAY各元素按类型默认值
STRUCT各成员按类型默认值
枚举枚举的第一个值
REF_TO, POINTER TO0 (空指针)

显式初始值

VAR
bReady : BOOL := TRUE;
iCounter : INT := 100;
rTemperature : REAL := 25.0;
lrAngle : LREAL := 3.14159265358979;
tCycleTime : TIME := T#100ms;
sDeviceName : STRING[32] := 'Darra PLC';

// 数组初始化
aiPreset : ARRAY[0..4] OF INT := [10, 20, 30, 40, 50];
arZeros : ARRAY[0..99] OF REAL := [100(0.0)];

// 结构体初始化
stMotor : ST_MotorData := (
sName := 'M1', iAxisCount := 6, rMaxSpeed := 3000.0
);

eState : E_MachineState := IDLE;
END_VAR
初始值执行时机
  • 冷启动 (OB100):所有变量重置为声明时的初始值
  • 暖启动/热重启VAR RETAINVAR PERSISTENT 保持上次值,其余重置
  • 在线下载:由用户选择"保留数据"或"使用新初始值"

RETAIN 与 NON_RETAIN

VAR RETAIN — 掉电保持

VAR RETAIN 变量在 PLC 断电、停止、重启后保持最后的值。

VAR RETAIN
riTotalParts : DINT := 0; // 总产量
riGoodParts : DINT := 0; // 合格品
riRejectParts : DINT := 0; // 不合格品
rrCalibOffset : LREAL := 0.0; // 标定偏移
tTotalRunTime : TIME := T#0ms; // 累计运行时间
END_VAR

VAR RETAIN 中的 NON_RETAIN

VAR RETAIN 块中,可用 NON_RETAIN 标记个别变量不保持。

VAR RETAIN
riTotalCount : DINT; // 保持
VAR NON_RETAIN
iTempCounter : INT; // 不保持(即使在 RETAIN 块中)
rScratchPad : REAL;
END_VAR
rrCalibOffset : LREAL; // 保持
END_VAR

RETAIN 与 PERSISTENT 对比

特性VAR RETAINVAR PERSISTENT
掉电保持
热重启保持
冷启动保持可配置(默认清零)✓ 始终保持
程序下载后保持
物理存储NVRAM / UPS 缓存NVRAM + 冗余备份
典型用途产量计数、运行时间标定系数、零点偏移
// 每次冷启动可清零 → RETAIN
VAR RETAIN
riShiftCount : DINT; // 班次产量
END_VAR

// 下载新程序也不能丢 → PERSISTENT
VAR PERSISTENT
rrToolCalib : LREAL; // 工具标定
rrZeroOffset : LREAL; // 零点偏移
END_VAR

AT 声明 — 直接地址映射

AT 关键字将变量直接绑定到指定的内存地址,用于访问物理 I/O、系统变量或 HMI 共享内存。

地址语法

%<区域><大小><偏移>[.<位>]
组成部分说明值范围
%地址标识前缀必选
区域I=物理输入, Q=物理输出, M=内存, D=数据块, S=系统I / Q / M / D / S
大小X=位, B=字节, W=字(2B), D=双字(4B), L=长字(8B)X / B / W / D / L
偏移字节起始偏移0 ~ 65535
仅 X 格式需要0 ~ 7
%IX0.0      // I 区 第0字节 bit0
%IW10 // I 区 第10~11字节 (WORD)
%ID20 // I 区 第20~23字节 (DINT)
%QX0.0 // Q 区 第0字节 bit0
%QW10 // Q 区 第10~11字节
%MD200 // M 区 第200~203字节
%D10.DBW0 // DB10 第0~1字节

物理 I/O 映射

VAR
// ===== 数字量输入 =====
bEmergencyStop AT %IX0.0 : BOOL; // 急停按钮
bStartBtn AT %IX0.1 : BOOL; // 启动按钮
bStopBtn AT %IX0.2 : BOOL; // 停止按钮
bLimitFwd AT %IX1.0 : BOOL; // 正限位
bLimitRev AT %IX1.1 : BOOL; // 负限位

// ===== 数字量输出 =====
bMotorRun AT %QX0.0 : BOOL; // 电机运行
bAlarmLamp AT %QX1.0 : BOOL; // 报警灯

// ===== 模拟量输入 =====
wEncoderPos AT %IW10 : WORD; // 编码器原始值
rTemperature AT %ID20 : REAL; // 温度传感器
rPressure AT %ID24 : REAL; // 压力传感器
diPosition AT %ID30 : DINT; // 绝对位置

// ===== 模拟量输出 =====
wAnalogOut AT %QW10 : WORD; // 模拟量输出原始值
rSpeedSetpoint AT %QD20 : REAL; // 速度设定
END_VAR

HMI 共享内存 (M 区)

VAR
bHMI_Start AT %MX0.0 : BOOL; // HMI 启动指令
bHMI_Stop AT %MX0.1 : BOOL; // HMI 停止指令
iRecipeSelect AT %MW10 : INT; // HMI 配方选择
rSetTemp AT %MD20 : REAL; // HMI 温度设定
rSetSpeed AT %MD24 : REAL; // HMI 速度设定
sOperatorMsg AT %MB100 : STRING[32]; // HMI 操作员消息
END_VAR

地址重叠警告

不同大小标识可能访问同一物理内存,编译器会检查并警告。

声明物理范围
bFlag AT %MX0.0M 区字节 0 的 bit 0
byByte AT %MB0M 区字节 0
wWord AT %MW0M 区字节 0~1
dwDWord AT %MD0M 区字节 0~3
// 危险:wStatus 与 bError 共享同一内存
VAR
wStatus AT %MW0 : WORD; // 占 M0~M1
bError AT %MX0.0 : BOOL; // 与 wStatus 低位重叠!
END_VAR

// 安全做法:统一 WORD 访问,再位提取
bError := (wStatus.0 = 1);

VAR_EXTERNAL — 外部变量访问

在 POU 中引用全局变量时使用 VAR_EXTERNAL 声明,明确表达依赖关系。

FUNCTION_BLOCK FB_ProductionMonitor
VAR_EXTERNAL
gbMachineReady : BOOL;
gbAutoMode : BOOL;
giBatchCount : DINT;
grTargetTemp : REAL;
stProduction : ST_ProductionData;
END_VAR
方式优点缺点
VAR_EXTERNAL 声明显式依赖,便于代码审查和测试需额外声明代码
直接使用全局名代码更简洁隐藏依赖关系,重构困难

变量可见性与访问控制

可见性层级

全局 (VAR_GLOBAL / VAR_ACCESS)
└── 项目内所有 POU 可见
└── 外部接口 (OPC UA / HMI) 通过 VAR_ACCESS 选择性暴露

POU 内部 (VAR / VAR_TEMP / VAR_STATIC)
└── 仅声明所在的 POU 内部可见
└── FB 实例变量在实例间隔离

接口 (VAR_INPUT / VAR_OUTPUT / VAR_IN_OUT)
└── 调用方通过形参赋值访问
└── VAR_INPUT 只读,VAR_OUTPUT 只写,VAR_IN_OUT 读写

封装原则

FUNCTION_BLOCK FB_AxisControl
// ===== 公开接口 =====
VAR_INPUT
bEnable : BOOL;
rTargetPos : LREAL;
rTargetSpeed : REAL;
END_VAR

VAR_OUTPUT
bHomed : BOOL;
bInPosition : BOOL;
rActualPos : LREAL;
bFault : BOOL;
iErrorCode : INT;
END_VAR

// ===== 内部实现 (对外不可见) =====
VAR
fbPositionPID : FB_PIDController;
fbSpeedPID : FB_PIDController;
eState : E_AxisState;
rRampSpeed : REAL;
END_VAR

访问控制策略

策略实现方式示例场景
封装内部状态敏感变量放 VAR,不暴露到 VAR_OUTPUTPID 内部误差累积值
只读暴露通过 VAR_OUTPUT 暴露读接口当前位置、速度
参数化配置VAR_INPUT + 默认值PID 参数、限值
全局共享VAR_GLOBAL + VAR_EXTERNAL生产数据、报警状态
外部接口VAR_ACCESSOPC UA 变量
掉电保护VAR RETAIN / VAR PERSISTENT标定参数、累计值

最佳实践

声明块顺序

固定顺序:VAR_INPUTVAR_OUTPUTVAR_IN_OUTVARVAR_TEMPVAR_STATICVAR_CONSTANTVAR RETAIN

FUNCTION_BLOCK FB_BestPractice
VAR_INPUT ... END_VAR
VAR_OUTPUT ... END_VAR
VAR_IN_OUT ... END_VAR
VAR ... END_VAR
VAR_TEMP ... END_VAR
VAR_STATIC ... END_VAR
VAR CONSTANT ... END_VAR
VAR RETAIN ... END_VAR
VAR PERSISTENT ... END_VAR
END_FUNCTION_BLOCK

命名规范

// ✅ 良好命名
bEmergencyStop : BOOL; // 急停按钮状态
iCurrentSpeed : INT; // 当前速度 (rpm)
rTemperatureActual : REAL; // 实际温度 (°C)
stMotorStatus : ST_MotorStatus;

// ❌ 不良命名
bFlag1 : BOOL; // 含义不明
iData : INT; // 太泛
rX : REAL; // 无上下文

常见错误

问题根因解决方案
变量未声明忘记在 VAR 块声明编译器报错,按提示补充
地址冲突%MW0%MB0 重叠重新规划地址分配
RETAIN 丢失NVRAM 电池耗尽更换电池;重要数据加 PERSISTENT
VAR_IN_OUT 误改源引用传递的副作用不需改源数据时改用 VAR_INPUT
初始值不生效热重启而非冷启动切到冷启动 (OB100) 或手动复位
临时变量随机值VAR_TEMP 未初始化使用前显式赋值
枚举值比较错误忘加类型前缀E_State.RUNNING 而非 RUNNING

推荐声明模板

FUNCTION_BLOCK FB_ConveyorControl

// --- 输入参数 ---
VAR_INPUT
bStart : BOOL; // 启动指令 (上升沿有效)
bStop : BOOL; // 停止指令 (上升沿有效)
rSetSpeed : REAL := 1000.0; // 目标速度 (rpm)
END_VAR

// --- 输出参数 ---
VAR_OUTPUT
bRunning : BOOL; // 运行中
rActualSpeed : REAL; // 实际速度 (rpm)
bFault : BOOL; // 故障
iErrorCode : INT; // 错误码
END_VAR

// --- 内部状态 ---
VAR
tonRamp : TON; // 加速斜坡定时
rtStart : R_TRIG; // 启动上升沿
eState : INT := 0; // 状态机
rInternalSpeed : REAL := 0.0; // 速度斜坡值
END_VAR

// --- 临时变量 ---
VAR_TEMP
iLoop : INT; // 循环索引
bAllClear : BOOL; // 安全条件汇总
END_VAR

// --- 常量 ---
VAR CONSTANT
ACCEL_RATE : REAL := 50.0; // 加速度 (rpm/cycle)
MAX_SPEED : REAL := 3000.0; // 最高速度 (rpm)
END_VAR

// --- 掉电保持 ---
VAR RETAIN
riRunHours : DINT := 0; // 累计运行小时数
riStartCount : DINT := 0; // 累计启动次数
END_VAR

// 程序主体
bAllClear := NOT bFault;
// ... 控制逻辑

END_FUNCTION_BLOCK

相关文档