跳到主要内容

运算符与表达式

SCL 提供了丰富的运算符用于构建表达式,涵盖算术、比较、逻辑、位运算和赋值操作。本章详细介绍每种运算符的语法、优先级规则和类型转换约定。

算术运算符

运算符名称说明示例结果
+加法数值相加5 + 38
-减法数值相减10 - 46
*乘法数值相乘6 * 742
/除法数值相除,结果为 REAL10 / 33.333333
MOD取模整数除法余数10 MOD 31
**幂运算指数运算2 ** 38.0

除法注意: 整数参与除法时,运算结果提升为 REAL 类型。如需整数截断,使用 TRUNCDIV 指令。

// 算术运算示例
VAR
iA, iB, iSum : INT;
rResult : REAL;
diRemainder : DINT;
END_VAR

iSum := iA + iB; // 加法
rResult := 100.0 / 3.0; // 除法 → 33.33333
diRemainder := 17 MOD 5; // 取模 → 2
rResult := 2.0 ** 10.0; // 幂运算 → 1024.0

比较运算符

所有比较运算符返回 BOOL 类型。

运算符名称说明示例
=等于两值相等为 TRUEiVal = 100
<>不等于两值不等为 TRUEiVal <> 0
<小于左值小于右值为 TRUEiTemp < 85
>大于左值大于右值为 TRUErSpeed > 500.0
<=小于等于左值小于等于右值为 TRUEiCount <= 1000
>=大于等于左值大于等于右值为 TRUEdiPosition >= 0
// 比较运算示例
IF iPressure > 1000 THEN
bOverload := TRUE;
END_IF;

IF diPosition = 0 AND bHomeSensor THEN
bHomed := TRUE;
END_IF;

逻辑运算符

逻辑运算符用于 BOOL 表达式的组合判断,也可用于位置位运算。

运算符等效写法说明真值表 (A, B)
AND&逻辑与TRUE & TRUETRUE
OR逻辑或任一 TRUETRUE
XOR异或两值不同 → TRUE
NOT逻辑非 (单目)NOT TRUEFALSE
// 逻辑运算示例
IF bEnable AND bSafetyGate THEN
bRun := TRUE;
END_IF;

IF bStart OR bManualOverride THEN
bCycleRequest := TRUE;
END_IF;

IF NOT bFault THEN
bReady := TRUE;
END_IF;

// AND 与 & 等效
IF bEnable & bSafetyGate THEN
bRun := TRUE;
END_IF;

位运算符

位运算符作用于 BYTEWORDDWORDLWORD 等位串类型,按位执行逻辑运算或移位操作。

按位逻辑

运算符说明示例结果
AND按位与16#0F AND 16#F016#00
OR按位或16#0F OR 16#F016#FF
XOR按位异或16#0F XOR 16#F016#FF
NOT按位取反 (单目)NOT 16#0F16#F0 (以 BYTE 为例)

移位与循环

运算符名称方向说明
SHL左移低位补 0,高位丢弃
SHR右移高位补 0,低位丢弃
ROL循环左移移出的高位回填到低位
ROR循环右移移出的低位回填到高位

移位运算符的第二个操作数为移位位数(UINTINT 常量)。

// 位运算示例
VAR
wStatus : WORD;
wControl : WORD;
wResult : WORD;
dwFlags : DWORD;
dwMasked : DWORD;
END_VAR

// 按位设置标志位
wControl := 16#0000;
wControl := wControl OR 16#0001; // 置位 Bit 0
wControl := wControl OR 16#0080; // 置位 Bit 7

// 按位清除标志位
wStatus := wStatus AND NOT 16#0004; // 清除 Bit 2

