【modbus-C#】 NModbus4 使用

ff49fa2b9135c17aa307909b84ae7df5.png

813f7f9a943519fe48e836388f28cfa4.png

演示界面

视频演示















Modbus Encoding for Floating Point Values

IEEE 754 单精度浮点格式是表示浮点数的最流行方法,但需要 32 位。制造商已决定使用 2 个连续的 Modbus 寄存器来编码浮点值。这听起来很容易……但是,没那么快。尽管同意使用 2 个连续的寄存器对浮点值进行编码,但对于数据发送的顺序没有标准方法。

示例:对于浮点值 50.123,IEE 754 单精度浮点表示如下所示。

Decimal50.1230049133
Binary01000010010010000111110111110100
Hexidecimal0x42487df4

分成两个 16 位字(寄存器):高 0x4248 低 0x7df4。Modbus 保持寄存器 40001 和 40002 的编码。一些制造商先发送高位字,然后发送低位字。

Modbus RegContents HexContents Decimal
4000010x7df432244
4000020x424816968

其他制造商先发送低位字,然后发送高位字。

Modbus RegContents HexContents Decimal
4000010x424816968
4000020x7df432244

How to read Modbus floating point values

大多数 Modbus 主站提供了一种交换浮点值字序的方法。请查阅相关设备的通信点列表,以确定用于对浮点值进行编码的字(寄存器)顺序。根据该设置配置主设备。

如果没有提供有关如何发送数据的信息,则它将成为一个试错过程。选择一种格式并配置主设备以读取该格式的值。如果读回的值非常不准确,则交换单词,这通常会更正读回的值。















如何在 MODBUS RTU 消息中编码真实(浮点)和 32 位数据

本文讨论了通过 Modbus RTU 处理 32 位数据类型时遇到的一些典型困难,并为解决这些问题提供了实际帮助。

点对点 Modbus 协议是 RTU 通信的流行选择,如果没有其他原因,它是基本的便利。该协议本身控制 Modbus 网络上每个设备的交互,设备如何建立已知地址,每个设备如何识别其消息以及如何从数据中提取基本信息。本质上,协议是整个 Modbus 网络的基础。

然而,这种便利并非没有一些复杂性,Modbus RTU 消息协议也不例外。该协议本身是基于具有 16 位寄存器长度的设备设计的。因此,在实现 32 位数据元素时需要特别考虑。这个实现决定使用两个连续的 16 位寄存器来表示 32 位数据或基本上 4 字节的数据。正是在这 4 个字节的数据中,可以将单精度浮点数据编码为 Modbus RTU 消息。

The Importance of Byte Order

Modbus 本身没有定义浮点数据类型,但人们普遍认为它使用 IEEE-754 标准实现 32 位浮点数据。然而,IEEE 标准对数据有效载荷的字节顺序没有明确的定义。因此,在处理 32 位数据时,最重要的考虑因素是以正确的顺序寻址数据。

例如,IEEE 754 标准中为单精度 32 位浮点数定义的数字 123456.00 如下所示:

18c51c64ca9dbcec92bc21d533ef4bb3.png

各种字节顺序的影响是显着的。例如,将表示 123456.00 的 4 字节数据按“B A D C”序列排序,称为“字节交换”。当解释为 IEEE 744 浮点数据类型时,结果完全不同:

9ce87821fa0b107527f6a3cd921633a1.png

在“C D A B”序列中对相同字节进行排序称为“字交换”。同样,结果与 123456.00 的原始值有很大不同:

542201b01ff4465350084ed8952473fc.png

此外,“字节交换”和“字交换”本质上都会完全颠倒字节顺序以产生另一个结果:

f38b11a48d3668e4c9e650c0f46aec34.png

显然,在使用 Modbus 等网络协议时,必须严格注意内存字节在传输时是如何排序的,也称为“字节顺序”。

Determining Byte Order

根据 Modbus 应用协议规范 V1.1.b,Modbus 协议本身被声明为“大端”协议:

  “Modbus 使用“big-Endian”表示地址和数据项。这意味着当传输大于单个字节的数字量时,首先发送最高有效字节。”

Big-Endian 是网络协议最常用的格式——事实上,它非常普遍,也被称为“网络顺序”。

鉴于 Modbus RTU 消息协议是 big-Endian,为了通过 Modbus RTU 消息成功交换 32 位数据类型,必须考虑主从机的字节序。许多 RTU 主设备和从设备允许特定的字节顺序选择,特别是在软件模拟单元的情况下。只需确保所有单元都设置为相同的字节顺序。

根据经验,设备微处理器的家族决定了它的字节序。通常,大端风格(首先存储高位字节,然后是低位字节)通常出现在使用摩托罗拉处理器设计的 CPU 中。little-Endian 风格(首先存储低位字节,然后是高位字节)通常出现在使用 Intel 架构的 CPU 中。至于哪种风格被认为是“倒退”,这是个人观点的问题。

