当前位置: 首页 > news >正文

博图SCL语言中常用运算符使用详解及实战案例(下)

二、运算符优先级 (从高到低)

理解优先级对于避免逻辑错误至关重要。当不确定时,使用括号`()`是最安全、最清晰的做法。

1.  `()` (括号)
2.  `NOT`, `-` (取负) - 一元运算符
3.  `**` (幂)
4.  `*`, `/`, `MOD`
5.  `+`, `-`(加减)
6.  `=`, `<>`, `>`, `<`, `>=`, `<=` (比较运算符)
7.  `AND`, `&` (逻辑与/按位与)
8.  `XOR` (逻辑异或/按位异或)
9.  `OR` (逻辑或/按位或)
10. `:=` (赋值)

三、实战案例

 案例1:电机控制联锁 (逻辑与、比较运算符)

FUNCTION_BLOCK MotorControl
VAR_INPUT
StartButton: BOOL;      // 启动按钮信号
StopButton: BOOL;       // 停止按钮信号
OverTemp: BOOL;         // 过热信号 (TRUE表示过热)
LubOilPressureOK: BOOL; // 润滑油压正常信号 (TRUE表示正常)
SpeedActual: REAL;      // 实际转速
END_VAR
VAR_OUTPUT
MotorRunCmd: BOOL;      // 电机运行命令输出
END_VAR
VAR
StartPermitted: BOOL;   // 内部启动允许标志
END_VAR

  // 启动允许条件:无过热、润滑油压正常、转速为零(防止带载启动)
StartPermitted := NOT OverTemp AND LubOilPressureOK AND (SpeedActual <= 0.1);

  // 电机运行命令逻辑:启动允许时按下启动按钮则启动,或已运行时未按停止按钮则保持运行
MotorRunCmd := (StartPermitted AND StartButton AND NOT StopButton) OR (MotorRunCmd AND NOT StopButton);

  // 安全联锁:一旦过热或油压丢失,立即停止电机 (覆盖启动命令)
IF OverTemp OR NOT LubOilPressureOK THEN
MotorRunCmd := FALSE;
END_IF;

END_FUNCTION_BLOCK

案例2:状态字解析 (位操作、比较运算符)
假设设备状态通过一个`WORD`(16位) `statusWord`返回,不同位代表不同状态(如0位=就绪,1位=运行,2位=故障,3位=警告...)。

FUNCTION ParseStatusWord : BOOL // 返回TRUE表示有严重故障需要停机
VAR_INPUT
statusWord: WORD; // 设备状态字
END_VAR
VAR_TEMP
isReady, isRunning, isFault, isWarning: BOOL;
END_VAR

  // 使用位掩码提取状态位
