python使用pymodbus库进行modbus tcp通信

这篇具有很好参考价值的文章主要介绍了python使用pymodbus库进行modbus tcp通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

使用pymodbus库进行modbus tcp通信

使用python解决工业通信问题是一个非常好的选择,python具有丰富的生态,可以轻松解决工业通信的各种问题。本篇主要介绍使用pymodbus库进行modbus tcp仿真,实现pc端读取plc或工业设备modbus变量。

安装pymodbus:

pip install -U pymodbus

1 创建modbus tcp server

这里我们先创建一个虚拟的modbus设备,如果你手里有一个plc或者工业设备,可以直接跳过本节。

modbus_server.py

'''
 * @Author: liuzhao 
 * @Last Modified time: 2022-10-05 09:56:13 
'''

from pymodbus.server.sync import (
    StartTcpServer,
)
from pymodbus.datastore import (
    ModbusSequentialDataBlock,
    ModbusServerContext,
    ModbusSlaveContext,
)
from pymodbus.version import version

datablock = ModbusSequentialDataBlock.create()
context = ModbusSlaveContext(
    di=datablock,
    co=datablock,
    hr=datablock,
    ir=datablock,
    )
single = True

# Build data storage
store = ModbusServerContext(slaves=context, single=single)


if __name__ == '__main__':

	address = ("0.0.0.0", 503)
	StartTcpServer(
	    context=store,  # Data storage
	    address=address,  # listen address
	  	allow_reuse_address=True,  # allow the reuse of an address
	)

直接运行该脚本,就可以在本机的503端口创建一台modbus设备了,具体实现暂不深追,我们学习的重点是客户端对modbus变量的读写。

2 读写modbus变量

modbus变量类型以及地址

Object type Access Size Address
Coil Read-write 1 bit 00001 – 09999
Discrete input Read-only 1 bit 10001 – 19999
Input register Read-only 16 bits 30001 – 39999
Holding register Read-write 16 bits 40001 – 49999

coil是线圈,Discrete input是数字量输入,Input register是模拟量输入,Holding register是保持寄存器。一般地址范围是0-65535 [wiki]

2.1 读取常规变量

读写线圈 | 读取输入变量 | 读写保持寄存器

from pymodbus.client.sync import ModbusTcpClient
from pymodbus.bit_read_message import ReadCoilsResponse
from pymodbus.register_read_message import ReadInputRegistersResponse
from pymodbus.exceptions import ConnectionException      # 连接失败,用于异常处理

host = '127.0.0.1'
port = 503
client = ModbusTcpClient(host,port)


# 写入线圈
client.write_coil(1, True)
client.write_coil(2, False)
client.write_coil(3, True)

# 读取线圈    注意对于离散量的读取,第二个参数cout是有坑的,必须为8的倍数个
result:ReadCoilsResponse = client.read_coils(address=1,cout=8)     # 从地址1开始读,读取8个线圈,一次读8的倍数个线圈,不设置为8的倍数可能会出现问题
print(result.isError())

# 不建议使用
print(result.getBit(7))            # 这里的参数address不是plc里的地址,而是python列表的address,

print('read_coils ')

# 建议使用
print(result.bits)        # 打印读取结果,一共8位
# 读取其中的位
print(                   
    result.bits[0],
    result.bits[1],
    result.bits[2]
    )         # 相当于result.getBit(0)


# 读取数字输入
result = client.read_discrete_inputs(address=10001,count=8)    # 从10001开始读,读取8位
print(result.bits)


# 读取模拟输入寄存器
input_register_result:ReadInputRegistersResponse = client.read_input_registers(1,count=8)
# print(f'is_error:{input_register_result.isError()}')
print('read_input_registers ')
print(input_register_result.registers)   
print(input_register_result.getRegister(0))   


# 读写保持寄存器
client.write_register(address=40001,value=100)
result:ReadInputRegistersResponse = client.read_holding_registers(address=40001,count=1)
print('read_holding_registers ')
print(result.registers)

# 关闭连接
client.close()


2.2 读取复杂变量

字符串、浮点数、负数等
这里需要注意modbus设备的存储结构是低位低字节还是低位高字节,也就是设备内存的字节、字的排列顺序。

  根据不同的设备,对照下表调整正确的组合方式。
Word Order Byte order Word1 Word2
Big Big 0x1234 0x5678
Big Little 0x3412 0x7856
Little Big 0x5678 0x1234
Little Little 0x7856 0x3412
# 复杂数据类型

from collections import OrderedDict
import logging

from pymodbus.client.sync import ModbusTcpClient as ModbusClient

