Skip to content

4.2 移位与循环指令

本节将介绍PLC的移位和循环操作指令

学习目标

  • 掌握移位指令的类型和用法
  • 理解逻辑移位与算术移位的区别
  • 能够灵活运用移位指令

1. 移位指令概述

1.1 什么是移位操作

移位操作是将数据的所有位向左或向右移动指定位数的操作。

移位操作示意图:

原始数据:    [1][0][1][1][0][0][1][0]
                ↓  左移2位
移位后:      [1][1][0][0][1][0][0][0]
                      ↑↑
                   补0(左移右侧补0)

原始数据:    [1][0][1][1][0][0][1][0]
                ↓  右移2位
移位后:      [0][0][1][0][1][1][0][0]
               ↑↑
            补0(逻辑右移左侧补0)

1.2 移位指令分类

移位指令类型:

┌─────────────────────────────────────────────────────┐
│                    移位指令                          │
├────────────────┬────────────────┬───────────────────┤
│   逻辑移位      │   算术移位      │   循环移位        │
├────────────────┼────────────────┼───────────────────┤
│ · SHL 逻辑左移 │ · 保留符号位    │ · ROL 循环左移   │
│ · SHR 逻辑右移 │ · 右移时高位    │ · ROR 循环右移   │
│ · 补0          │   补符号位      │ · 移出位回到另端 │
└────────────────┴────────────────┴───────────────────┘

1.3 移位指令通用格式

功能通用指令说明
逻辑左移SHL右侧补0
逻辑右移SHR左侧补0
循环左移ROL移出位回右侧
循环右移ROR移出位回左侧
位移位寄存器SFTR/SFTL位元件批量移位

2. 左移指令(SHL)

2.1 逻辑左移原理

逻辑左移(SHL)原理:

所有位向左移动,右侧补0,左侧移出的位丢弃

示例:左移2位
Before: [1][0][1][1][0][1][0][0] = 0xB4 (180)

After:  [1][1][0][1][0][0][0][0] = 0xD0 (208)
         └─┬─┘            ↑↑
         丢弃            补0

数学意义:左移n位 ≈ 乘以2ⁿ
180 × 4 = 720(但结果溢出,实际为208)

2.2 左移指令梯形图

【梯形图】
              ┌──────────┐
   条件 ─────┤   SHL    │
              │          │
   数据 ─────┤IN    OUT ├───── 结果
   移位数 ───┤N         │
              └──────────┘

【逻辑表达】
结果 := SHL(数据, 移位数);
// 或
结果 := 数据 SHL 移位数;

【数据类型】
· 16位字左移
· 32位双字左移

2.3 位元件左移指令

位元件批量左移(SFTL):

【梯形图】
       条件               源    目标   位数   长度
    ───┤├───────[SFTL 源 目标 位数 长度]───

【参数说明】
· 源:移入数据源
· 目标:移位区起始
· 位数:每次移位位数
· 长度:移位区总长度

【工作过程】
移位区数据向左移动,右侧移入新数据

3. 右移指令(SHR)

3.1 逻辑右移原理

逻辑右移(SHR)原理:

所有位向右移动,左侧补0,右侧移出的位丢弃

示例:右移2位
Before: [1][0][1][1][0][1][0][0] = 0xB4 (180)

After:  [0][0][1][0][1][1][0][1] = 0x2D (45)
        ↑↑            └─┬─┘
       补0            丢弃

数学意义:右移n位 ≈ 除以2ⁿ
180 ÷ 4 = 45

3.2 算术右移

算术右移(SAR)原理:

右移时保留符号位(最高位)

示例:算术右移2位(有符号数-76)
Before: [1][0][1][1][0][1][0][0] = 0xB4 (-76有符号)

After:  [1][1][1][0][1][1][0][1] = 0xED (-19有符号)
        ↑↑              └─┬─┘
      补符号位          丢弃

数学意义:-76 ÷ 4 = -19
保持负数特性

3.3 右移指令梯形图

【梯形图】
              ┌──────────┐
   条件 ─────┤   SHR    │
              │          │
   数据 ─────┤IN    OUT ├───── 结果
   移位数 ───┤N         │
              └──────────┘

【逻辑表达】
结果 := SHR(数据, 移位数);
// 或
结果 := 数据 SHR 移位数;

