- 威纶通 EasyBuilder Pro 的穿透传输(Pass-Through)功能死穴: 威纶通 cMT 系列 HMI,网口接外网/局域网,串口(RS485)接三菱 FX3U PLC。 在 EBPr
- 松下 A6 伺服脉冲控制调到怀疑人生: A6 伺服驱动器(带 20 位高精编码器),接 PLC 发送差分脉冲(PULSE/DIR)控制定位。 电机低速(100 rpm)运转时,声音极度安静,定位也准
- 求助施耐德 Modicon M241 走 Ethernet/IP 控 ATV340 的抗干扰死坑: 软件使用 EcoStruxure Machine Expert。PLC 通过网线直接连接 3 台
- 台达 AS300 走 CANopen 控制自家 C2000 变频器求助: AS300 主机自带 CANopen 总线,通过台达官方软件(ISPSoft / CANopen Builder)配置了 DS
- 被欧姆龙 PLC 和第三方/自家 HMI 的 Modbus TCP 数据格式折腾炸了: OMRON NX1P2 PLC 作为 Modbus TCP Server,给触摸屏提供温度和压力数据(32 位
被欧姆龙 PLC 和第三方/自家 HMI 的 Modbus TCP 数据格式折腾炸了: OMRON NX1P2 PLC 作为 Modbus TCP Server,给触摸屏提供温度和压力数据(32 位
联系人:15634442347583
电话/手机:联系客服
发布时间:2026-09-22 09:10
浏览:57次
OMRON NX1P2 PLC 作为 Modbus TCP Server,给触摸屏提供温度和压力数据(32 位 IEEE 754 浮点数)。
通讯链路完全连通,整数(INT/DINT)读取非常平稳。
奇葩故障: 只要读取 REAL 浮点数(比如 25.5),触摸屏上显示出来就是类似 NaN 或者 -3.45e+38 这类天文数字乱码!
我在触摸屏端切换了高低字转换(Byte Swap / Word Swap),试遍了 AB CD、CD AB、BA DC 四种排列组合,没有一个是对的!
为什么标准的 32 位浮点数在 OMRON 的 Modbus 地址映射里,怎么换字序都解不出正确小数?



















































因为如果 PLC 里真的是标准 IEEE-754 的 REAL#25.5,它的 32 位位型固定就是:
25.5
=
16#41CC0000
无论厂家怎么排列,Modbus 上最终只能是这 4 个字节的排列组合。你把常见四种顺序都试完仍然没有 25.5,说明:
触摸屏读到的那两个 Holding Register,压根就不是 41CC0000 这32个位。
这才是这个案子的突破口。
Modbus 本身根本没有“REAL寄存器”
Modbus 标准只规定:
Input Register = 16 bit
Holding Register = 16 bit
它没有规定“32位浮点数怎么存”,也没有规定两个16位寄存器谁是高字谁是低字。32位 REAL 必须由设备厂家自己拆成两个连续寄存器。Modbus
而 NX1P2 的:
REAL = 32 bit / 4 byte
所以你必须主动完成:
PLC REAL
↓
保留IEEE754原始32位位型
↓
拆成两个WORD
↓
送进Modbus Holding Register区
不能直接认为:
REAL变量
=
两个Modbus寄存器
会自动成立。
我第一怀疑:PLC程序里做了“数值转换”,而不是“位型复制”
这在 Sysmac Studio 里特别容易踩坑。
假设:
Temperature : REAL := 25.5;
它的 IEEE754 位型是:
41 CC 00 00
正确做法是原封不动复制这32个位。
Omron 官方为 NJ/NX 专门提供:
CopyRealToDword
它的定义就是:
把 REAL 的原始 bit pattern 直接复制到 DWORD,不进行数值换算。
官方例子:
REAL#2.5
↓ CopyRealToDword
DWORD#16#40200000
32个位完全不变。Omron eData
反方向也是:
CopyDwordToReal
官方明确叫 Bit Pattern Copy,例如:
DWORD#16#40200000
↓
REAL#2.5
而不是把十六进制整数 1075838976 数值转换成浮点数。Omron Files
如果程序写成类似这种逻辑,就错了
概念上:
HoldingReg[0] := REAL_TO_WORD(Temperature);
或者先:
Temperature
↓
转换成整数
↓
DWORD
↓
拆两个WORD
那么:
25.5
可能先变成:
25
=
16#0019
此时寄存器里根本没有:
16#41CC0000
你在 HMI 上:
ABCD
CDAB
BADC
DCBA
换一万遍也不可能重新得到25.5。
字序交换只能重新排列已经存在的位,不能把错误的数据类型转换重新变回 IEEE754。
最快的破案方法:不要看 HMI 浮点显示,直接看两个原始寄存器的 HEX
把 PLC 温度暂时固定成:
REAL#25.5
然后让 HMI 或 Modbus Poll 按两个16位无符号整数/HEX读取。
正确结果必须出现下面之一。
高字在前
Register N = 16#41CC
Register N+1 = 16#0000
网络四字节:
41 CC 00 00
低字在前
Register N = 16#0000
Register N+1 = 16#41CC
四字节:
00 00 41 CC
如果设备还进行了单字节交换,也无非是:
CC 41 00 00
或者:
00 00 CC 41
所以诊断特别简单:
25.5固定
↓
直接看两个寄存器HEX
只要找不到 41CC 和 0000 这一对,问题就在 PLC/Modbus Server 映射端,跟 HMI 的 Float Swap 已经没关系了。
如果看到 0019,几乎当场破案
例如:
Reg 100 = 0019
Reg 101 = 0000
这就说明:
REAL 25.5
↓
被当作“数值”转换
↓
INT/WORD 25
而不是:
25.5
↓
IEEE754
↓
41CC0000
这种情况下应改成:
Temperature REAL
↓
CopyRealToDword
↓
DWORD 41CC0000
↓
High Word = 41CC
Low Word = 0000
然后再送进 Modbus Server 的 WORD 缓冲区。
我建议 NX1P2 根本不要把业务 REAL 变量直接映给 Modbus
最稳妥的架构是专门建立:
MB_Holding : ARRAY[...] OF WORD
所有 Modbus 数据都先打包进去。
例如:
PLC内部:
Temp_1 REAL = 25.5
Pressure_1 REAL = 1.25
先做:
Temp_1
↓
CopyRealToDword
↓
41CC0000
↓
MB_Holding[100] = 41CC
MB_Holding[101] = 0000
压力:
1.25
↓
3FA00000
↓
MB_Holding[102] = 3FA0
MB_Holding[103] = 0000
于是寄存器地图永远非常清楚:
Modbus寄存器 内容
40101 Temp1 High Word
40102 Temp1 Low Word
40103 Pressure1 High Word
40104 Pressure1 Low Word
这比让 Modbus FB 自己去猜:
REAL
DINT
INT
到底怎样排内存稳定得多。
NX/NJ 本身也支持 REAL、DWORD、WORD 以及 Union,因此可以用共同内存/位型方式做这类打包。ia.omron.com
第二嫌疑:32位数据“错位一个寄存器”
如果 PLC 端实际已经正确:
40101 = 41CC
40102 = 0000
40103 = 4148
40104 = 0000
但 HMI 从:
40102
开始读 Float,
它拿到的就变成:
0000 4148
这当然就是一个极小的怪数字。
更严重一点:
40102 = 0000
40103 = FFA5
拼起来可能直接形成:
NaN
Infinity
-3.xxE38
所以:
NaN / 极限大数特别像两个不属于同一个 REAL 的 WORD 被拼在了一起。
为什么整数全正常,却只有REAL炸?
因为 INT:
一个Modbus Register
=
一个值
不存在配对问题。
DINT/REAL:
Register N
+
Register N+1
必须同时满足:
起始地址正确
+
两个WORD属于同一个数据
+
Word order正确
+
Byte order正确
只要地址偏1:
[REAL A低字]
+
[REAL B高字]
就能拼出一个完全合法但荒谬的 IEEE754 数。
这里还要特别查 40001 与 Offset 0 的问题
Modbus 官方协议中的逻辑地址实际上是从0开始的无符号索引。Modbus
但是很多 HMI 界面喜欢写成:
40001
40002
40003
有些驱动解释:
40001 → protocol address 0
另一些却要求你直接输入:
0
1
2
如果双方差1,
INT 测试时有时你只是觉得:
“这个地址也有数据。”
但32位 Float 就会立即暴露问题,因为它必须从正确的 Word 边界开始。
所以我建议用这个特殊测试值。
别只测试25.5,再测试两个非常漂亮的数
1.0
IEEE754:
3F800000
因此两个寄存器必须是:
3F80
0000
或:
0000
3F80
100.0
IEEE754:
42C80000
必须看到:
42C8
0000
或者反过来。
这两个特别容易肉眼认。
如果强制 100.0,结果看到
Reg N = 42C8
Reg N+1 = 0000
那么 PLC 完全正确。
接下来只查 HMI:
Float32 / IEEE754
Starting Register
Word Swap
如果看到
Reg N = 0064
那就百分百不是字序问题。
因为:
100 decimal = 0064 hex
说明 PLC 端已经把:
REAL#100.0
做成整数100了。
如果看到
42C8
但是下一地址不是:
0000
而是另一个数据,
说明:
Modbus Server 映射长度/地址布局出了问题。
第三个坑:不要用普通 DWORD_TO_REAL 去做“位型恢复”
这个也是 Sysmac 用户特别容易混淆的地方。
你真正要的是:
41CC0000
这32个位重新解释成:
25.5
所以要的是:
CopyDwordToReal
Omron 官方明确说它是 bit-pattern copy。Omron Files
不是普通数学意义的:
DWORD → REAL
否则可能把:
16#41CC0000
当成十进制十几亿,
然后再转成:
1.xxxE9
完全是另一回事。
我现在给这个问题的嫌疑排序
第一名:NX1P2 的 REAL 没有按位打包成两个 WORD,而是被做了数值类型转换。
这是“四种交换全错”最典型的原因。
第二名:HMI 的32位读取起始地址错一个 Register。
特别查:
0-based / 1-based
40001 / address 0
第三名:Modbus Server 的 Holding Register buffer 本来就是 WORD 数组,但程序把 REAL 直接/错误地塞进去。
NX1P2 通过软件 FB 实现这类 Modbus Server 时,显式建立 WORD 型交换区通常最稳妥;Modbus 协议本身只认识16位寄存器。Modbus
第四名:PLC端数据在两个扫描周期分别更新两个WORD。
可能偶尔形成:
旧High + 新Low
从而短暂得到 NaN/极大数。两个 WORD 最好从同一个 DWORD 快照一次性拆分更新。
现场第一刀其实只需要一分钟
先别再切任何 Swap。
PLC:
Temperature := REAL#25.5;
然后直接查看 Modbus 原始两个寄存器的 HEX。
正确答案必须包含:
41CC
0000
如果没有:
去改 NX1P2 的数据打包。
如果有:
再查 HMI 的起始地址和 Word/Byte Order。
所以这个案例一句话讲透就是:
字节序只能解决“同一组正确的32个位排列顺序不一致”,解决不了“PLC根本没有把 REAL 的 IEEE-754 位型放进 Modbus 寄存器”这个问题。对 NX1P2,最稳的方式是先用官方 CopyRealToDword 做位型复制,再明确拆成两个16位 Holding Register;25.5 在任何正确系统里最终都必须能追踪到 16#41CC0000。如果原始寄存器里根本找不到 41CC/0000 这一对,就不要再折腾 HMI 的 AB/CD 交换了。