// 位掩码检测
IF (wStatus AND 16#0002) <> 0 THEN
// Bit 1 为 TRUE
END_IF;

// 左移 3 位
wResult := wStatus SHL 3;

// 右移 2 位
wResult := wStatus SHR 2;

// 循环左移 4 位
wResult := ROL(wStatus, 4);

// 循环右移 4 位
wResult := ROR(wStatus, 4);

// DWORD 掩码操作
dwMasked := dwFlags AND 16#00FF0000;
dwFlags := dwFlags OR 16#00010000;

赋值运算符

运算符名称说明
:=赋值将右值赋给左变量

赋值是 SCL 中最基本的操作,等号右边可以是字面量、变量、函数调用或任意复杂表达式。

// 赋值示例
iCounter := 0; // 字面量赋值
rSetpoint := rMasterSpeed * 0.75; // 表达式赋值
bReady := iTemp < 85 AND iLevel > 0; // 比较表达式赋值
sName := 'Motor_1'; // 字符串赋值
tTimeout := T#500ms; // 时间段赋值
arrData[5] := 100; // 数组元素赋值
stMotor.rSpeed := 1500.0; // 结构体成员赋值

运算符优先级表

从最高优先级到最低优先级,同一行内的运算符优先级相同。

优先级类别运算符结合性
1 (最高)括号(表达式)左到右
2幂运算**右到左
3单目NOT+ (正号)、- (负号)右到左
4乘除*/MOD左到右
5加减+-左到右
6移位SHLSHRROLROR左到右
7比较<><=>=左到右
8等于/不等=<>左到右
9按位与AND左到右
10按位异或XOR左到右
11按位或OR左到右
12 (最低)赋值:=右到左

经验法则:

  • 括号优先:不确定优先级时,用括号明确表达式的计算顺序。
  • 算术高于比较,比较高于逻辑:a + b > c AND d 等价于 ((a + b) > c) AND d
  • 逻辑与 (AND) 优先级高于逻辑或 (OR):a OR b AND c 等价于 a OR (b AND c)

表达式求值顺序

表达式的求值遵循以下规则:

  1. 按优先级从高到低:先算优先级高的运算符,再算优先级低的运算符。
  2. 同优先级从左到右:优先级相同时,从左到右依次计算(幂运算 ** 为右到左)。
  3. 短路求值ANDOR 采用短路求值——左操作数足以确定结果时,右操作数不再计算。
// 短路求值示例
// 如果 iIndex < 0,右侧 arrData[iIndex] 不会计算,避免越界
IF iIndex >= 0 AND iIndex < 100 AND arrData[iIndex] > 0 THEN
bValid := TRUE;
END_IF;

// 如果 bFault,右侧的复杂函数调用不会执行
IF NOT bFault OR ResetSystem() THEN
bRunning := TRUE;
END_IF;

表达式中的类型转换

隐式提升规则

SCL 在不损失精度和范围的前提下,会自动进行类型提升:

源类型可隐式提升到
SINTINTDINTLINTREALLREAL
INTDINTLINTREALLREAL
DINTLINTREALLREAL
LINTLREAL
USINTUINTUDINTULINTINTDINTLINTREALLREAL
UINTUDINTULINTDINTLINTREALLREAL
UDINTULINTLINTREALLREAL
ULINTLREAL
REALLREAL

规则:

  • 有符号和无符号混合表达式中,有符号类型优先提升到足够容纳两者的更大类型。
  • REALLREAL 不会自动提升为整数类型——整数到浮点可提升,反之必须显式转换。
  • TIMEDATETODDT 在内部以整数存储,但与其他类型混合运算时需显式转换。

显式类型转换

当隐式转换不可用时,使用类型转换函数:

VAR
iVal : INT;
rVal : REAL;
diVal : DINT;
byArr : ARRAY[0..3] OF BYTE;
END_VAR

iVal := INT_TO_INT(100); // 同一类型,无操作
rVal := INT_TO_REAL(iVal); // INT → REAL
iVal := REAL_TO_INT(rVal); // REAL → INT(截断小数)
diVal := REAL_TO_DINT(rVal); // REAL → DINT
byArr := DWORD_TO_BYTE_ARRAY(16#12345678); // DWORD → 字节数组

集合运算 — IN 运算符

IN 运算符用于判断值是否属于给定的集合范围,返回 BOOL 类型。

// IN 运算符语法
// <值> IN [<元素1>, <元素2>, ...]
// <值> IN <下限>..<上限>

// 示例
IF iState IN [1, 2, 3] THEN
// iState 为 1、2 或 3
bValidState := TRUE;
END_IF;

IF iSpeed IN 1000..3000 THEN
// iSpeed 在 1000 到 3000 之间(含边界)
bInRange := TRUE;
END_IF;

// 组合使用
IF iErrorCode IN [10, 20, 30..50] THEN
// iErrorCode 为 10、20 或在 30..50 范围内
bRecoverable := TRUE;
END_IF;

// 等价于显式比较
IF iErrorCode = 10 OR iErrorCode = 20
OR (iErrorCode >= 30 AND iErrorCode <= 50) THEN
bRecoverable := TRUE;
END_IF;

综合示例

示例 1: 电机速度控制

FUNCTION_BLOCK FB_MotorSpeedControl
VAR_INPUT
bEnable : BOOL;
bFault : BOOL;
rSpeedRef : REAL; // 速度给定 (rpm)
iMode : INT; // 0=停止, 1=低速, 2=中速, 3=高速
END_VAR
VAR_OUTPUT
rSpeedOut : REAL;
bRunning : BOOL;
wStatus : WORD;
END_VAR
VAR
rRampRate : REAL := 10.0;
rMaxSpeed : REAL := 3000.0;
END_VAR

// 模式与速度映射 + 安全逻辑
IF bEnable AND NOT bFault THEN
// 使用 IN 运算符判断模式
IF iMode IN [1, 2, 3] THEN
// 根据模式设定目标速度
CASE iMode OF
1: rSpeedRef := 500.0; // 低速
2: rSpeedRef := 1500.0; // 中速
3: rSpeedRef := 3000.0; // 高速
END_CASE;

// 限幅处理
IF rSpeedRef > rMaxSpeed THEN
rSpeedRef := rMaxSpeed;
END_IF;

// 加减速斜坡
IF rSpeedOut < rSpeedRef THEN
rSpeedOut := rSpeedOut + rRampRate;
ELSIF rSpeedOut > rSpeedRef THEN
rSpeedOut := rSpeedOut - rRampRate;
END_IF;

// 状态字:运行中
wStatus := wStatus OR 16#0001;
bRunning := TRUE;
ELSE
// 无效模式,停止
rSpeedOut := 0.0;
bRunning := FALSE;
wStatus := 16#0000;
END_IF;
ELSE
// 未使能或有故障,安全停止
rSpeedOut := 0.0;
bRunning := FALSE;
wStatus := wStatus AND NOT 16#0001;
wStatus := wStatus OR 16#0008; // 故障状态位
END_IF;
END_FUNCTION_BLOCK

示例 2: 数据校验与位域操作

FUNCTION F_CheckTemperature : BOOL
VAR_INPUT
rCurrentTemp : REAL;
rSetpoint : REAL;
rHysteresis : REAL;
dwAlarmFlags : DWORD;
END_VAR
VAR
rDelta : REAL;
bOverTemp : BOOL;
bUnderTemp : BOOL;
bAlarmActive : BOOL;
END_VAR

// 计算偏差
rDelta := rCurrentTemp - rSetpoint;
IF rDelta < 0.0 THEN
rDelta := -rDelta; // 绝对值
END_IF;

// 判断是否超出滞环范围
bOverTemp := rCurrentTemp > (rSetpoint + rHysteresis);
bUnderTemp := rCurrentTemp < (rSetpoint - rHysteresis);

// 检查报警标志——使用按位与
// 位 0 = 超温报警, 位 1 = 欠温报警, 位 2 = 传感器故障
bAlarmActive := (dwAlarmFlags AND 16#00000007) <> 0;

// 组合判断
IF (bOverTemp OR bUnderTemp) AND NOT bAlarmActive THEN
// 温度超出范围且无硬件报警,产生警告
F_CheckTemperature := TRUE;
ELSE
F_CheckTemperature := FALSE;
END_IF;

// 使用 IN 运算符检查温度是否在合理工作范围
IF rCurrentTemp IN -40.0..85.0 THEN
// 温度在传感器正常工作范围内
// 继续执行后续逻辑
END_IF;
END_FUNCTION

示例 3: 复杂组合表达式

// 电机启动条件——综合使用算术、比较、逻辑、位运算
bStartAllowed :=
(NOT bEmergencyStop) // 急停未触发
AND (diActualPosition >= 0) // 位置有效
AND (rDriveCurrent <= (rRatedCurrent * 1.1)) // 电流在额定 110% 以内
AND (wDriveStatus AND 16#0020) <> 0 // 驱动器就绪位
AND (iMode IN [1, 2, 3]) // 运行模式有效
AND (NOT (dwFaultLog AND 16#0000FF00) <> 0); // 无严重故障

// 位置偏差计算
diPositionError := diTargetPosition - diActualPosition;
IF ABS(diPositionError) > 1000 THEN
bPositionError := TRUE;
END_IF;

// 速度前馈补偿
rFeedForward := (rTargetSpeed * 0.85) + (rAcceleration * 0.15);
rFinalOutput := (rPIDOutput * 0.7) + (rFeedForward * 0.3);