【数据类型】
· 16位字右移(逻辑)
· 32位双字右移

3.4 位元件右移指令

位元件批量右移(SFTR):

【梯形图】
       条件               源    目标   位数   长度
    ───┤├───────[SFTR 源 目标 位数 长度]───

【参数说明】
· 源:移入数据源
· 目标:移位区起始
· 位数:每次移位位数
· 长度:移位区总长度

【工作过程】
移位区向右移动,左侧移入新数据

4. 循环移位指令(ROL/ROR)

4.1 循环左移(ROL)

循环左移原理:

左侧移出的位回到右侧,形成循环

示例:循环左移2位
Before: [1][0][1][1][0][1][0][0]

After:  [1][1][0][1][0][0][1][0]
                          ↑↑
                    从左侧移出的位

移出的[1][0]回到了右侧

4.2 循环右移(ROR)

循环右移原理:

右侧移出的位回到左侧,形成循环

示例:循环右移3位
Before: [1][0][1][1][0][1][0][0]

After:  [1][0][0][1][0][1][1][0]
        ↑↑↑
   从右侧移出的[1][0][0]

移出的位回到了左侧

4.3 循环移位指令梯形图

【梯形图】
              ┌──────────┐
   条件 ─────┤   ROL    │
              │          │
   数据 ─────┤IN    OUT ├───── 结果
   移位数 ───┤N         │
              └──────────┘

【逻辑表达】
// 循环左移
结果 := ROL(数据, 移位数);

// 循环右移
结果 := ROR(数据, 移位数);

【特点】
· 不丢失任何位
· 适合位图循环显示
· 适合密钥轮换等应用

5. 字移位指令

5.1 字移位指令

字右移(WSFR):

       条件
    ───┤├───────[WSFR 源 目标 长度]───

· 源:移入数据
· 目标:移位区起始
· 长度:移位区长度(字数)

工作原理:
Before: 目标[0]=A, 目标[1]=B, 目标[2]=C, 目标[3]=D, 目标[4]=E
移位后: 目标[0]=源, 目标[1]=A, 目标[2]=B, 目标[3]=C, 目标[4]=D
                              E被移出丢弃

5.2 FIFO/LIFO操作

FIFO(先进先出)队列:

【入队指令】
       条件
    ───┤├───────[SFWR 数据 队列 容量]───  // 数据入队

【出队指令】
       条件
    ───┤├───────[SFRD 队列 目标 容量]───  // 从队列出队

队列结构:
队列[0] = 当前元素个数
队列[1..n] = 数据区

说明:
· FIFO:先入先出,适合排队处理
· LIFO:后入先出,适合堆栈操作

6. 移位寄存器应用

6.1 步进控制

移位寄存器实现步进控制:

需求:控制8个工位依次动作

       节拍信号               移入   步进   位数   长度
    ───┤P├──────[SFTL 1 步进区 位数 长度]───

· 每次节拍信号脉冲,步进区中的1向左移动一位
· 步进区[0]=1→步进区[1]=1→...→步进区[7]=1

输出控制:
       步进区[0]
    ───┤├───────( 工位1 )───

       步进区[1]
    ───┤├───────( 工位2 )───
    ...
       步进区[7]
    ───┤├───────( 工位8 )───

6.2 产品跟踪

应用:传送带产品跟踪

传感器检测产品,跟踪产品在传送带上的位置

       节拍脉冲               入口检测  跟踪区  位数   长度
    ───┤├───────[SFTL 入口检测 跟踪区 位数 长度]───

· 节拍脉冲:传送带节拍信号(如编码器脉冲)
· 入口检测:入口检测(有产品=1)
· 跟踪区:跟踪区域(20个位置)

当跟踪区[10]=1时,表示产品到达位置10
       跟踪区[10]
    ───┤├───────( 位置10动作 )──

6.3 流水灯效果

流水灯程序:

方法1:循环移位

       秒脉冲              数据   移位数
    ───┤├───────[ROL 数据 1 数据]───

       始终
    ───┤├───────[MOV 数据 输出组]───

· 秒脉冲:1秒时钟脉冲
· 数据初始值=1
· 每秒循环左移1位
· 输出到LED组

方法2:表格循环
       秒脉冲
    ───┤P├──────[INC 索引]───
               [索引 > 7]────[MOV 0 索引]───

       始终
    ───┤├───────[SHL 1 索引 输出]───