isReady := (statusWord AND 16#0001) <> 0; // 检查第0位 (掩码 16#0001 = 2#0000_0000_0000_0001)
isRunning := (statusWord AND 16#0002) <> 0; // 检查第1位 (掩码 16#0002 = 2#0000_0000_0000_0010)
isFault := (statusWord AND 16#0004) <> 0; // 检查第2位 (掩码 16#0004 = 2#0000_0000_0000_0100)
isWarning := (statusWord AND 16#0008) <> 0; // 检查第3位 (掩码 16#0008 = 2#0000_0000_0000_1000)

  // 更新HMI或进行逻辑判断
// 例如:如果有故障位(isFault)被置位,或者设备应该在运行但未运行(isRunning应为TRUE但实际FALSE),则返回TRUE表示严重故障
ParseStatusWord := isFault OR (isReady AND NOT isRunning AND ...); // ... 根据具体逻辑补充条件

  // 或者使用移位和类型转换检查特定位 (另一种方法)
// isReady := BOOL((statusWord SHR 0) AND 1); // 右移0位后取最低位

END_FUNCTION

案例3:模拟量限幅与报警 (比较运算符、算术运算符)

FUNCTION ProcessTemperature : REAL
VAR_INPUT
rawTempInput: INT; // 来自AI模块的原始值 (例如 0-27648对应0.0-100.0℃)
scaleMin: REAL := 0.0; // 量程下限
scaleMax: REAL := 100.0; // 量程上限
alarmHigh: REAL := 85.0; // 高温报警阈值
alarmLow: REAL := 10.0; // 低温报警阈值
END_VAR
VAR_OUTPUT
scaledTemp: REAL; // 工程单位温度值
highAlarm: BOOL;  // 高温报警输出
lowAlarm: BOOL;   // 低温报警输出
END_VAR
CONST
rawMax: INT := 27648; // AI模块满量程原始值
END_CONST

  // 1. 标度转换 (注意避免整数除法截断!)
scaledTemp := scaleMin + ( (scaleMax - scaleMin) * REAL(rawTempInput) / REAL(rawMax) );

  // 2. 输出限幅 (可选,确保输出在工程范围内)
scaledTemp := LIMIT(MIN := scaleMin, MAX := scaleMax, IN := scaledTemp);

  // 3. 报警判断
highAlarm := scaledTemp > alarmHigh;
lowAlarm := scaledTemp < alarmLow;

  // 返回处理后的温度值
ProcessTemperature := scaledTemp;

END_FUNCTION

案例4:使用MOD实现循环计数/分时操作

// 在周期性任务中调用 (例如 OB30)
PROGRAM Main
VAR
cycleCounter: INT := 0; // 循环计数器
task1Active, task2Active, task3Active: BOOL;
END_VAR

  // 每周期计数器加1
cycleCounter := cycleCounter + 1;

  // 使用MOD 3 将计数分为3个阶段 (0,1,2)
CASE (cycleCounter MOD 3) OF
0: // 阶段0
task1Active := TRUE;
task2Active := FALSE;
task3Active := FALSE;
// 执行任务1...
1: // 阶段1
task1Active := FALSE;
task2Active := TRUE;
task3Active := FALSE;
// 执行任务2...
2: // 阶段2
task1Active := FALSE;
task2Active := FALSE;
task3Active := TRUE;
// 执行任务3...
END_CASE;

  // 防止计数器过大溢出 (可选)
IF cycleCounter >= 30000 THEN
cycleCounter := 0;
END_IF;

END_PROGRAM

案例4:使用MOD实现循环计数/分时操作
```scl
// 在周期性任务中调用 (例如 OB30)
PROGRAM Main
VAR
cycleCounter: INT := 0; // 循环计数器
task1Active, task2Active, task3Active: BOOL;
END_VAR

  // 每周期计数器加1
cycleCounter := cycleCounter + 1;

  // 使用MOD 3 将计数分为3个阶段 (0,1,2)
CASE (cycleCounter MOD 3) OF
0: // 阶段0
task1Active := TRUE;
task2Active := FALSE;
task3Active := FALSE;
// 执行任务1...
1: // 阶段1
task1Active := FALSE;
task2Active := TRUE;
task3Active := FALSE;
// 执行任务2...
2: // 阶段2
task1Active := FALSE;
task2Active := FALSE;
task3Active := TRUE;
// 执行任务3...
END_CASE;

  // 防止计数器过大溢出 (可选)
IF cycleCounter >= 30000 THEN
cycleCounter := 0;
END_IF;

END_PROGRAM

四、关键总结与最佳实践

1.  明确赋值`:=` vs 比较`=`:** 这是SCL新手最常见的错误。赋值用`:=`,比较是否相等用`=`。
2.  警惕整数除法`/`: `INT / INT` 或 `DINT / DINT` 结果会被**截断**为整数!要得到浮点结果,必须将至少一个操作数转换为`REAL`或`LREAL`(使用`REAL()`函数或在变量声明时使用浮点类型)。
3.  理解位操作`AND`, `OR`, `XOR`, `NOT`, `SHR`, `SHL`:这是处理状态字、标志位、通信协议数据的利器。务必清楚是按位操作(操作数是整数)还是逻辑操作(操作数是`BOOL`)。
4.  利用`MOD`:实现循环计数、奇偶判断、分时任务调度非常方便。
5.  善用括号`()`: 当表达式复杂或对优先级不确定时,使用括号强制指定计算顺序。这能显著提高代码可读性和避免逻辑错误。
6.  注意短路求值: `AND`和`OR`运算符在可能的情况下会短路求值(`AND`遇到`FALSE`则停止,`OR`遇到`TRUE`则停止)。利用这点可以将计算代价高的条件或可能出错的条件(如除以零检查)放在后面。`&`和`OR`(当用于`BOOL`)不短路。
7.  浮点数比较精度: 不要直接用`=`比较两个`REAL`或`LREAL`是否完全相等(由于浮点精度误差)。应检查它们的差值是否小于一个很小的容差`eps` (e.g., `ABS(a - b) < 1.0e-6`)。

熟练掌握SCL运算符是编写高效、可靠PLC程序的基础。结合具体的自动化控制任务多加练习,就能灵活运用这些运算符解决实际问题。

http://www.xdnf.cn/news/1150831.html

相关文章:

  • OpenCV 官翻 3 - 特征检测 Feature Detection
  • 【无标题】重点阅读——如何在信息层面区分和表征卷曲维度,解析黑洞内部的维度区分机制
  • 《命令行参数与环境变量:从使用到原理的全方位解析》
  • 搭建比分网服务器怎么选数据不会卡顿?
  • lvs原理及实战部署
  • 【I2C】01.I2C硬件连接I2C总线时序图讲解
  • Go语言pprof性能分析指南
  • Temperature 是在LLM中的每一层发挥作用,还是最后一层? LLM中的 Temperature 参数 是怎么计算的
  • 操作系统-分布式同步
  • TCP/UDP协议深度解析(四):TCP的粘包问题以及异常情况处理
  • GaussDB 数据库架构师修炼(六) 集群工具管理-1
  • 异步解决一切问题 |消息队列 |减少嵌套 |hadoop |rabbitmq |postsql
  • 深入解析 Amazon Q:AWS 推出的企业级生成式 AI 助手
  • 【设计模式C#】外观模式(用于解决客户端对系统的许多类进行频繁沟通)
  • LangGraph教程10:LangGraph ReAct应用
  • 访问 gitlab 跳转 0.0.0.0
  • 深入理解设计模式:策略模式的艺术与实践
  • XSS原型与原型链
  • 告别项目混乱:基于 pnpm + Turborepo 的现代化 Monorepo 工程化最佳实践
  • C++控制台贪吃蛇开发:从0到1绘制游戏世界
  • Git 完全手册:从入门到团队协作实战(2)
  • GaussDB union 的用法
  • Maven 依赖管理
  • Java从入门到精通:全面学习路线指南
  • uniapp props、$ref、$emit、$parent、$child、$on
  • MySQL练习3
  • 【橘子分布式】gRPC(编程篇-中)
  • 《Origin画百图》之多分类矩阵散点图
  • 从零开始学Tailwind CSS : 颜色配置原理与实践
  • (后者可以节约内存/GPU显存)Pytorch中求逆torch.inverse和解线性方程组torch.linalg.solve有什么关系