ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

PLC编程进制转换与数据类型详解:从位、字节到浮点数

PLC编程进制转换与数据类型详解:从位、字节到浮点数 大家好欢迎回到我们的 PLC 编程系列课程。这一讲是第二十三讲也是很多初学者从“会写位逻辑程序”迈向“能处理真实工程数据”的一道关键门槛——进制转换与数据类型。可能有人会问我只是写个电机启停、写个气缸动作需要懂数据类型吗需要做进制转换吗答案是需要而且非常重要。当你用模拟量模块读取温度、用 Modbus 通讯读取变频器频率、用编码器测量伺服电机位置时你会发现程序里到处是十六进制、二进制、Word、DINT、REAL 这些概念。如果进制和数据类型的基础不牢固轻则监控数据对不上重则设备动作错误甚至损坏。本讲会从底层概念讲起把二、八、十、十六进制之间的换算捋清楚再系统梳理 PLC 的常用数据类型接着用模拟量采集、Modbus 通讯、机械手定位三个工程案例把知识点串起来最后给出常见问题的排查思路。无论你用的是西门子、三菱、欧姆龙还是国产 PLC这一讲的核心思路都适用。1. 为什么 PLC 编程离不开进制转换与数据类型1.1 PLC 内部的一切都是“0 和 1”PLC 的 CPU 本质上是一个数字处理器它不认识“36.5 摄氏度”也不认识“正转 5 厘米”。它只认识电路中的高电平和低电平对应逻辑上的“1”和“0”。当我们通过编程软件往 PLC 里写一个十进制数 100 时PLC 内部存储的并不是字符形式的“100”而是一串二进制位数据。比如 100 在 16 位存储空间里是0000 0000 0110 0100这一串 0 和 1 本身没有意义关键在于 CPU 如何解释它。同样一串0000 0000 0110 0100解释成无符号整数它是 100解释成十六进制它是 0x0064解释成 BCD 码它可能会被当成 64 这个十进制数。所以学习数据类型本质上就是在学“同一串二进制CPU 应该怎么读”。1.2 进制转换在实际项目中的典型场景进制转换不是纯理论问题它在以下场景中频繁出现触摸屏或上位机输入十六进制参数如通讯报文地址 0x01用监控表查看寄存器时需要切换十进制、十六进制显示处理 Modbus 通讯报文时寄存器数据通常以十六进制形式查看调试伺服驱动器或变频器时厂商手册里的参数地址和状态字都是十六进制处理 BCD 码设备如拨码开关输入、部分仪表输出。如果看不懂十六进制很多设备手册相当于天书。1.3 数据类型让“数据解释”有了规则在高级语言如 Java、Python中数据类型是语言层面的强制要求在 PLC 中数据类型则决定了存储空间占多大1 位、1 字节、2 字节还是 4 字节数值范围是多少有符号还是无符号参与运算时的行为整数除法还是浮点除法通讯时如何组合和拆分数据。同一个地址用错数据类型是 PLC 编程最常见的错误之一。2. 进制转换从二进制到十六进制2.1 常用进制的基数与数码先搞清楚几个基本术语进制基数使用的数码示例二进制20、11010B八进制80 - 717O十进制100 - 942十六进制160 - 9、A - F2AHPLC 程序中常见后缀或前缀写法需要区分厂家西门子常写2#1010、16#2A数据类型前面加WH、DW等表示字或双字三菱、欧姆龙部分软件中十六进制写作H2A或0x2A二进制写作B1010或2#1010。不同软件的写法有差异但进制的数学含义完全一样。2.2 二进制与十六进制转换四位一组二进制与十六进制之间的转换最常用因为 2 的 4 次方等于 16所以每 4 位二进制数可以对应 1 位十六进制数。转换规则二进制转十六进制从右往左每 4 位一组不够 4 位左边补 0十六进制转二进制每一位十六进制数展开成 4 位二进制数。例如二进制1010 1101 00111010 - A 1101 - D 0011 - 3结果为0xAD3西门子写法为16#AD3。反向示例十六进制0x3F转二进制3 - 0011 F - 1111结果为0011 1111。2.3 十进制与十六进制转换除基取余十进制转十六进制时用“除 16 取余”法以十进制 3000 为例3000 ÷ 16 187 余 8 187 ÷ 16 11 余 11即 B 11 ÷ 16 0 余 11即 B从下往上读3000 的十六进制是0xBB8。反过来十六进制转十进制就是把每一位的数码乘以其位权后累加0xBB8 11 × 16² 11 × 16¹ 8 × 16⁰ 11 × 256 11 × 16 8 2816 176 8 30002.4 负数在 PLC 中的表示补码PLC 中的有符号整数采用二进制补码表示。以 16 位整数为例最高位是符号位0 表示正1 表示负。数值 -100 的补码计算过程1. 100 的二进制 0000 0000 0110 0100 2. 按位取反 1111 1111 1001 1011 3. 末位加 1 1111 1111 1001 1100所以 -100 在 16 位存储空间中是1111 1111 1001 1100用十六进制表示为0xFF9C。这也是为什么在监控表中看到0xFF9C这样的数据时必须判断当前数据类型是有符号还是无符号否则会把负数看成 65436。2.5 开发软件中的进制监控技巧多数 PLC 编程软件在监控表、强制表或交叉引用视图中都支持切换数据显示格式。以西门子博途TIA Portal为例监控变量时可以在“监视值的格式”下拉菜单中切换二进制八进制十进制十六进制浮点数三菱 GX Works 中软元件监视界面的数值显示也可以右键切换进制。这个功能在排查通讯数据时非常重要——你会经常需要确认自己看到的16#FFFF到底是 -1 还是 65535。3. PLC 常见数据类型详尽梳理3.1 位、字节、字、双字的关系PLC 的最小存储单位是位bit一个位只能存放 0 或 1。按照 IEC 61131-3 标准以及主流 PLC 的实际使用习惯数据存储有如下层级名称位数英文PLC 中常见应用位1BOOL开关量、线圈、中间继电器字节8BYTE小范围数据、ASCII字符字16WORD / INT模拟量原始值、Modbus寄存器双字32DWORD / DINT / REAL高速计数、浮点数、长整数在西门子 PLC 中一个普通定时器的设定值通常以 16 位整数形式存放而高速计数器的当前值可能需要 32 位双字。在三菱 PLC 中D0是 16 位数据寄存器D0和D1组合起来可以构成 32 位数据。3.2 整数类型与数值范围这是 PLC 编程中必须背熟的一张表数据类型存储大小数值范围说明BOOL1 位0 或 1位数据BYTE8 位0 255无符号字节SINT8 位-128 127有符号短整数USINT8 位0 255无符号短整数WORD16 位0 65535无符号字UINT16 位0 65535无符号整数INT16 位-32768 32767有符号整数DWORD32 位0 4294967295无符号双字UDINT32 位0 4294967295无符号双整数DINT32 位-2147483648 2147483647有符号双整数REAL32 位约 ±3.4E38浮点数7 位有效数字LREAL64 位约 ±1.8E308双精度浮点数注意不同 PLC 品牌对类型的名称和存储大小有细微差别例如西门子博途中的 INT 是 16 位有符号而某些国产 PLC 的 INT 可能定义不同。使用前务必查看对应 PLC 的手册。3.3 REAL 浮点数的精度问题REAL32 位浮点数能表示的数值范围很大但精度有限大约只有 7 位有效十进制数字。比如0.1 0.2 0.3这句话在计算机里并不严格成立因为 0.1 和 0.2 都无法用二进制浮点数精确表示。PLC 中做浮点数相等判断时不能直接写IF speed 10.0 THEN ...而是应该判断两者的差值是否小于一个允许误差IF ABS(speed - 10.0) 0.01 THEN ...这个细节在运动控制和模拟量控制中非常容易踩坑。3.4 BCD 码一种特殊的“二进制表示十进制”BCD 码Binary-Coded Decimal是一种用 4 位二进制数表示 1 位十进制数的编码方式。例如十进制BCD 码0000010001200108100091001100001 0000991001 1001注意十进制数 10 的 BCD 码是0001 0000即高 4 位表示十位的 1低 4 位表示个位的 0。它与二进制数 101010完全不同。工程中使用 BCD 码的场景很多温控表、数显表的通讯数据采用 BCD 码格式输出旧式拨码开关输入设备直接产生 BCD 码某些驱动器参数的读写使用 BCD 码。在西门子指令中存在 BCD 与整数互转的指令如BTI、ITB三菱 PLC 中也有BIN和BCD指令。写通讯程序时重点注意如果读回来的数据看起来“什么都不是”试着按 BCD 解释一下。4. 不同品牌 PLC 的数据类型差异4.1 西门子 PLC 数据类型特点西门子博途TIA Portal环境下PLC 编程采用符合 IEC 61131-3 标准的数据类型体系。典型变量声明示例VAR rawValue : INT; // 模拟量原始值 scaledReal : REAL; // 转换后的工程量 startCmd : BOOL; // 启动命令 modeByte : BYTE; // 模式字节 positionL : DINT; // 32位位置值 END_VAR西门子 S7-1200/S7-1500 中访问 DB 块的变量时可以直接使用符号名非常方便。要注意 BOOL 在整个程序中可能会被优化掉跨 PLC 之间通讯或下载时避免只依赖位地址访问。4.2 三菱 PLC 数据类型特点三菱 PLC如 FX 系列和 Q 系列编程中数据类型更多体现在软元件上而不是像高级语言那样显式声明。常用软元件X输入继电器按八进制编号X0 - X7、X10 - X17Y输出继电器按八进制编号M内部继电器位数据D数据寄存器16 位R文件寄存器16 位Z变址寄存器。三菱的 32 位数据处理通常将两个连续的数据寄存器组合使用例如D0 D1组成 32 位其中 D0 是低 16 位不同指令存在差异需要查看手册确认。这种地址映射方式比符号变量更接近硬件所以进制转换更容易出现在通讯、模拟量处理中。4.3 Modbus 数据传输中的数据类型Modbus 协议是工业现场最常见的通讯协议。它定义了四种基本数据对象Modbus 对象位宽功能线圈Coil1 位读写开关量输出离散输入Discrete Input1 位只读开关量输入输入寄存器Input Register16 位只读模拟量等数据保持寄存器Holding Register16 位读写参数、模拟量等数据很多人问“Modbus 数据类型长度默认为多长”——答案是一个寄存器默认 16 位每个寄存器可存放一个 WORD无符号整型 0-65535。如果需要传输 32 位浮点数或 32 位整数必须连续占用 2 个寄存器且要约定字节序和字序。例如一个 REAL 数据在 Modbus 中可能占用地址 100 和 101 两个寄存器具体是高字在前还是低字在前与设备厂家有关。调试时可以先用固定值如 1.0发送通过反馈数据判断字节顺序。5. 进制转换与数据类型结合实战5.1 模拟量采集从原始值到工程量模拟量模块是 PLC 和现场传感器沟通的桥梁。例如一个 4-20mA 的压力变送器连接到 PLC 模拟量输入通道PLC 读取到的不是 12mA而是通道中的数字量原始值。不同 PLC 的模拟量原始值范围不同西门子 S7-200 SMART / S7-1200 中4-20mA 通常对应 0 - 27648三菱 FX 系列常见模拟量模块中4-20mA 可能对应 0 - 4000其他品牌请以模块手册为准。假设我们使用一个量程为 0 - 10MPa 的压力变送器PLC 读到原始值rawValue转换公式为工程值 (量程上限 - 量程下限) × (原始值 - 偏移下限) / (原始值上限 - 原始值下限) 量程下限以 0-27648 对应 0-10MPa 为例pressure 10.0 * rawValue / 27648使用西门子 STL/SCL 风格编写一个转换函数块// 模拟量输入转换为工程量 // 输入: rawValue 原始值 (INT) // 输出: engValue 工程值 (REAL) // 参数: engMin, engMax 工程量程 // 参数: rawMin, rawMax 原始值范围 FUNCTION_BLOCK FB_AnalogScale VAR_INPUT rawValue : INT; engMin : REAL; engMax : REAL; rawMin : REAL; rawMax : REAL; END_VAR VAR_OUTPUT engValue : REAL; END_VAR VAR ratio : REAL; END_VAR ratio : (engMax - engMin) / (rawMax - rawMin); engValue : ratio * (INT_TO_REAL(rawValue) - rawMin) engMin; END_FUNCTION_BLOCK这段代码解决了一个核心问题把原始的十六进制/十进制整数按线性关系转换成有物理意义的浮点数。注意计算顺序先把 INT 转成 REAL避免整数除法。很多新手在这步会写出10 * raw / 27648如果 raw 小于 27648得到的结果永远是 0就是忽略了整数除法。5.2 Modbus 通讯两个寄存器组合成 32 位数据现场有一台支持 Modbus RTU 的仪表压力值以 32 位浮点数形式存放在两个保持寄存器中。PLC 作为主站读取后需要把两个 16 位的 WORD 拼成一个 32 位的 REAL。以寄存器地址顺序高字在前、低字在后为例// 组合32位无符号整数 combined : SHL(DWORD_TO_UDINT(wordHigh), 16) OR UDINT_TO_DWORD(wordLow);在结构文本 ST 中更直接的写法// 假设 wordHigh 和 wordLow 都是 WORD 类型 // 先把 WORD 转成 DWORD然后移位和按位或 dwordTemp : (SHL(DWORD_TO_UDINT(WORD_TO_DWORD(wordHigh)), 16) OR WORD_TO_DWORD(wordLow)); // 将 DWORD 按 REAL 解释 realValue : DWORD_TO_REAL(dwordTemp);这里要特别强调DWORD_TO_REAL不是数值转换而是把 32 位二进制数据按 IEEE 754 浮点数格式重新解释。这类似于 C 语言中的memcpy或指针强制类型转换。如果你在博途中找不到这个直接转换指令也可以通过 UNION 结构体实现TYPE T_FloatUnion UNION dwordData : DWORD; realData : REAL; END_UNION END_TYPE然后先填入dwordData再读取realData即可得到浮点数值。这个场景极容易出错排查时的常用方法是固定仪表的输出值为 1.0读取两个寄存器原始值用十六进制显示确认 1.0 对应的 IEEE 754 编码0x3F800000确认哪个寄存器是高字、哪个是低字确认 PLC 的字节序是否与仪表一致。5.3 机械手定位脉冲数与毫米的换算机械手或伺服定位控制中电机编码器反馈的是脉冲数而工艺要求通常以毫米mm为单位。这本质上是数据类型由浮点数向整数转换的过程也是进制转换之外最容易丢精度的环节。假设伺服电机每旋转一圈需要 10000 个脉冲丝杠导程为 10mm则每毫米对应的脉冲数为pulsesPerMm 10000 / 10 1000 脉冲/mm如果目标位置是 123.5mm则目标脉冲数为targetPulses 123.5 × 1000 123500用 ST 实现// 输入目标位置和当前脉冲位置输出还需要移动的脉冲数 // 使用REAL中间计算最后取整 targetPosMm : REAL; // 目标位置单位 mm currentPosMm : REAL; // 当前位置单位 mm pulsesPerMm : REAL; // 脉冲当量脉冲/mm diffPulses : DINT; // 需要移动的脉冲数 diffPulses : REAL_TO_DINT((targetPosMm - currentPosMm) * pulsesPerMm);注意REAL_TO_DINT的取整方式是四舍五入还是截断在不同 PLC 中可能不同必须查阅指令手册。对于要求较高的场合建议先做舍入处理diffPulses : REAL_TO_DINT((targetPosMm - currentPosMm) * pulsesPerMm 0.5);这样做是为了避免负方向移动时因截断导致的累积误差。5.4 梯形图与函数块的组织在实际项目中进制转换和数据组合的逻辑应该封装成函数块或函数而不是散落在梯形图的各个网络里。推荐做法编写一个统一的“Modbus 数据解析”函数块编写一个统一的“模拟量缩放”函数块编写一个“类型转换工具”函数库INT 转 REAL、WORD 组合 DWORD、DWORD 转 REAL 等主程序中只负责调用这些块不重复写转换代码。这样做的好处是后续更换传感器、修改量程、调整通讯协议时只需要修改一处不会牵一发动全身。6. 常见问题与排查思路6.1 问题场景表问题现象常见原因排查思路模拟量读数为 0 或跳变量程不匹配、线缆屏蔽不良、转换公式写错先确认原始值是否符合量程再用固定工程值验证公式温度显示为负数或巨大正数把有符号数当无符号数解释切换监控格式确认 INT/UINTModbus 读出来的浮点数是乱码寄存器顺序反了、字节序不对发送固定值 1.0核对0x3F800000两个寄存器组合的 DINT 数值错误字序反了或高字低字处理错误用 0x12345678 测试组合结果检查高低字整数除法结果一直为 0两个 INT 直接相除未先转 REALREAL : INT_TO_REAL(a) / INT_TO_REAL(b)触摸屏输入 100PLC 读到 0x0100 而非 0x0064触摸屏使用了 BCD 模式修改触摸屏输入格式或在 PLC 中做 BCD 转 BIN高速计数值超过 32767 后变成负数使用了 16 位 INT 存储 32 位值改用 DINT 或 DWORD浮点数比较不相等导致程序逻辑错误REAL 精度问题用绝对差值与允许误差比较6.2 排查进制与类型问题的完整流程当你怀疑程序或数据出现进制/类型错误时按以下顺序排查确认现场设备信号的物理量程在 PLC 监控表中查看通讯原始值或模拟量原始值切换监控视图的进制十进制、十六进制判断数据变化趋势确认 PLC 侧的数据类型定义WORD、INT、REAL、DINT确认通讯协议中寄存器个数、字节序、字序使用固定测试值如 1.0、0x12345678验证解析逻辑在函数块内部添加临时变量逐步断点找到第一个出错的位置。7. 最佳实践与工程建议7.1 数据存储统一规范无论你使用哪个品牌 PLC都建议在程序开始时约定一套数据规范所有工程量统一用 REAL 存储所有原始值统一用 INT 或 WORD 存储所有状态标志统一用 BOOL所有计数/位置值统一用 DINT所有通讯报文统一用字节数组或 WORD 数组存储。这样做可以降低后续维护成本避免每个人按自己的习惯定义类型。7.2 显式转换代替隐式转换PLC 编程中很多隐式类型转换会悄悄发生。例如在表达式中同时使用 INT 和 REAL不同编译器会做不同的隐式处理。为了代码可读性和可移植性建议所有跨类型运算都写成显式转换。示例对比// 不推荐的写法 result : a b; // 如果 a 是 INTb 是 REAL结果取决于编译器 // 推荐的写法 result : INT_TO_REAL(a) b; // 明确告诉别人你想做什么7.3 注意 PLC 扫描周期与数据一致性读取 32 位数据DINT 或 REAL时PLC 在单个扫描周期内可能只完成了高 16 位的读取而此时数据源已经更新了低 16 位导致读到组合后的数据是“撕裂”的。解决方式使用通讯指令库自带的 32 位读取功能在读数前先暂停数据更新如某些仪表有保持寄存器连续读取两次比较结果一致再使用在中断或通讯完成事件中统一处理数据。7.4 仿真与测试优先进制转换和数据类型相关的逻辑适合先用 PLC 仿真功能验证不一定需要真实硬件。西门子博途有 S7-PLCSIM可以仿真三菱 GX Works 也有仿真器国产 PLC 多数也自带仿真工具。仿真环境最大的价值在于可以随意输入固定值快速验证转换公式和组合逻辑。7.5 现场变更时的安全检查在生产环境中修改数据类型、量程、通讯地址时务必遵循先在仿真中验证备份当前项目修改前记录原有参数小范围灰度测试设备运行中在线修改时评估对当前流程的影响必要时停机修改。8. 总结与下一步学习建议本讲的内容量比较大核心要点可以概括为进制转换的数学原理二进制、十六进制、十进制之间可以相互转换PLC 监控时按需切换显示格式数据类型的本质同一串二进制数据按不同方式解释结果完全不同类型使用原则整型用于离散计数、浮点型用于连续工程量、BOOL 用于状态、WORD/DWORD 用于通讯原始数据工程转换公式模拟量原始值到工程量的线性换算、Modbus 双寄存器组合浮点数、脉冲数与毫米换算调试方法论先确认原始值再用固定值验证解析逻辑最后才排查外部设备。学完这一讲建议你动手做以下练习在你的 PLC 编程软件中新建三个变量分别是 INT、REAL 和 DWORD分别写入 100、1.0 和16#3F800000观察监控表里的显示差异用模拟量模块接一个电位器按本讲的公式做一次工程值转换找一台支持 Modbus 的设备尝试读取浮点数并正确解析记录高低字顺序。进制转换与数据类型是 PLC 从入门到进阶的分水岭。掌握好这一部分后续学习 PID 调节、运动控制、现场总线通讯都会顺畅很多。下一讲我们可以深入一个实际机台的控制程序把本讲的知识放进完整案例中继续巩固。如果这篇文章对你有帮助欢迎收藏备用也欢迎在评论区留下你在调试中遇到的进制或数据类型相关的问题。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进