西门子PLC的位运算与移位操作技巧
在PLC编程中,位运算与移位操作是处理二进制数据的核心技术。掌握这些技巧,能够让你在处理开关量、数据打包、状态标志等场景时事半功倍。本文将系统讲解西门子S7系列PLC中这些操作的原理与实战技巧。
1位运算基础与实战
位运算操作直接作用于二进制位的逻辑关系,是PLC编程中最基本也是最强大的工具之一。
1.1 基本位逻辑运算
西门子PLC提供四种基本位运算:与(AND)、或(OR)、非(NOT)、异或(XOR)。每种运算都有特定的适用场景。
与运算(AND) 用于提取数据的特定位。假设你有一个字节型数据 MB0,其中bit0-bit3存储了设备状态编码,bit4-bit7是保留位。现在只想读取低四位的状态,可以使用与运算屏蔽高四位:
// 假设 MB0 = 10111011 (十六进制 BB)
// 想要提取低四位
// 掩码:00001111 (十六进制 0F)
// 结果:00001011 (十进制 11)
LD MB0
AW< W#16#0F // 与字立即数 0x0F
= MB10 // 结果存入 MB10
或运算(OR) 用于将特定位置1。设备控制中常见需求是强制将某个标志位置1而不影响其他位:
// 假设状态字 MW20 = 0000000000100100
// 需要将 bit5 置1 (报警标志)
// 掩码:0000000000100000 (十六进制 0020)
LD MW20
OW< W#16#20 // 或字立即数 0x0020
= MW22 // 结果:0000000000100100 | 0000000000100000 = 0000000000100100
非运算(NOT) 用于位取反。在生成反向信号或创建互补标志时特别有用:
// 将运行标志取反得到停止标志
LD "运行标志"
NOT
= "停止标志"
异或运算(XOR) 的特性是相同为0、不同为1,这在 Toggle 开关(每次触发取反)中非常实用:
// 按钮每按一次,输出状态翻转一次
LD "按钮按下"
EU // 上升沿检测
XOR "toggle状态" // 与当前状态异或
= "toggle状态"
1.2 位运算组合技巧
在实际项目中,单一位运算往往不够用,需要组合使用。下面讲解几个经典组合。
提取多个非连续位:假设从控制字中提取bit2和bit5的状态,组成一个2位数值。思路是分别提取两位,然后移位合并:
// 控制字 MW100 = xxxx xxxx xxxx xxxx
// 提取 bit2 -> 移位到 bit0
// 提取 bit5 -> 移位到 bit1
LD MW100
AW< W#16#04 // 提取 bit2 (0000 0000 0000 0100)
= MW102
LD MW100
AW< W#16#20 // 提取 bit5 (0010 0000)
= MW104
// 实际上更高效的做法是一次完成:
LD MW100
AW< W#16#24 // 组合掩码:04 | 20 = 24
SRW 2 // 右移2位,bit5现在到了bit3位置
AW< W#16#03 // 再提取低2位
= MB200 // 结果:00bb (b是原始的bit2和bit5)
条件标志位设置:在状态机编程中,经常需要根据不同条件设置对应的状态位。可以使用或运算累积设置:
// 初始状态字
LD W#16#0000
= "状态字"
// 条件1满足则置 bit0
LD "条件1"
= M0.0
LD M0.0
OD "状态字"
= "状态字"
// 条件2满足则置 bit1
LD "条件2"
= M0.1
LD M0.1
OD "状态字"
= "状态字"
2移位操作详解
移位操作将数据各位向左或向右移动指定的位数,是实现数据打包、循环控制、乘除运算的高效手段。
2.1 移位指令家族
西门子PLC提供多种移位指令,适用范围各不相同:
| 指令 | 功能 | 数据类型 | 典型应用 |
|---|---|---|---|
SLW |
逻辑左移 | 字/双字 | 乘2^n、快速乘运算 |
SRW |
逻辑右移 | 字/双字 | 除2^n、快速除运算 |
RLD |
循环左移 | 双字 | 数据轮询、环形缓存 |
RRD |
循环右移 | 双字 | 数据轮询、环形缓存 |
SSI |
有符号右移 | 整数 | 保留符号的除2运算 |
2.2 逻辑移位实操
逻辑左移 SLW 将各位依次向左移动,低位补0,高位溢出丢失。每左移一位相当于乘以2。这在需要快速乘以2的幂次时比乘法指令更高效:
// 将 MB0 的值乘以 8 (2^3)
LD MB0
SLW 3 // 左移3位
= MB10 // 结果 = MB0 * 8
逻辑右移 SRW 将各位依次向右移动,高位补0,低位溢出丢失。每右移一位相当于除以2取整。这在处理编码器脉冲计数时特别有用:
// 编码器每转产生1024个脉冲
// 当前脉冲计数在 MD50
// 需要计算转数 (取整)
LD MD50
SRW 10 // 右移10位 = 除以1024
= MD60 // 结果 = 转数
2.3 循环移位实操
循环左移 RLD 和 循环右移 RRD 与逻辑移位的区别在于:从一端移出的位会从另一端移入,形成环形结构。这在实现循环指示灯、轮询调度等场景中非常有用:
// 实现4个灯的循环点亮
// 初始状态:0001 (灯1亮)
LD "首次扫描"
= M0.0
// 初始化
LD M0.0
= "灯状态"
// 定时器触发移位
LD "定时器1".Q
RRD 1 // 循环右移1位
= "灯状态"
循环移位的典型应用——位状态轮询:在大型系统中需要定期轮询检查多个设备状态,可以使用循环移位配合指针:
// 轮询检查8个温度传感器
// 初始轮询指针 P#0.0
// 每次扫描后移动指针
LD "轮询完成"
RRD 3 // 指针移动到下一个字节的bit0 (8位 = 3位偏移)
= "当前指针"
// 使用指针读取对应传感器状态
LD "当前指针"
= P#M50.0 // 指向 M50.0
2.4 有符号移位
有符号右移 SSI 在右移时保持符号位不变。这意味着正数高位补0,负数高位补1(负数的二进制表示中最高位为1)。这确保右移后数值的符号不变:
// 有符号整数 MW100 = -8 (1111111111111000)
// 右移2位
LD MW100
SSI 2 // 结果:1111111111111110 = -2
// -8 / 4 = -2 (向下取整)
// 对比逻辑右移 SRW:
// SRW 2 // 结果:0011111111111110 = 16374 (变成了正数)
3位运算与移位组合应用
将位运算与移位操作组合使用,能够解决复杂的实际问题。
3.1 数据打包与解包
在通信协议或数据存储中,经常需要将多个离散数据打包成连续字节,或从连续字节中解包出多个数据。
打包示例:将3个5位数值(范围0-31)紧凑存储到2个字节中。思路是依次移位并用或运算合并:
// 假设:
// A = 0-31 (5位)
// B = 0-31 (5位)
// C = 0-31 (5位)
// 总共需要 15 位,2个字节足够
// 打包过程:
// Byte0: A的低5位 | B的高3位
// Byte1: B的低2位 | C的全部5位 | 预留1位
// 步骤1:准备数据(假设已在 MW10, MW12, MW14)
LD MW10
SLW 11 // A 左移11位 (到 bit11-15)
= MD20
LD MW12
SLW 6 // B 左移6位 (到 bit6-10)
OD MD20
= MD20
LD MW14
SLW 1 // C 左移1位 (到 bit1-5)
OD MD20
= MD20 // 打包完成,结果在 MD20
解包示例:从上述打包数据中提取原始值:
// 从 MD20 解包出 A, B, C
// 提取 A (bit11-15)
LD MD20
SRW 11 // 右移11位
AW< W#16#1F // 保留低5位 (掩码 0000000000011111)
= MW30 // 得到 A
// 提取 B (bit6-10)
LD MD20
SRW 6 // 右移6位
AW< W#16#1F // 保留低5位
= MW32 // 得到 B
// 提取 C (bit1-5)
LD MD20
SRW 1 // 右移1位
AW< W#16#1F // 保留低5位
= MW34 // 得到 C
3.2 状态编码与译码
位运算可以实现高效的状态编码和译码功能。
状态编码:将多个布尔状态压缩为一个整数表示,便于存储和比较:
// 设备状态监控
// 4个传感器:运行中、故障、报警、维护请求
// 编码为 4位数值:bit3=运行 bit2=故障 bit1=报警 bit0=维护
// 编码过程
LD "运行中"
= M0.0
LD "故障"
= M0.1
LD "报警"
= M0.2
LD "维护请求"
= M0.3
// 组合编码
LD M0.0
OD "状态编码"
LD M0.1
OD "状态编码"
LD M0.2
OD "状态编码"
LD M0.3
OD "状态编码"
= "状态编码"
状态译码:从编码值中判断特定状态:
// 从"状态编码"判断是否故障
LD "状态编码"
AW< W#16#04 // 检测 bit2 (故障位)
JCN NO_FAULT // 非零则跳转
// 故障处理
SET
= "故障标志"
NO_FAULT: NOP 0
3.3 快速乘除运算
利用移位替代乘法或除法指令,可以显著提升扫描周期敏感型程序的执行效率:
// 常规乘法:MD0 * 10
// 优化写法:MD0 * 8 + MD0 * 2
LD MD0
SLW 3 // *8
= MD10
LD MD0
SLW 1 // *2
= MD14
LD MD10
OD MD14
= MD20 // 结果
// 常规除法:MD0 / 8
// 优化写法:右移3位
LD MD0
SRW 3
= MD30 // 结果
性能对比:在S7-1200/1500系列中,移位指令的执行周期通常比乘法指令快30%-50%。对于每秒需要执行数万次的高速计数场景,这种优化效果明显。
4常见陷阱与解决方案
4.1 数据类型不匹配
移位和位运算对数据类型有严格要求。字(16位)和双字(32位)操作必须使用对应指令,混用会导致错误:
// 错误示例:字数据使用双字移位指令
LD MW0 // 字类型
SLD 3 // 双字左移指令 - 错误!
// 正确写法
LD MW0
SLW 3 // 字左移 - 正确
4.2 移位位数超限
移位位数必须小于数据类型宽度。字操作不超过16,双字操作不超过32:
// 错误:字左移16位
LD MW0
SLW 16 // 超限!结果不确定
// 正确:字左移5位
LD MW0
SLW 5 // 有效移位
4.3 有符号数处理
处理有符号数据时,普通逻辑移位会破坏符号位。负数的二进制表示比较特殊,最高位为1表示负数:
// 负数 -1 的16位表示:1111111111111111
// 逻辑右移1位:0111111111111111 = 32767 (变成正数!)
// 正确做法:使用有符号移位
LD MW0 // MW0 = -1
SSI 1 // 有符号右移1位:1111111111111111 = -1 (符号保持)
5实际工程案例
5.1 编码器脉冲分频
设备使用2000线编码器,但PLC高速计数器最高输入频率受限,需要4分频后接入:
// 编码器脉冲接入 I0.0
// 使用系统时钟脉冲
// 在OB1中:
LD "首次扫描"
= M0.0
// 初始化分频计数器
LD M0.0
= "分频计数"
LD I0.0
EU
JDOV 计数器溢出
// 每次脉冲加1
LD "分频计数"
+I 1
= "分频计数"
// 检查是否达到4
L "分频计数"
>=I 4
JC 输出脉冲
// 未达4,返回
BE
// 输出一分频脉冲
输出脉冲:
LD 1
= Q0.0 // 分频后的脉冲输出
// 计数器归零重新计数
LD 0
= "分频计数"
计数器溢出:
LD 0
= "分频计数"
5.2 多按钮组合功能
通过位运算识别多个按钮的组合状态,实现短按、长按、多键组合等功能:
// 定义:
// I0.0 = 按钮A
// I0.1 = 按钮B
// I0.2 = 按钮C
// 读取当前按键组合
LD I0.0
OD I0.1
OD I0.2
= MB100 // 组合编码:bit2=C, bit1=B, bit0=A
// 判断单独按A
LD MB100
AW< W#16#01
= "单独按A"
// 判断A+B组合
LD MB100
AW< W#16#03
= "AB组合"
// 判断长按(需要定时器配合)
LD I0.0
= "按钮A_状态"
LD "按钮A_状态"
NOT
= "按钮A_下降沿"
LD "按钮A_状态"
LD T1
= "长按标志" // T1为2秒定时器
6总结
位运算与移位操作是PLC编程中不可或缺的底层技能。掌握本文讲解的与或非异或四种位运算,能够完成数据提取、标志设置、状态翻转等功能;理解逻辑移位与循环移位的区别,能够实现乘除运算、数据轮询、快速编码;学会组合运用这些技巧,能够完成数据打包、状态译码等复杂任务。在实际项目中,根据数据类型选择合适的指令,注意有符号数的特殊处理,避免移位位数超限等常见错误,就能在西门子PLC中灵活运用这些强大功能。

暂无评论,快来抢沙发吧!