当前位置: 首页 > 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.lryc.cn/news/593360.html

相关文章:

  • LangGraph教程10:LangGraph ReAct应用
  • Python Pandas读取Excel表格中数据并根据时间字段筛选数据
  • 月舟科技近调记录
  • 网络爬虫概念初解
  • ndexedDB 与 LocalStorage:全面对比分析
  • C++数据结构————集合
  • 【Keil5-map文件】
  • 阿里云服务器 CentOS 7 安装 MySQL 8.4 超详细指南
  • c#泛型集合(ArrayList和List、Dictionary的对比)
  • 每日面试题09:进程、线程、协程的区别
  • 48Days-Day03 | 删除公共字符,两个链表的第一个公共结点,mari和shiny
  • 【每日算法】专题十五_BFS 解决 FloodFill 算法
  • HD Video Converter Factory pro 高清视频转换器 v27.7.0 绿色中文便携版
  • 【2025最新】 .NET FrameWork微软离线运行库合集,一键安装版
  • Spring之【AnnotatedBeanDefinitionReader】
  • 前端面试专栏-工程化:28.团队协作与版本控制(Git)
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现动物分类(C#源码,UI界面版)
  • Selenium 中 findElement 方法全解析:定位网页元素的 7 种方式
  • RPC(Remote Procedure Call,远程过程调用)介绍
  • 探秘边缘安全架构设计要点解析
  • 深入了解 find_element 方法:Web 自动化定位元素的核心​
  • Node.js特训专栏-实战进阶:17.会话管理与安全存储
  • 开发框架安全ThinkPHPLaravelSpringBootStruts2SpringCloud复现
  • SLAM中的非线性优化-2D图优化之激光SLAM基于优化的前端匹配(十八)
  • KVM中使用桥接模式.运维就业技术教程
  • 零基础学习性能测试-linux服务器监控:CPU监控
  • 【RK3576】【Android14】USB开发调试
  • 《Spring Boot 插件化架构实战:从 SPI 到热插拔的三级跳》
  • Android14 SystemUI 启动流程(2)
  • Verilog *2* SPI-立创逻辑派G1测试-1