当前位置:   article > 正文

python实现ModBusRTU服务端_modbusslavecontext

modbusslavecontext

python实现基于串口通信的ModBusRTU服务端是一件简单的事情,只要通过pymodbus模块就可以实现。

一、一个Demo及其引发的问题

1、一个Demo

  1. import asyncio
  2. import json
  3. import threading
  4. import time
  5. from pymodbus.server import StartSerialServer, ServerAsyncStop
  6. from pymodbus.datastore import ModbusSequentialDataBlock, ModbusServerContext, ModbusSlaveContext
  7. from pymodbus.transaction import ModbusRtuFramer
  8. from Application.common.private_socket import Request
  9. if __name__ == "__main__":
  10. # 定义串口配置
  11. port = "COM46"
  12. # Serial(port="COM46", baudrate=115200, timeout=2, bytesize=8, parity="N", stopbits=1)
  13. framer = ModbusRtuFramer
  14. # 创建数据存储区
  15. # data_block = ModbusSequentialDataBlock(0, [0] * 100) # 100个保持寄存器?
  16. data_block = ModbusSlaveContext(
  17. hr=ModbusSequentialDataBlock(0, [0] * 100)
  18. )
  19. # store = ModbusSlaveContext(hr=data_block)
  20. # context = ModbusServerContext(slaves=store)
  21. context = ModbusServerContext(slaves={1: data_block}, single=False)
  22. # 启动Modbus RTU服务器
  23. # StartSerialServer(context=context, framer=framer, port="COM46")
  24. # thread = threading.Thread(target=StartSerialServer, kwargs={"context": context, "framer": framer, "port": port, "baudrate":9600, "timeout":2, "bytesize":8, "parity":"N", "stopbits":1})
  25. thread = threading.Thread(target=StartSerialServer, kwargs={"context": context, "framer": framer, "port": port, "baudrate":9600})
  26. thread.start()
  27. # 设置保持寄存器的0地址的值为s
  28. # 定义函数参数
  29. write_address = 0 # 起始地址
  30. read_address = 10
  31. read_count = 10
  32. values = [115] # 触发指令s 要设置的多个值列表,如[10, 20, 30]
  33. # 调用函数,设置0地址为触发指令s
  34. data_block.setValues(16, write_address, values)
  35. while True:
  36. time.sleep(3)
  37. # 获取保持寄存器的值并打印
  38. hr_values = data_block.getValues(3, 0, count=20)
  39. print("Hold Register Values:", hr_values)
  40. asyncio.run(ServerAsyncStop()) # 停止服务器

在这里简单说明上述程序涉及到的对象:

(1)ModbusRtuFramer的作用

Modbus 通信协议中,数据以帧的形式进行传输。ModbusRtuFramer 是 pymodbus 库中的一个类,它的作用是负责处理 Modbus RTU 帧的编码和解码。

具体来说,ModbusRtuFramer 完成了以下几个主要任务:

①编码(封装)Modbus RTU 帧:当你需要发送 Modbus RTU 请求或响应时,ModbusRtuFramer 负责将请求或响应的数据按照 Modbus RTU 协议的格式进行封装,生成符合 Modbus RTU 规范的帧,以便发送到 Modbus 设备。

②解码(解析)Modbus RTU 帧:当你从 Modbus 设备接收到数据时,ModbusRtuFramer 负责将接收到的二进制数据按照 Modbus RTU 协议的格式进行解析,提取出请求或响应的数据,以便进行后续的处理和分析。

③错误检测和纠正:ModbusRtuFramer 也负责检测 Modbus RTU 帧中的错误,比如奇偶校验错误、帧起始符和结束符错误等。如果帧中存在错误,ModbusRtuFramer 会帮助你识别错误的位置和类型,便于进行纠正或错误处理。

总之,ModbusRtuFramer 是一个处理 Modbus RTU 帧的工具,它确保了在 Modbus RTU 通信中,数据的正确封装和解析,以及错误的检测和处理。

(2)ModbusSequentialDataBlock、ModbusSlaveContext与ModbusServerContext的作用

在 pymodbus 库中,ModbusSequentialDataBlock、ModbusSlaveContext 和 ModbusServerContext 是用来处理 Modbus 数据存储和上下文的类,它们的作用如下:

①ModbusSequentialDataBlock:

ModbusSequentialDataBlock 是一个用于创建顺序排列的 Modbus 寄存器块的类。
它通常用于模拟设备的保持寄存器(Holding Registers)或输入寄存器(Input Registers)。
这个类允许你定义寄存器的起始地址和初始化寄存器的值。
例如:ModbusSequentialDataBlock(0, [0] * 100) 创建了一个从地址 0 开始,包含 100 个初始值为 0 的保持寄存器的块。