from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadBuilder, BinaryPayloadDecoder



ORDER_DICT = {"<": "LITTLE", ">": "BIG"}


def run_binary_payload_client(host:str,port:int):
  
    for word_endian, byte_endian in (
        (Endian.Big, Endian.Big),
        (Endian.Big, Endian.Little),
        (Endian.Little, Endian.Big),
        (Endian.Little, Endian.Little),
    ):
        print("-" * 60)
        print(f"Word Order: {ORDER_DICT[word_endian]}")
        print(f"Byte Order: {ORDER_DICT[byte_endian]}")
        print()
    
        builder = BinaryPayloadBuilder(
            wordorder=word_endian,
            byteorder=byte_endian,
        )
		
		# 写入的变量
        my_string = "abcd-efgh123345765432"
        builder.add_string(my_string)
        builder.add_bits([0, 1, 0, 1, 1, 0, 1, 0])
        builder.add_8bit_int(-0x12)
        builder.add_8bit_uint(0x12)
        builder.add_16bit_int(-0x5678)
        builder.add_16bit_uint(0x1234)
        builder.add_32bit_int(-0x1234)
        builder.add_32bit_uint(0x12345678)
        builder.add_16bit_float(12.34)
        builder.add_16bit_float(-12.34)
        builder.add_32bit_float(22.34)
        builder.add_32bit_float(-22.34)
        builder.add_64bit_int(-0xDEADBEEF)
        builder.add_64bit_uint(0x12345678DEADBEEF)
        builder.add_64bit_uint(0x12345678DEADBEEF)
        builder.add_64bit_float(123.45)
        builder.add_64bit_float(-123.45)
        registers = builder.to_registers()
        print("Writing Registers:")
        print(registers)
        print("\n")
        payload = builder.build()
        address = 40001          # 从40001开始写入
        # We can write registers
        client.write_registers(address, registers, unit=1)    # 写入
     	
     	# 读取复杂变量
        print("Reading Registers:")
        address = 40001

        count = len(payload)
        print(f"payload_len {count}")
        result = client.read_holding_registers(address, count, slave=1)
        print(result.registers)
        print("\n")
        decoder = BinaryPayloadDecoder.fromRegisters(
            result.registers, byteorder=byte_endian, wordorder=word_endian
        )
        # Make sure word/byte order is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder
        assert (
            decoder._byteorder == builder._byteorder  # pylint: disable=protected-access
        )  # nosec
        assert (
            decoder._wordorder == builder._wordorder  # pylint: disable=protected-access
        )  # nosec

        decoded = OrderedDict(
            [
                ("string", decoder.decode_string(len(my_string))),
                ("bits", decoder.decode_bits()),
                ("8int", decoder.decode_8bit_int()),
                ("8uint", decoder.decode_8bit_uint()),
                ("16int", decoder.decode_16bit_int()),
                ("16uint", decoder.decode_16bit_uint()),
                ("32int", decoder.decode_32bit_int()),
                ("32uint", decoder.decode_32bit_uint()),
                ("16float", decoder.decode_16bit_float()),
                ("16float2", decoder.decode_16bit_float()),
                ("32float", decoder.decode_32bit_float()),
                ("32float2", decoder.decode_32bit_float()),
                ("64int", decoder.decode_64bit_int()),
                ("64uint", decoder.decode_64bit_uint()),
                ("ignore", decoder.skip_bytes(8)),
                ("64float", decoder.decode_64bit_float()),
                ("64float2", decoder.decode_64bit_float()),
            ]
        )
        print("Decoded Data")
        for name, value in iter(decoded.items()):
            print(
                "%s\t" % name,  # pylint: disable=consider-using-f-string
                hex(value) if isinstance(value, int) else value,
            )
        print("\n")

	# 关闭连接
    client.close()


if __name__ == "__main__":
    run_binary_payload_client("127.0.0.1", 503)    

相关资料

1、modbus tcp 通信协议
2、modbus tcp 通信协议2
3、pymodbus官方文档
4、pymodbus仓库

欢迎转载文章来源地址https://www.toymoban.com/news/detail-813420.html

