封面

西门子PLC编程:数制与基本数据类型 — 学习笔记

写作时间:2026-07-21 12:00:00
📁 1200
# 数据类型 # 数制 # SCL

西门子PLC编程:数制与基本数据类型 — 学习笔记

📚 课程主题:数制与基本数据类型(整数数据类型) 🏭 适用平台:西门子 S7-1200 / S7-1500(TIA Portal) 📅 整理时间:2026-07-21


一、核心问题:位序列与整数的区别

在西门子PLC编程中,位序列(Bit String)和整数(Integer)是两类本质不同的数据类型。虽然它们在底层都以二进制形式存储,但使用目的、操作指令和表示方式截然不同。

对比维度 位序列(Bit String) 整数(Integer)
用途 位的集合,用于控制字、状态字、错误代码、标志位等 用于数学计算(计数、运算、标定等)
操作指令 与(AND)、或(OR)、异或(XOR)、取反(NOT)、移位(SHL/SHR)等 加(+)、减(-)、乘(*)、除(/)、取模(MOD)等
拆分合并 作为位的集合,通常需要拆分/合并使用(如提取某一位状态) 位的拆分合并没有数学意义
表示方式 一般使用**二进制(2#)十六进制(16#)**表示 一般使用十进制表示

二、位序列数据类型详解

2.1 位序列类型族

位序列(Bit String)是一组无符号的定长数据类型,用于表示位模式而非数值。TIA Portal 中主要包括以下类型:

数据类型 关键字 大小 范围(无符号) 典型用途
布尔 BOOL 1 位 0 或 1 单个数字量 I/O 点(如 I0.0, Q0.1)
字节 BYTE 8 位 0 ~ 255 压缩的标志字节、串行协议字符
WORD 16 位 0 ~ 65,535 位模式寄存器、状态字、无符号计数器
双字 DWORD 32 位 0 ~ 4,294,967,295 状态字对、大型位模式寄存器
长字 LWORD 64 位 0 ~ 2⁶⁴ - 1 时间戳、大型计数器(仅 S7-1500)

💡 关键理解:位序列的本质是"位的容器",关注的是每一位的独立状态,而非整体数值大小。

2.2 内存映射与字节序

西门子PLC采用小端(Little-Endian)、面向字节的内存约定:

  • 低字节 占用等于字地址的地址
  • 高字节 占用下一个地址

示例:WORD 在 MW20 的位映射

字位 位地址 所属字节 意义
%X0 M20.0 低字节(MB20) 整个 WORD 的 LSB
%X1 M20.1 低字节
... ... 低字节
%X7 M20.7 低字节 低字节的 MSB
%X8 M21.0 高字节(MB21) 高字节的 LSB
%X9 M21.1 高字节
... ... 高字节
%X15 M21.7 高字节 整个 WORD 的 MSB

⚠️ 注意:MW20 由 MB20(低字节)和 MB21(高字节)组成。若 VW100 = 2(二进制 00000000 00000010),则 VB100 = 0(高字节),VB101 = 2(低字节)。

2.3 位访问语法

S7-1500 / S7-1200(固件 V4.0+)

支持直接的结构化位片(Bit-Slice)访问:

// 读取位
bReady := "StatusWord".%X0;   // 读取第0位(LSB)
bFault := "StatusWord".%X7;   // 读取第7位
bBit9  := "StatusWord".%X8;   // 读取第8位(高字节LSB)

// 写入位
"StatusWord".%X15 := TRUE;    // 设置最高位(MSB)作为故障标志

旧固件替代方案(S7-1200 V1.0~V3.x)

  1. 直接位内存地址:若绑定到 %MW20,直接读写 %M20.0 ~ %M21.7
  2. AT 覆盖:在 DB 中声明 AT 覆盖结构
// 使用 AT 覆盖
TYPE "UDT_BitView16"
  STRUCT
    bits : ARRAY[0..15] OF BOOL;  // bit 0 = LSB
  END_STRUCT;
END_TYPE

DATA_BLOCK "DB_BitView"
  STRUCT
    rawWord : WORD;
    bitView AT rawWord : "UDT_BitView16";
  END_STRUCT;
END_DATA_BLOCK

// 使用
"DB_BitView".bitView.bits[3] := TRUE;  // 修改第3位

2.4 位操作指令(字逻辑)

// 置位第5位(不触动其他位)
"StatusWord" := "StatusWord" OR 16#0020;

// 清零第5位
"StatusWord" := "StatusWord" AND (WORD#16#FFFF XOR 16#0020);

// 翻转第5位
"StatusWord" := "StatusWord" XOR 16#0020;

// 测试第5位
bBit5 := ("StatusWord" AND 16#0020) <> 16#0;

三、整数数据类型详解

3.1 整数类型族

整数类型用于数学运算,分为有符号无符号两类:

数据类型 关键字 大小 范围(有符号) 范围(无符号) 典型用途
短整数 SINT 8 位 -128 ~ +127 状态标志、小计数器
无符号短整数 USINT 8 位 0 ~ 255 ASCII字符、布尔数组
整数 INT 16 位 -32,768 ~ +32,767 通用计数器、模拟量标定(原始值0-27648)
无符号整数 UINT 16 位 0 ~ 65,535 定时器预设值、内存指针
双整数 DINT 32 位 -2,147,483,648 ~ +2,147,483,647 高速计数器、大型累加器
无符号双整数 UDINT 32 位 0 ~ 4,294,967,295 时间戳(毫秒)、滴答计数
长整数 LINT 64 位 -9,223,372,036,854,775,808 ~ +9,223,372,036,854,775,807 系统诊断(仅 S7-1500)

💡 关键理解:有符号整数的最高位为符号位(0=正,1=负),负数采用二进制补码表示(正数取反再加1)。

3.2 INT 的结构(16位有符号整数)

位 15  | 位 14 ~ 位 0
 符号位  |   数值位(15位)
   0/1   |  0 ~ 32767
  • 位 15 = 0:正数(0 ~ 32767)
  • 位 15 = 1:负数(-32768 ~ -1,补码表示)

3.3 数学运算指令

整数支持标准算术运算:

nResult := nValue1 + nValue2;   // 加法
nResult := nValue1 - nValue2;   // 减法
nResult := nValue1 * nValue2;   // 乘法
nResult := nValue1 / nValue2;   // 除法(整数除法)
nRemainder := nValue1 MOD nValue2;  // 取模(余数)

四、位序列 vs 整数:深入对比

4.1 核心区别总结

特性 位序列(WORD/DWORD) 整数(INT/DINT)
语义 "将此视为位模式" "将此视为有符号/无符号数值"
最高位含义 普通数据位(无符号) 符号位(有符号)
适用场景 状态字、控制字、错误代码、通信数据包 计数、测量值、PID运算、数学公式
位拆分 有意义(提取单个标志位) 无意义(破坏数值语义)
进制表示 十六进制(16#)或二进制(2#) 十进制
类型转换 需显式转换(WORD_TO_INT等) 需显式转换(INT_TO_WORD等)

4.2 类型转换注意事项

TIA Portal 不会自动转换位序列和整数类型,必须显式转换:

nSigned : INT;
wRaw    : WORD;

// ❌ 错误:隐式转换不被允许
nSigned := wRaw;   // 编译错误!

// ✅ 正确:显式转换
nSigned := WORD_TO_INT(wRaw);   // WORD → INT
wRaw    := INT_TO_WORD(nSigned); // INT → WORD

⚠️ 陷阱:当 WORD 值 > 16#7FFF(32767)时,转换为 INT 会得到负数(因为最高位被解释为符号位)。例如:WORD#16#8000 → INT = -32768。

4.3 WORD vs UINT 的区别

特性 WORD UINT
大小 16位 16位
范围 0 ~ 65535 0 ~ 65535
语义 "位模式/寄存器" "非负整数"
用途 状态字、原始寄存器值 算术运算中的非负计数器

💡 在 TIA Portal 中,WORD 和 UINT 是不同类型,编译器在某些严格模式下会标记类型不匹配。选择依据:表示位模式用 WORD,表示非负整数用 UINT


五、数制表示法

TIA Portal 支持多种数制字面量:

表示法 前缀 示例 十进制值
二进制 2# 2#1010 10
十进制 无前缀 10 10
十六进制 16# 16#A 10
八进制 8# 8#12 10
BCD BCD# BCD#10 10(用于旧式BCD I/O)

📝 注意:TIA Portal 不支持 C 风格的 0x 前缀。十六进制请始终使用 16#


六、实际应用示例

6.1 位序列应用:状态字解析

VAR
    StatusWord : WORD;          // 设备状态字(位序列)
    bReady     : BOOL;          // 就绪标志(位0)
    bRunning   : BOOL;          // 运行标志(位1)
    bFault     : BOOL;          // 故障标志(位7)
    bEmergency : BOOL;          // 急停标志(位15)
END_VAR

// 读取状态位
bReady     := "StatusWord".%X0;
bRunning   := "StatusWord".%X1;
bFault     := "StatusWord".%X7;
bEmergency := "StatusWord".%X15;

// 设置运行标志(不影响其他位)
"StatusWord" := "StatusWord" OR 16#0002;  // 置位bit1

6.2 整数应用:计数与运算

VAR
    nCounter   : INT;           // 计数器(整数)
    nSetpoint  : INT := 100;    // 设定值
    nActual    : INT;           // 实际值
    nError     : INT;           // 误差
END_VAR

// 数学运算
nCounter := nCounter + 1;       // 计数器递增
nError   := nSetpoint - nActual; // 计算误差

// 比较运算
IF nError > 10 THEN
    // 误差过大,报警处理
END_IF;

6.3 混合使用:从模拟量读取

VAR
    wRawInput  : WORD;          // 模拟量原始输入(位序列,0-27648)
    nScaled    : INT;           // 标定后的工程值(整数)
END_VAR

// 将位序列转换为整数进行数学运算
nScaled := WORD_TO_INT(wRawInput);

// 进行线性标定(如 0-27648 → 0-100°C)
nScaled := (nScaled * 100) / 27648;

七、常见错误与避坑指南

7.1 错误类型对照表

错误现象 根本原因 解决方法
编译错误:无法将 WORD 赋值给 INT 类型不匹配,无隐式转换 使用 WORD_TO_INT() 显式转换
HMI 读取无符号值显示为负数 HMI 将有符号/无符号类型混淆 将 HMI 标签配置为无符号类型,或在PLC中转换
位片访问返回错误值 字节序不匹配(大端 vs 小端) 使用 SWAP 指令交换字节序
WORD 值 > 32767 转 INT 变负数 补码解释导致符号翻转 语义上非负时使用 UINT,而非 INT
地址交叉(如 DW0 与 DW2) 双字由连续字组成,地址重叠 确保地址间隔至少为数据类型大小

7.2 字节序与通信

当 WORD 通过 PROFINET、Modbus TCP 等通信时,线缆上的字节序可能是大端(Big-Endian),而西门子内存是小端。在位片访问前需使用 SWAP 指令规范化:

// 接收到的 Modbus 数据(大端)
wReceived : WORD := 16#A5B6;

// 交换字节序后位片才正确
wSwapped := SWAP(wReceived);  // 结果:16#B6A5

7.3 地址不重叠原则

MB0  →  BYTE(占用 MB0)
MW0  →  WORD(占用 MB0, MB1)
MD0  →  DWORD(占用 MB0, MB1, MB2, MB3)

❌ 错误:MD0 和 MW2 存在地址交叉(MB2, MB3 重叠)
✅ 正确:MD0 和 MW4 无交叉

八、思维导图:数据类型选择决策

需要存储数据?
    ├── 是单个开关量? → BOOL(1位)
    ├── 是多位标志集合?
    │       ├── 8位  → BYTE
    │       ├── 16位 → WORD
    │       ├── 32位 → DWORD
    │       └── 64位 → LWORD(S7-1500)
    └── 是数值用于计算?
            ├── 需要负数?
            │       ├── 8位  → SINT
            │       ├── 16位 → INT
            │       ├── 32位 → DINT
            │       └── 64位 → LINT(S7-1500)
            └── 仅非负数?
                    ├── 8位  → USINT
                    ├── 16位 → UINT
                    ├── 32位 → UDINT
                    └── 64位 → ULINT(S7-1500

九、参考资源

  • 西门子 TIA Portal 帮助文档 — 数据类型
  • 西门子 S7-1500 系统手册(位片访问章节)
  • 西门子 S7-1200/1500 编程指南

🎯 学习要点回顾

  1. 位序列 = 位的容器,关注每一位的独立状态;整数 = 数值,关注整体大小和数学运算
  2. 位序列用二进制/十六进制表示,整数用十进制表示
  3. 位序列支持位操作指令(AND/OR/XOR/移位),整数支持算术指令(加减乘除)
  4. 位序列可以拆分合并(有意义),整数的位拆分无意义
  5. TIA Portal 类型检查严格,位序列与整数之间必须显式转换

本笔记基于西门子官方文档及课程资料整理,供学习参考使用。

💬

留言板暂未开启

评论方案(Giscus / Twikoo)将在后续版本敲定, 敬请期待。