PLC 编程绕不开两类基础问题:进制怎么算、数据类型怎么选。很多初学者在写程序时,地址没错、逻辑也对,但结果就是不对,最后查下来往往是数据类型搞错,或者十六进制和十进制没换算清楚。这一讲就把进制转换和数据类型放在一起讲透,结合三菱和西门子 PLC 的常见用法,把底层概念、指令用法、通信报文和实战案例串起来。
1. 进制转换与数据类型核心知识速览
| 知识点 | PLC 中的常见形式 | 典型应用场景 |
|---|---|---|
| 二进制 BIN | 位元件组合成的数值形式 | 数字量输入输出、位状态判断 |
| 十进制 DEC | K 常数、D 寄存器数值显示 | 定时器设定值、计数器当前值、模拟量工程量 |
| 十六进制 HEX | H 常数、通信报文中的地址和数据 | Modbus 地址、触摸屏通讯地址、设备报文 |
| 八进制 OCT | 三菱 X/Y 输入输出编号 | 三菱 PLC 输入输出端子编号 |
| BCD 码 | 拨码开关、数码管显示 | 外部 BCD 码盘输入、七段数码管输出 |
| 位数据 BOOL | 单个 bit,0 或 1 | 按钮、继电器、气缸到位信号 |
| 整型数据 INT/DINT | 16 位或 32 位整数 | 计数值、步进位置、温度整数值 |
| 浮点数据 REAL | 32 位浮点数 | 模拟量、PID 过程值、高精度计算 |
| 字数据 WORD/DWORD | 按位组合的 16/32 位数据 | 通信协议解析、状态字、控制字 |
需要明确一点:PLC 内部本质上只认二进制,所有的进制转换只是在“人对数据的理解方式”和“外部设备的通信约定”之间做翻译。十进制、十六进制都是给人看的,设备报文里则是十六进制和二进制为主。
2. 为什么 PLC 编程必须掌握进制转换
2.1 输入输出编号本身就是进制问题
三菱 PLC 的输入继电器 X 和输出继电器 Y 采用八进制编号。也就是说,X0 到 X7 之后不是 X8、X9,而是 X10。很多新手第一次写程序时找 X8,找半天找不到,就是因为不知道三菱输入输出是八进制编号。这是硬件层面强制的进制规则,必须适应。
西门子 PLC 的 I/Q 地址则是十进制编号,比如 I0.0 到 I0.7,然后是 I1.0。这种差异在实际项目中非常容易踩坑,尤其是同时维护三菱和西门子两种 PLC 的设备。
2.2 通信报文全部是十六进制
PLC 和变频器、仪表、伺服驱动器、触摸屏通信时,报文里的地址和数据都按十六进制组织。比如 Modbus 协议中,保持寄存器地址 40001 对应的实际报文地址往往是 0x0000。如果不理解十六进制,连设备手册都读不懂,更别说排查通信故障。
2.3 数据类型的长度决定数值范围和解析方式
同一个寄存器,按 16 位有符号整数解释和按 16 位无符号整数解释,得到的数值完全不同。比如十六进制 0xFFFF,如果当作有符号整数 INT,它是 -1;如果当作无符号整数 WORD,它是 65535。通信协议里如果没写清楚数据类型,调试时就会出现“数值对不上”的经典问题。
2.4 模拟量和工程量转换离不开进制与数值跨度
模拟量模块采集到的原始值是一串数字,比如 0 到 4000 或 0 到 27648。要把这个原始值转换成实际的温度、压力、流量,必须理解数值存储类型,才能写对缩放公式。
3. PLC 常用数据类型详解
3.1 三菱 PLC 系列数据单位
三菱 FX 系列和 Q/L 系列中,最小的数据单位是位(bit),由 X、Y、M、S 等位元件表示。多个位组合成字节(Byte)、字(Word)、双字(Double Word)。
| 组合单位 | 位数 | 数值范围(无符号) | 数值范围(有符号) | 典型元件 |
|---|---|---|---|---|
| 位 Bit | 1 | 0~1 | 0~1 | X0、Y0、M0、S0 |
| 字节 Byte | 8 | 0~255 | -128~127 | 特殊功能寄存器低 8 位 |
| 字 Word | 16 | 0~65535 | -32768~32767 | D0、D100、T 当前值 |
| 双字 Double Word | 32 | 0~4294967295 | -2147483648~2147483647 | D0D1、D100D101 |
三菱数据寄存器 D 是 16 位。32 位数据需要使用两个连续 D 寄存器存储,比如 D0D1,其中 D1 是高 16 位,D0 是低 16 位。这在处理浮点数或长整数时必须注意。
3.2 西门子 PLC 常用数据类型
西门子博途(TIA Portal)中的数据类型更丰富,编程前必须明确每个变量的类型。
| 数据类型 | 位数 | 数值范围 | 说明 |
|---|---|---|---|
| BOOL | 1 | TRUE / FALSE | 位变量,对应 I0.0、M0.0 |
| BYTE | 8 | 0~255 | 无符号字节 |
| WORD | 16 | 0~65535 | 无符号字 |
| DWORD | 32 | 0~4294967295 | 无符号双字 |
| INT | 16 | -32768~32767 | 有符号整数 |
| DINT | 32 | -2147483648~2147483647 | 有符号双整数 |
| REAL | 32 | 浮点数 | 按 IEEE 754 存储 |
| STRING | 可变 | 字符 | 触摸屏和文本处理 |
西门子 PLC 中,BOOL 通常占用一个位,但地址按字节分组。比如 M0.0 到 M0.7 属于 MB0。WORD 和 INT 都占 16 位,区别在于 WORD 没有正负号,INT 有正负号。当外部设备报文给出 0xFFFF 时,你用 INT 变量接收就是 -1,用 WORD 接收就是 65535。
3.3 数据类型不匹配的典型后果
实际项目里最常见的错误包括:
在比较指令中把 INT 和 DINT 直接比较,结果一直不成立。把 WORD 数值传给 INT 变量,导致 30000 变成了负数。把 32 位浮点数存在 16 位寄存器里,数值被截断。通信报文按 16 位解析,但实际发送的是 32 位数据,导致每个数据都错位。
这些问题的根源都是对数据类型理解不够。学习数据类型时,不要死记硬背,要理解“位宽”和“有无符号”这两个维度。
4. 进制转换的数学方法与 PLC 指令实现
4.1 手工换算:二进制、十进制、十六进制
二进制转十进制:每一位乘以 2 的 n 次方后相加。比如二进制 1011 0101 转十进制:
1128 + 064 + 132 + 116 + 08 + 14 + 02 + 11 = 181
十六进制转二进制:每个十六进制位拆成 4 位二进制。比如 0xB5,B 是 1011,5 是 0101,所以 0xB5 = 1011 0101。
二进制转十六进制:从右往左每 4 位一组,不足 4 位前面补 0。比如二进制 1111 0101 1110,分组为 1111、0101、1110,对应十六进制 0xF5E。
十进制转十六进制:用 16 反复除,余数倒排。比如十进制 4826 转十六进制:
4826 / 16 = 301 余 10(A) 301 / 16 = 18 余 13(D) 18 / 16 = 1 余 2 1 / 16 = 0 余 1
结果就是 0x12DA。
这些手工方法主要用于排查问题时心算验证,日常编程主要靠指令和软件工具。
4.2 三菱 PLC 的进制相关指令
三菱 FX 系列中,常数前缀直接表示进制:
| 前缀 | 进制 | 示例 |
|---|---|---|
| K | 十进制 | K100 |
| H | 十六进制 | H1F |
| B | 二进制 | B1010(部分系列) |
三菱的 BIN 指令用于 BCD 码和二进制之间的转换,MOV 指令则直接传送数值。在 FX 系列中,K 常数输入后会以二进制形式存储,但显示和监控时以十进制显示。H 常数输入后会按十六进制存储到寄存器中。
4.3 西门子博途的进制显示与转换指令
博途中的常量可以指定进制格式。在 LAD/FBD 中,输入 16#1F 表示十六进制,输入 2#1010 表示二进制。转换指令在“移动和转换操作”中可以找到。
| 转换方向 | 指令示例 | 说明 |
|---|---|---|
| INT 转 DINT | INT_TO_DINT | 16 位整数扩成 32 位 |
| INT 转 REAL | INT_TO_REAL | 整数转浮点数 |
| DINT 转 REAL | DINT_TO_REAL | 双整数转浮点数 |
| BCD 转 INT | BCD_I | BCD 码转整数 |
| INT 转 BCD | I_BCD | 整数转 BCD 码 |
4.4 用结构化文本 ST 写进制转换函数
如果需要批量转换或实现自定义逻辑,可以在博途的 SCL 或三菱的 ST 语言中写函数。以下是一个十六进制字符串转十进制的 SCL 示例:
FUNCTION "HexStringToInt" : INT { S7_Optimized_Access := 'TRUE' } VERSION : 0.1 VAR_INPUT hexChar : CHAR; END_VAR IF hexChar >= '0' AND hexChar <= '9' THEN "HexStringToInt" := CHAR_TO_INT(hexChar) - CHAR_TO_INT('0'); ELSIF hexChar >= 'A' AND hexChar <= 'F' THEN "HexStringToInt" := CHAR_TO_INT(hexChar) - CHAR_TO_INT('A') + 10; ELSE "HexStringToInt" := 0; END_IF;实际项目中,这类函数主要用于解析第三方设备报文。但更稳妥的方式是先在协议文档中确认字节序和数据类型,再选择直接使用系统转换指令。
5. 三菱 PLC 进制转换与数据类型实战
5.1 拨码开关 BCD 码输入处理
很多设备使用 BCD 码拨码开关输入设定值。BCD 码用 4 位二进制表示一个十进制位,比如十进制 25 的 BCD 码是 0010 0101。三菱 PLC 读取拨码开关后,需要进行 BCD 转 BIN 才能参与运算。
// 伪代码示例:读取 BCD 码后转换为二进制 // X0~X7 为 BCD 码输入 MOV K2X000 D10 // 将 X0~X3 和 X4~X7 组合成 8 位 BCD 码存入 D10 BCD D10 D20 // BCD 码转为二进制(部分系列为 BIN 指令)三菱 FX 系列中,BCD 指令用于将二进制数转换为 BCD 码,BIN 指令用于将 BCD 码转换为二进制数。实际型号指令存在差异,使用前要查阅对应编程手册。
5.2 十六进制数据显示到触摸屏
触摸屏地址通常对应 PLC 的 D 寄存器。如果 D 寄存器里的数据是十六进制格式,触摸屏显示时也要选择十六进制格式。否则直接以十进制显示,数值会完全对不上。
比如 D0 中存储 H12A,即十进制的 298。触摸屏如果以十进制显示,会显示 298;以十六进制显示,会显示 12A。这个地方最容易造成现场误解。
5.3 32 位数据拼接处理
三菱 FX 系列处理 32 位数据时,需要两个连续 D 寄存器。比如浮点数运算指令 DEMOV D0 D10,其中 D0 和 D1 组成一个 32 位数据,D10 和 D11 组成另一个 32 位数据。低字在前、高字在后是三菱的默认存储方式。
实际项目中如果需要把两个 16 位寄存器拼成 32 位,可以使用下列方式:
// 假设 D0 是低 16 位数据,D1 是高 16 位数据 // 组合为 32 位数据存放到 D5D4 MOV D1 D5 // 高字放到高字位置 MOV D0 D4 // 低字放到低字位置6. 西门子 PLC 数据存储与强制转换处理
6.1 模拟量转换中的类型处理
西门子模拟量模块的原始值范围是 0~27648 或 -27648~27648。必须把原始值先转成 REAL,再做量程缩放,否则直接用整数做除法,结果会丢失精度。
// SCL 示例:模拟量原始值转工程量 #rawValue := "AI_Channel1"; // INT 类型 #scaleValue := INT_TO_REAL(#rawValue) * 100.0 / 27648.0;如果没有先做 INT_TO_REAL,而是用整数直接乘以 100 再除以 27648,结果是整数运算,精度损失会导致 PID 控制不稳定。
6.2 设备通信中的 Word 和 DWord 解析
MODBUS TCP 通信中,很多设备返回 32 位数据时先发高字再发低字,也有设备先发低字再发高字。在博途中接收时,需要把两个 WORD 拼接成 DWORD,再按 DINT 或 REAL 解析。
// 将两个 WORD 拼接为 DWORD #highWord := #receiveData[0]; #lowWord := #receiveData[1]; #combinedDWord := SHL(IN := WORD_TO_DWORD(#highWord), N := 16) OR WORD_TO_DWORD(#lowWord); #realValue := DWORD_TO_REAL(#combinedDWord);这样拼接后,还需要确认字节序,否则两个字的顺序一颠倒,数值完全错误。
6.3 防止数据截断
在西门子 PLC 中,把 DINT 数据直接移动到 INT 变量时,超出 16 位范围的部分会被截断。例如 DINT 值 70000 赋给 INT 变量,会得到一个错误值。编程时必须先用范围判断:
IF #dinValue >= -32768 AND #dinValue <= 32767 THEN #intValue := DINT_TO_INT(#dinValue); ELSE #intValue := 0; // 范围溢出时给默认值 END_IF;7. Modbus 通信中的进制与数据类型问题
7.1 Modbus 地址区与进制关系
Modbus 协议是 PLC 项目中最常见的通信协议。它分为四个地址区:
| 地址区 | 名称 | 读写属性 | 数据类型 |
|---|---|---|---|
| 0xxxx | 线圈 | 读写 | BOOL |
| 1xxxx | 离散输入 | 只读 | BOOL |
| 3xxxx | 输入寄存器 | 只读 | 16 位 WORD |
| 4xxxx | 保持寄存器 | 读写 | 16 位 WORD |
这里 xxxx 是十进制编号,但报文里使用的是十六进制地址。例如保持寄存器 40001,在报文 PDU 中地址是 0x0000;40002 对应 0x0001。虽然大多数库函数会自动处理地址偏移,但排查故障时仍然需要理解这一点。
7.2 16 位和 32 位数据的寄存器组合
Modbus 寄存器本身只有 16 位。32 位数据需要占用两个连续寄存器。设备手册通常会写“寄存器地址 0x0100 为高字,0x0101 为低字”或者相反。还有一种情况是 DWORD 模式的 32 位整数、FLOAT 模式的 32 位浮点,它们占用寄存器数量相同,但解析方式不同。
以常见的流量计读取为例,假设流量值以 32 位浮点数存储,占寄存器 0x0100 和 0x0101:
# 请求示例:读取保持寄存器地址 0x0100 开始的 2 个寄存器 # 从站地址 01,功能码 03,起始地址高字节 01,起始地址低字节 00,寄存器数高字节 00,寄存器数低字节 02 01 03 01 00 00 02返回的数据是 4 字节,解析时需要按 IEEE 754 浮点数格式组合。如果解析出来数值离谱,大概率是字节序或高低字顺序反了。
7.3 模拟量仪表的值域与数据类型
现场仪表常常把工程量映射到 0~65535 或 0~2000 等范围,然后以 WORD 类型通过 Modbus 输出。PLC 端接收后,要把这个 WORD 转为 REAL 再进行量程缩放,计算公式如下:
// DINT_REAL 示例需要结合具体 PLC 环境 rawReal := WORD_TO_REAL(rawWord); // 无符号字转浮点 engValue := rawReal * (engMax - engMin) / (rawMax - rawMin) + engMin;如果仪表手册说数据是有符号整数,就不能用 WORD_TO_REAL,而是先用 WORD_TO_INT,再转 REAL。很多仪表用 0~65535 表示量程,但也有用 -32768~32767 的,必须看手册。
8. 进制转换与数据类型的常见错误及排查
| 问题现象 | 可能原因 | 排查方法 | 解决措施 |
|---|---|---|---|
| 三菱程序里找不到 X8、X9 | 三菱输入输出是八进制编号 | 查看 PLC I/O 地址分配表 | 使用 X0-X7、X10-X17 等八进制地址 |
| 触摸屏显示数据和 PLC 不一致 | 触摸屏变量数据类型/进制设置错误 | 对比触摸屏数值和 PLC 监控值 | 将触摸屏变量类型和进制格式设置为一致 |
| 数值变成负数 | 有符号和无符号类型混用 | 查看监控表格中的十六进制原始值 | 统一使用 WORD 或 INT 类型 |
| 模拟量精度差 | 整数运算没有转浮点 | 在程序中加入浮点转换指令 | 使用 INT_TO_REAL 后再计算 |
| Modbus 读到的数值离谱 | 字节序或寄存器顺序不对 | 用手持调试工具查看原始报文 | 调整高低字拼接顺序 |
| 32 位数据只更新一半 | 两个寄存器未同时更新 | 检查 PLC 扫描周期和通信周期 | 增加数据更新锁存或使用一致的读写指令 |
| 强制转换后数据溢出 | 源数据超过目标类型范围 | 检查源数据的最大值 | 增加范围判断和饱和处理 |
| 通信数据错位 | 数据类型长度定义错误 | 核对协议文档中的寄存器映射表 | 按协议文档重新定义变量类型 |
排查这些问题时,最有效的方式是把 PLC 监控界面切到十六进制显示,对照设备手册里的原始报文。一旦看到原始 hex 值,问题基本就定位了。
9. PLC 编程进制与数据类型最佳实践
9.1 建立统一的数据类型约定
在项目开始前,整理一份数据类型和地址规划表。模拟量输入统一使用 REAL,通信原始数据统一使用 WORD,计数器和脉冲数据统一使用 DINT。这样在多人协作时不容易出现类型混乱。
9.2 通信数据先解析再使用
不要直接在程序中使用通信原始寄存器值。建议写一个独立的通信数据解析功能块,把 WORD 转为工程量,把双字拼接后的 REAL 存到全局数据块。后续逻辑只使用解析后的变量,不直接操作通信缓冲区。
9.3 进制转换工具常备
现场排查问题的时候,建议电脑上备一个进制转换工具,或者直接用 Windows 计算器的程序员模式。十六进制、十进制、二进制、八进制之间切换查看,效率会高很多。
9.4 注释里写清楚数据类型和范围
在 PLC 程序中,每个关键变量的注释要写清楚“来源”“数据类型”“工程单位”“量程范围”。尤其在通信数据块中,每个 WORD 对应设备手册的哪个地址,必须写明白,否则三个月后再维护,谁都不知道这个变量是干什么的。
9.5 小规模验证后再批量修改
修改数据类型或进制转换逻辑时,先在一个测试程序里跑通,确认 PLC 监控数值和设备手册预期一致,再应用到正式项目。不要在正在运行的生产设备上直接改通信解析逻辑。
10. PLC 编程学习路线建议
这一讲的内容可以归纳为三条主线:
第一条:从硬件角度看编号规则,理解三菱八进制 X/Y 和西门子十进制 I/Q 的区别。第二条:从指令角度看转换方法,理解 MOV、BCD、BIN、INT_TO_REAL、WORD_TO_DWORD 等指令的实际用途。第三条:从通信角度看报文协议,理解 Modbus 等协议中的数据存储和解析。
建议练习时使用仿真软件,不必急着上硬件。三菱 GX Works2 和西门子博途都支持仿真,可以自己创建变量,模拟进制转换和数据拼接的过程。练熟之后,再用实际 PLC 连接实物传感器或通信设备做验证。
真正到了设备调试现场,你会发现在线监控里的“进制显示切换”和“数据类型定义”这两个功能,比任何高级指令都重要。能快速定位一个通信数据的原始十六进制值,并正确解释它的数据类型,就已经解决了现场一半的疑难问题。