西门子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)
- 直接位内存地址:若绑定到
%MW20,直接读写%M20.0~%M21.7 - 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 编程指南
🎯 学习要点回顾:
- 位序列 = 位的容器,关注每一位的独立状态;整数 = 数值,关注整体大小和数学运算
- 位序列用二进制/十六进制表示,整数用十进制表示
- 位序列支持位操作指令(AND/OR/XOR/移位),整数支持算术指令(加减乘除)
- 位序列可以拆分合并(有意义),整数的位拆分无意义
- TIA Portal 类型检查严格,位序列与整数之间必须显式转换
本笔记基于西门子官方文档及课程资料整理,供学习参考使用。