但是,如果字节顺序和字节顺序不是可配置的选项,您将必须确定如何解释字节。这可以通过从从站请求一个已知的浮点值来完成。如果返回不可能的值,即具有两位数指数等的数字,则很可能需要修改字节顺序。

Practical Help

FieldServer Modbus RTU 驱动程序提供了几个处理 32 位整数和 32 位浮点值的函数移动。更重要的是,这些函数移动考虑了所有不同形式的字节排序。下表显示了 FieldServer 函数将两个相邻的 16 位寄存器复制到一个 32 位整数值的移动。

Function KeywordSwap ModeSource BytesTarget Bytes
2.i16-1.i32N/A[ a b ] [ c d ][ a b c d ]
2.i16-1.i32-s

byte and

  word swap

[ a b ] [ c d ][ d c b a ]
2.i16-1.i32-sbbyte swap[ a b ] [ c d ][ b a d c ]
2.i16-1.i32-swword swap[ a b ] [ c d ][ c d a b ]

下表显示了将两个相邻 16 位寄存器复制到 32 位浮点值的 FieldServer 函数移动:

Function KeywordSwap ModeSource BytesTarget Bytes
2.i16-1.ifloatN/A[ a b ] [ c d ][ a b c d ]
2.i16-1.ifloat-sbyte and word swap[ a b ] [ c d ][ d c b a ]
2.i16-1.ifloat-sbbyte swap[ a b ] [ c d ][ b a d c ]
2.i16-1.ifloat-swword swap[ a b ] [ c d ][ c d a b ]

下表显示了将单个 32 位浮点值复制到两个相邻 16 位寄存器的 FieldServer 函数移动:

Function KeywordSwap ModeSource BytesTarget Bytes
1.float-2.i16N/A[ a b c d ][ a b ][ c d ]
1.float-2.i16-sbyte and word swap[ a b c d ][ d c ][ b a ]
1.float-2.i16-sbbyte swap[ a b c d ][ b a ][ d c ]
1.float-2.i16-swword swap[ a b c d ][ c d ][ a b ]

鉴于各种 FieldServer 功能移动,正确处理 32 位数据取决于选择正确的。观察这些 FieldServer 函数在已知单精度十进制浮点值 123456.00 上移动的以下行为:

16-bit ValuesFunction MoveResultFunction MoveResult
0x2000 0x47F12.i16-1.float123456.001.float-2.i160x2000 0x47F1
0xF147 0x00202.i16-1.float-s123456.001.float-2.i16-s0xF147 0X0020
0x0020 0xF1472.i16-1.float-sb123456.001.float-2.i16-sb0x0020 0xF147
0x47F1 0x20002.i16-1.float-sw123456.001.float-2.i16-sw0x47F1 0x2000

请注意,不同的字节和字顺序需要使用适当的 FieldServer 函数移动。一旦选择了正确的功能移动,数据就可以双向转换。

在 Internet 上可用的许多十六进制到浮点数转换器和计算器中,很少有人真正允许对字节和字序进行操作。一个这样的实用程序可以在这里找到(https://www.h-schmidt.net/FloatConverter/IEEE754.html)。该实用程序显示十进制浮点值 123456.00,如下所示:

b1a145d1bc5d6cdacb7b1e023d4d55d5.png

然后可以交换字节和/或字以分析 Modbus RTU 主设备和从设备之间可能存在哪些潜在的字节顺序问题。

参考:

1>https://store.chipkin.com/articles/how-real-floating-point-and-32-bit-data-is-encoded-in-modbus-rtu-messages

2>https://www.cnblogs.com/wjx-blog/p/13419909.html

3>https://blog.csdn.net/qq_34699535/article/details/111658342

4>https://blog.csdn.net/XUMENGCAS/article/details/122305152

5>https://www.thepyroscope.com/blog/modbus-comms-how-to-set-floating-point-values/

6>https://www.h-schmidt.net/FloatConverter/IEEE754.html


附部分源码

private void btn_write_Click(object sender, EventArgs e)
        {
            float value;
            bool ok = float.TryParse(txt_float.Text, out value);
            if (ok)
            {
                ushort lowOrderValue = BitConverter.ToUInt16(BitConverter.GetBytes(value), 2);// 后16bit
                ushort highOrderValue = BitConverter.ToUInt16(BitConverter.GetBytes(value), 0);//前16bit
                ushort[] data = new ushort[2];
                data[0] = lowOrderValue;//低16位  存入前一寄存器
                data[0 + 1] = highOrderValue;//高16位  存入后一寄存器
                try
                {
                    master.WriteMultipleRegisters(1, 0, data);
                    Thread.Sleep(2000);
                    txt_float.Text = "NULL";
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }
private void btn_read_Click(object sender, EventArgs e)
        {
            ushort[] res = master.ReadHoldingRegisters(1, 0, 2);
            float ret = GetFloatFormUshortArray(res);
            txt_float.Text = ret.ToString();
        }

The End

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值