效果:LED0→LED1→LED2→...→LED7→LED0 循环

7. 移位运算技巧

7.1 乘除法替代

用移位代替乘除法(效率更高):

乘法:
· X × 2  = X SHL 1
· X × 4  = X SHL 2
· X × 8  = X SHL 3
· X × 2ⁿ = X SHL n

除法:
· X ÷ 2  = X SHR 1
· X ÷ 4  = X SHR 2
· X ÷ 8  = X SHR 3
· X ÷ 2ⁿ = X SHR n

示例:X × 10 = X × 8 + X × 2 = (X SHL 3) + (X SHL 1)

7.2 位提取

提取特定位:

提取第n位的值:
结果 = (数据 SHR n) AND 1

【梯形图】提取数据第5位
       始终
    ───┤├───────[SHR 数据 5 中间值]───
               [AND 中间值 1 结果]───

结果 = 数据的第5位值(0或1)

7.3 位设置/清除

设置特定位为1:
数据 = 数据 OR (1 SHL n)

清除特定位为0:
数据 = 数据 AND (NOT (1 SHL n))

翻转特定位:
数据 = 数据 XOR (1 SHL n)

【梯形图】设置数据第3位为1
       始终
    ───┤├───────[SHL 1 3 掩码]───    // 掩码 = 0x08
               [OR 数据 掩码 数据]───  // 数据第3位置1

8. 应用实例

8.1 信号灯循环控制

需求:8个信号灯循环点亮

程序:
// 初始化
       首次扫描                         // 首次扫描标志
    ───┤├───────[MOV 1 数据]───       // 数据 = 0x0001

// 定时移位
       定时器
    ───┤├───────[ROL 数据 1 数据]───    // 循环左移

// 定时器(500ms)
       始终          定时器
    ───┤├─────────┤/├─────[OUT 定时器 500ms]───

// 输出
       始终
    ───┤├───────[MOV 数据 输出组]───     // 输出到LED组

效果:LED0→LED1→LED2→...→LED7→LED0 循环

8.2 数据加密(简单异或+移位)

简单加密算法:

加密:
1. 与密钥异或
2. 循环左移3位

解密:
1. 循环右移3位
2. 与密钥异或

【加密梯形图】
       加密按钮
    ───┤├───────[XOR 明文 密钥 中间值]───  // 异或
               [ROL 中间值 3 密文]───       // 循环左移

【解密梯形图】
       解密按钮
    ───┤├───────[ROR 密文 3 中间值]───      // 循环右移
               [XOR 中间值 密钥 明文]───    // 异或还原

8.3 串行数据接收

移位寄存器接收串行数据:

       数据输入                              // 数据输入
    ───┤├───────[MOV 数据输入 接收位]───

       时钟脉冲                              // 时钟脉冲
    ───┤P├──────[SFTL 接收位 数据区 1 16]──

每个时钟脉冲:
· 读取数据输入状态到接收位
· 数据区左移1位
· 接收位移入数据区

16个脉冲后,数据区存储16位串行数据

本节小结

移位指令要点:

┌────────────────────────────────────────────────────┐
│  逻辑移位                                          │
│  · SHL左移:右侧补0                               │
│  · SHR右移:左侧补0                               │
│  · 移出的位丢弃                                   │
├────────────────────────────────────────────────────┤
│  算术移位                                          │
│  · 右移时保留符号位                               │
│  · 用于有符号数除法                               │
├────────────────────────────────────────────────────┤
│  循环移位                                          │
│  · ROL/ROR:移出位回到另一端                      │
│  · 不丢失数据,适合循环显示                       │
├────────────────────────────────────────────────────┤
│  应用技巧                                          │
│  · 移位代替乘除(×2ⁿ/÷2ⁿ)                       │
│  · 位提取/设置/清除                               │
│  · 步进控制、产品跟踪                             │
└────────────────────────────────────────────────────┘

练习题

  1. 说明逻辑右移和算术右移的区别。
  2. 编写程序实现8个LED灯的流水效果。
  3. 如何用移位指令实现乘以10的运算?
  4. 设计一个移位寄存器实现5工位步进控制。

← 上一节:4.1 数学运算指令 | 返回目录 | 下一节:4.3 程序控制指令 →

本教程由 AI (Claude Opus 4.5) 生成,仅供学习参考