如何用最小的modbus读取数字计数器的寄存器

Posted

技术标签:

【中文标题】如何用最小的modbus读取数字计数器的寄存器【英文标题】:How to read register of digital counter with minimalmodbus 【发布时间】:2021-08-27 00:01:12 【问题描述】:

我正在尝试使用 Modbus RTU RS-485 读取工业数字计数器的值。使用USB-RS-485转换,这里是主发送代码取自以下datasheet,

Datasheet Link

我期望读取的输入寄存器是我所期望的,minimalmodbus的API期望指定寄存器号、小数位数和功能码。

库是否自动分配从属编号,还是我们必须定义它? 从datasheet看,是不是寄存器号就是地址? 如果有两个数据序列作为响应,我期望有多少位小数? CRC16 检查是否已包含在库中,因为我不应该对其进行编码?

到目前为止,这是我的代码,正在修改示例。

import minimalmodbus
import time

# port name, slave address (in decimal)
instrument = minimalmodbus.Instrument('/dev/ttyUSB0', 1)

instrument.serial.baudrate = 9600      
instrument.serial.bytesize = 8
instrument.serial.stopbits = 1
instrument.serial.timeout  = 1          
instrument.mode = minimalmodbus.MODE_RTU  
instrument.clear_buffers_before_each_transaction = True
instrument.debug = True

while True:
    # Register number, number of decimals, function code
    # not sure what to expect on number of register, is it 31004, 31005?
    
    digit_count = instrument.read_register(1, 2, 4)
    print(digit_count)
    time.sleep(1) 

我已经阅读了 Python Modbus 的其他库,我很乐意获得任何与 Modbus 相关的更好的编码建议。之前谢谢你。

【问题讨论】:

【参考方案1】:

库是否自动分配从属编号,还是我们必须定义它?

使用MinimalModbus,您可以在minimalmodbus.Instrument('/dev/ttyUSB0', 1) 调用中传递从属ID(1 是从属ID)。您在设备本身上设置从 ID 的方式各不相同(Modbus over serial line spec 未涵盖此内容;可能是配置程序、DIP 开关、基于序列号等。其他库可能采用不同的方法(例如默认为从ID 1)。

从datasheet看,是不是寄存器号就是地址?

规格表中的标题显示“否(地址)”,因此“10001(0000)”表示寄存器 1,地址 0(这些指的是同一件事;我建议阅读“Modbus:当 40001 真正意味着 1,或 this article 中的 0 真正意味着 1" 部分,它解释了一些与解决有关的问题)。

如果有两个数据序列作为响应,我期望有多少位小数?

不太清楚“两个数据序列”是什么意思。 Modbus spec 仅详细说明位(线圈)和 16 位值(输入/保持寄存器)的发送。快速浏览一下您的规格,该设备似乎只使用一个寄存器;例如“OUT1 输出时间”有“单位:×10㎳”所以取寄存器中的任何内容除以 10 得到 ms。

CRC16 检查是否已包含在库中,因为我不应该对其进行编码?

任何体面的 Modbus 库都会为您处理协议详细信息(例如 CRC)(所以您不需要编写此代码;MinimalModbus will calculate 为您服务)

【讨论】:

谢谢,我所说的数据序列是指我提供的图像响应中的两个数据,如果我没记错的话,我假设它是 2 个字节(H 中的 E2 40 00 01) - 如何获取E2 40 00 01 的数据?我仍然很困惑,因为在文档上,主人需要向指定的寄存器发送查询,这与代码有点不同?或者如果我们指定功能代码为 4,库是否会设法发送查询?假设我想从 No -> 31004 获取信息,是否只是数字寄存器是 4 放在参数上(或 31004?)。 Minimal modbus 将为您处理大部分内容(read_register 返回一个 16 位整数;该库会为您处理详细信息)。该库将发送查询并将响应处理为可用的东西。对于最小的 modbus,您将传递地址,因此 31004 = read_register(1003,0,3,true)(请注意,“计数器/计时器的当前值”可能会拆分为两个寄存器,但文档对此并不清楚)。 感谢您非常明确的回复。是的,我相信它被拆分为两个 31004 31005 寄存器,可能我稍后必须将它们组合起来并进行十六进制到十进制的转换。我假设 1003 是十进制的 03EB,因此:read_register(1003,0,3,true)read_register(1004,0,3,true)。但是,为什么您编写的功能代码是 3,因为数据表中是 4?对不起,多余的问题 抱歉你是对的read_register(1004,0,4,true)(电话接听)。在规范中找到重新组合寄存器“31004:Present Value(Low Word),31005:Present Value(High Word)”的位,因此您可以使用read_long(1003, 4, true, BYTEORDER_LITTLE) 阅读此内容(库将为您组合这些值)。 “十六进制到十进制转换”不确定您为什么觉得需要这样做(Modbus 函数将返回一个数字 - 十六进制/十进制仅在您需要显示时才起作用)。 确实很清楚,感谢功能代码的澄清。是的,我认为返回值是十六进制的,例如“03H”或任何东西,我只想要整数或十进制的数据,只是为了将值发送到数据中心。

以上是关于如何用最小的modbus读取数字计数器的寄存器的主要内容,如果未能解决你的问题,请参考以下文章

modbus数据格式

csv文件 长数据 用excel打开为科学计数法 用记事本打开显示为准确的数字 如何用excel打开也是准确数字

寄存器PLC地址与寄存器modbus协议地址

在 JavaScript 中将两个 16 位数字组合并转换为一个 32 位数字(浮点数)

如何读取modbus寄存器中的值

如何用java读取文件并统计文件的大小写字母,数字,特殊字符的个数