我的任务是实现基于pymodbus的Modbus服务器。该服务器将在Raspberry Pi或Up2控制器等Linux机器上运行。预计将与我无法控制的Modbus客户端对接。该外部Modbus客户端期望能够读取输入寄存器以及保存由我的Modbus服务器提供的寄存器。
我可以设置将由外部客户端读取的HOLDING寄存器的值。我无法设置外部客户端将读取的INPUT寄存器的值。怎么做到的?
我看到这篇帖子问了类似的问题,但似乎从未有人回答过这个问题:
How to write to PLC input registers using pymodbus
在此先感谢您的帮助!
答案 0 :(得分:0)
正如我所说,我对python或pymodbus不熟悉,但请看一下这个示例,它类似于我预期的样子:https://pymodbus.readthedocs.io/en/latest/source/example/updating_server.html
创建了四个100个“寄存器”阵列作为数据存储。我假设di =数字输入,co =线圈,hr =保持寄存器,ir =输入寄存器
store = ModbusSlaveContext(
di=ModbusSequentialDataBlock(0, [17]*100),
co=ModbusSequentialDataBlock(0, [17]*100),
hr=ModbusSequentialDataBlock(0, [17]*100),
ir=ModbusSequentialDataBlock(0, [17]*100))
context = ModbusServerContext(slaves=store, single=True)
然后在后台线程调用的“ updating_writer(a)”中更新这些值。在我看来,它每次调用时都会对每个值加1。在现实世界的PLC中,此功能可能会读取传感器,设置和其他操作/状态/配置数据之类的信息。
答案 1 :(得分:0)
感谢Marker和所有在线示例。我终于按需完成了这项工作。希望这对其他人有帮助。
我遇到了几个陷阱:
很好...
首先,我必须这样做:
from threading import Thread
然后我像以前一样在进程中启动了以下操作,但是在调用StartTcpServer之前,我启动了update_writer线程(所有start_addr,init_val和num_addrs变量均已设置为较早)。
discrete_inputs_obj = ModbusSequentialDataBlock(di_start_addr, [di_init_val]*di_num_addrs)
coils_obj = ModbusSequentialDataBlock(co_start_addr, [co_init_val]*co_num_addrs)
holding_regs_obj = ModbusSequentialDataBlock(hr_start_addr, [hr_init_val]*hr_num_addrs)
input_regs_obj = ModbusSequentialDataBlock(ir_start_addr, [ir_init_val]*ir_num_addrs)
mb_store = ModbusSlaveContext(di=discrete_inputs_obj, co=coils_obj, hr=holding_regs_obj, ir=input_regs_obj, zero_mode=True)
mb_context = ModbusServerContext(slaves=mb_store, single=True)
mb_store = ModbusSlaveContext(
di=ModbusSequentialDataBlock(di_start_addr, [di_init_val]*di_num_addrs),
co=ModbusSequentialDataBlock(co_start_addr, [co_init_val]*co_num_addrs),
hr=ModbusSequentialDataBlock(hr_start_addr, [hr_init_val]*hr_num_addrs),
ir=ModbusSequentialDataBlock(ir_start_addr, [ir_init_val]*ir_num_addrs))
mb_context = ModbusServerContext(slaves=mb_store, single=True)
updating_writer_cfg = {}
updating_writer_cfg["mb_context"] = mb_context
updating_writer_cfg["managed_obj"] = managed_obj #For being able to send messages to this Thread
updating_writer_thread = Thread(target = updating_writer, args = [updating_writer_cfg]) # We need this to be a thread in this process so that they can share the same datastore
updating_writer_thread.start()
StartTcpServer(mb_context, address=("", port))
在update_writer的While循环中,我有轮询polled_obj的代码以接收消息。在该循环中添加关键代码的地方是:
mb_context[0].setValues(4, addr_to_write, regs_to_write)
......其中4是写入功能,addr_to_write是开始写入的寄存器地址,而regs_to_write是寄存器值的列表... AND ...
regs_to_read = mb_context[0].getValues(3, addr_to_read, num_regs_to_read)
...其中3是读取函数,addr_to_read是开始读取的寄存器地址。 regs_to_read将是长度为num_regs_to_read的列表。