到了这里,关于python使用pymodbus库进行modbus tcp通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 利用python进行TCP通信接收数据进行处理,使用队列来存放接收的数据

            在上面的程序中,我们创建了一个队列 data_queue 来存放接收到的数据,并使用Python的socket模块创建了一个TCP服务器套接字 server_socket 。当有客户端连接请求时,程序会创建一个新线程来处理客户端请求,并在处理函数 handle_client 中将接收到的数据放入队列中。  

    2024年02月13日
    浏览(42)
  • Modbus TCP通信协议详解

    一、Modbus TCP通信概述 MODBUS/TCP是简单的、中立厂商的用于管理和控制自动化设备的MODBUS系列通讯协议的派生产品,显而易见,它覆盖了使用TCP/IP协议的“Intranet”和“Internet”环境中MODBUS报文的用途。协议的最通用用途是为诸如PLC,I/O模块,以及连接其它简单域总线或I/O模块的

    2024年02月08日
    浏览(161)
  • Modbus TCP通信报文解析

    一、实现了读取线圈状态和写入多个线圈的功能。代码中包含了详细的注释说明,可以清晰地了解每个方法的功能和使用方式。 对于读取线圈状态的方法,使用时需要传入从站地址、起始地址和线圈数量,最后会返回一个 bool 数组,其中每个元素表示一个线圈的状态。 对于

    2024年02月15日
    浏览(51)
  • 嵌入式通信协议【Modbus】Modbus TCP的帧格式

    Client request:例: 19 B2 00 00 00 06 06 03 00 27 00 02 上面是modbus客户端发出的报文内容,为modbus tcp/ip协议格式,其前面的六个字节为头字节( header handle); 19 B2 00 00 00 06 19 B2  00 00 00 06 两个Client发出的检验信息,Sever端只是需要将这两个字节的内容copy以后再放到response的报文的相应位

    2024年02月05日
    浏览(85)
  • C# Modbus通信从入门到精通(21)——Modbus TCP协议原理

    Modbus TCP是走网口的,也可以在同一时间内有多个从站访问主站,并且通过Modbus事务处理标识来区分同一时刻的不同Modbus事务,这是区别于Modbus ASCII和Modbus RTU的地方。 Modbus客户端通常输入Modbus服务器的IP地址和端口号来建立TCP连接,然后根据从站地址来确定具体访问哪个从站

    2024年02月15日
    浏览(64)
  • LabVIEW实现Modbus-TCP通信

    Modbus协议是一种已广泛应用于当今工业控制领域的通用通讯协议,按其格式可分为Modbus-RTU、Modbus-ASCII和Modbus-TCP。其中,前两者适用于串行通信控制网络中,例如RS485、RS232等,而Modbus-TCP主要应用于基于以太网TCP/IP通信的控制网络中。通过此协议,控制器相互之间、或控制器经

    2024年02月15日
    浏览(53)
  • S7-1200 MODBUS TCP 通信多请求处理

    单独的客户机连接需要遵循的规则: 1. 每个“MB_CLIENT”连接需要使用一个不同的背景数据块; 2. 每个“MB_CLIENT”连接必须指定一个服务器 IP 地址; 3. 每个“MB_CLIENT”连接必须指定一个唯一的连接 ID; 4. 是否需要唯一的 IP 端口号取决于服务器组态; 5.连接 ID 和背景数据块组

    2024年02月10日
    浏览(46)
  • Codesys与Modbus TCP从站通信详细说明+实例代码+Modbus软件助手

    一、 说明 codesys 软件版本: 3.5.17 测试助手软件 : Modbus Poll 程序和软件下载 : 在底部 二、Codesys设置 1 新建项目 2 选择控制器类型和语言 3 右键点击【Device】选择【添加设备】添加网络驱动 4 再添加Modbus Tcp Slave Device 5 扫描网络并确定 6 扫描Ethernet网络接口 7 设置从站端口号

    2024年01月16日
    浏览(69)
  • PMAC与Modbus主站进行Modbus Tcp通讯

    在项目的PMAC Script LanguageGlobal Includes下创建一个名为00_Modbus_Para.pmh的pmh文件。 具体的参数查看手册,样例使用的是本机的回环地址。 在C LanguageBackground Programs下添加一个后台C应用程序,名为capp1。在capp1文件夹下创建一个capp1.c的source文件。 在PMAC Script LanguagePLC Programs文件夹

    2024年02月11日
    浏览(35)
  • 通过modbus tcp 和台达PLC通信测试记录

    安装台达梯形图软件 “WPLSoft” http://downloadcenter.delta-china.com.cn/DownloadCenter?v=1q=WPLsort_expr=cdatesort_dir=DESC 2.硬件连接 2.1 电脑网卡 连接PLC以太网, IP设为192.168.1.x网段,PLC默认IP为192.168.1.5. 2.2 PLC 供电24V, S/S输入公共端接GND,UP0/ZP0输出驱动电源的端口接GND / 24V 2.3 在 PLC X0输入触

    2024年02月08日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包