②ModbusSlaveContext:

ModbusSlaveContext 是一个用于表示 Modbus 从设备的类。
它包含一个或多个数据存储块(比如保持寄存器块、输入寄存器块等)。
这个类可以用来创建一个模拟的 Modbus 从设备上下文。
你可以在这个上下文中添加多个不同类型的数据块,模拟一个完整的 Modbus 从设备。


③ModbusServerContext:

ModbusServerContext 是一个用于表示整个 Modbus 服务器的类。
它包含一个或多个 Modbus 从设备的上下文(ModbusSlaveContext 实例)。
这个类可以用来创建一个完整的 Modbus 服务器环境,包含多个模拟的 Modbus 从设备。

在搭建 Modbus 通信环境时,你通常会创建 ModbusSequentialDataBlock 实例作为寄存器的存储,然后将它们添加到 ModbusSlaveContext 中。最后,将多个 ModbusSlaveContext 实例添加到 ModbusServerContext 中,以构建一个包含多个从设备的 Modbus 服务器环境。这样的架构可以让你模拟多个不同类型的 Modbus 从设备。

(3)context = ModbusServerContext(slaves={1: data_block}, single=False)的解释

在这个代码行中,你创建了一个 ModbusServerContext 对象,该对象用于模拟一个 Modbus 服务器的上下文。ModbusServerContextpymodbus 模块中的一个类,它用于存储和管理 Modbus 服务器的数据。在这个特定的代码行中,你传递了一些参数给 ModbusServerContext 构造函数:

  • slaves={1: data_block}: 这个参数是一个字典,表示 Modbus 服务器的从设备。在这里,你创建了一个从设备,其 Modbus 地址为 1,并且将这个从设备关联到了一个 data_block 对象上。data_block 可能是一个 ModbusSequentialDataBlock 对象,用于存储 Modbus 寄存器的数据。

  • single=False: 这个参数用于确定是否将所有的从设备视为一个整体。当 single=True 时,所有的从设备共享相同的 Modbus 地址空间,它们没有独立的地址范围。而当 single=False 时,每个从设备都有独立的 Modbus 地址空间,它们的地址范围是相互独立的。

所以,这一行代码的意义是创建了一个 ModbusServerContext 对象,该对象包含一个从设备(Modbus 地址为 1),并且这个从设备拥有独立的 Modbus 地址空间。这个上下文可以在模拟多个独立的 Modbus 设备时使用。

(4)关于StartSerialServer启动服务器时必须的参数

必须传入以下参数才能正常启动

  • "context": context 表示传入的 Modbus 上下文。
  • "framer": framer 表示 Modbus 使用的帧格式。
  • "port": port 表示串口号,例如 "COM46"
  • "baudrate": baudrate表示波特率,即每秒传输的位数。

这些参数将被传递给 StartSerialServer 函数,用于启动 Modbus RTU 服务器。

这需要根据客户端的设置来对应设置。

2、权限问题

建议使用管理员权限运行脚本。

3、端口占用问题

确保端口没有被其他软件占用。

4、pymodbus版本问题

网上的示例代码,StartSerialServer要求传入serial模块的Serial(port=COM, baudrate=Baudrate, timeout=2, bytesize=Databits, parity=Parity, stopbits=Stopbits)实例,我不确定是哪个版本,你可以试一下,目前在新版本只要传入波特率和端口即可。

二、pymodbus相关文档

1、官方文档地址

Datastore — PyModbus 3.6.0dev documentation

2、Datastore对象

Datastore is responsible for managing registers for a server.

(1)pymodbus.datastore.ModbusSparseDataBlock

pymodbus.datastore.ModbusSparseDataBlock 是 PyModbus 库中用于创建稀疏数据块(sparse data block)的类。在 Modbus 协议中,数据通常被组织成多个数据块,而每个数据块包含一定数量的数据寄存器或者线圈。

ModbusSparseDataBlock 允许您创建包含不连续地址的数据块。具体来说,您可以在数据块中指定特定地址的数据,而无需为数据块的每个地址都分配内存。这种方式可以有效地节省内存空间,尤其是在处理大量数据时。

以下是 ModbusSparseDataBlock 的初始化参数:

  • values:一个字典,包含要存储的数据。字典的键是地址,值是相应地址的数据值。
  • address:数据块的起始地址。
  • size:数据块的大小,即包含的地址数量。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/991520
推荐阅读
相关标签
  

闽ICP备14008679号