python modbus 实现TCP 通信

2 篇文章 1 订阅
1 篇文章 0 订阅

下载对应pip

pip install modbus_tk

实现RTU通信

https://blog.csdn.net/qq_40423339/article/details/96289321

由于没有硬件设备,采用软件模拟,软件下载地址为

链接:https://pan.baidu.com/s/10C_3VL04Ycb5C_-YfrPj_w 
提取码:jhuv 
复制这段内容后打开百度网盘手机App,操作更方便哦

在通过TCP通信的时候我们需要下载modbusslave和modbuspol,但modbusslave有一个缺陷,就是最多只能连接100个寄存器或者线圈,我们可以通过使用nodbus-TCP client Tester来模拟更多的线圈或者寄存器,他最多支持65536个线圈或者寄存器。

下载安装好开始连接,第一次连接需要激活

打开slave,点击connection-connect,配置好参数选择OK,开始监听
在这里插入图片描述

模拟创建一个HOLDING_REGISTERS

在这里插入图片描述
简单修改设备id为1,function为03 Holding Register,点击ok

点击左上角file-new依次创建 以下 模拟器

在这里插入图片描述在这里插入图片描述在这里插入图片描述

点击Display-communication开始显示协议传输信息

在这里插入图片描述

编写python代码


import modbus_tk
import modbus_tk.defines as cst
import modbus_tk.modbus_tcp as modbus_tcp
logger = modbus_tk.utils.create_logger("console")
if __name__ == "__main__":
    try:
        # 连接MODBUS TCP从机
        master = modbus_tcp.TcpMaster(host="192.168.1.66")
        master.set_timeout(5.0)
        logger.info("connected")
        # 读保持寄存器
        demo1 = master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 9)
        print(demo1)
        # 读输入寄存器
        logger.info(master.execute(3, cst.READ_INPUT_REGISTERS, 0, 9, output_value=1))
        # 读线圈寄存器
        logger.info(master.execute(2, cst.READ_COILS, 0, 8))
        logger.info(master.execute(2, cst.WRITE_SINGLE_COIL, 1, output_value=2))
        # 读离散输入寄存器
        logger.info(master.execute(4, cst.READ_DISCRETE_INPUTS, 0, 8))
        # 单个读写寄存器操作
        # 写寄存器地址为0的保持寄存器
        logger.info(master.execute(1, cst.WRITE_SINGLE_REGISTER, 0, output_value=20))
        logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 8))
        # 写寄存器地址为0的线圈寄存器,写入内容为0(位操作)
        logger.info(master.execute(2, cst.WRITE_SINGLE_COIL, 0, output_value=2))
        logger.info(master.execute(2, cst.READ_COILS, 0, 1))
        # # 多个寄存器读写操作
        # # 写寄存器起始地址为0的保持寄存器,操作寄存器个数为4
        logger.info(master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 0, output_value=[20,21,22,23]))
        logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 4))
        # # 写寄存器起始地址为0的线圈寄存器
        logger.info(master.execute(2, cst.WRITE_MULTIPLE_COILS, 0, output_value=[0,0,0,1]))
        logger.info(master.execute(2, cst.READ_COILS, 0, 4))
    except modbus_tk.modbus.ModbusError as e:
        logger.error("%s- Code=%d" % (e, e.get_exception_code()))

我对modbus_tk.defines中文件进行简单翻译

import modbus_tk.defines

#modbus exception codes  异常代码
# 代码功能不合法
ILLEGAL_FUNCTION = 1
# 数据地址不合法
ILLEGAL_DATA_ADDRESS = 2
# 数据值不合法
ILLEGAL_DATA_VALUE = 3
# slave设备失败
SLAVE_DEVICE_FAILURE = 4
# 命令已收到
COMMAND_ACKNOWLEDGE = 5
# slave设备忙
SLAVE_DEVICE_BUSY = 6
# 内存奇偶校验差
MEMORY_PARITY_ERROR = 8

# supported modbus functions 功能代码
# 读线圈
READ_COILS = 1
# 离散读输入
READ_DISCRETE_INPUTS = 2
# 读保持寄存器
READ_HOLDING_REGISTERS = 3
# 读输入寄存器
READ_INPUT_REGISTERS = 4
# 写单一线圈
WRITE_SINGLE_COIL = 5
# 写单一寄存器
WRITE_SINGLE_REGISTER = 6
# *读例外状态
READ_EXCEPTION_STATUS = 7
DIAGNOSTIC = 8
# *报告slave的id
REPORT_SLAVE_ID = 17
# 写多个线圈
WRITE_MULTIPLE_COILS = 15
# 写多寄存器
WRITE_MULTIPLE_REGISTERS = 16
# *读写多个寄存器
READ_WRITE_MULTIPLE_REGISTERS = 23
# *设备信息
DEVICE_INFO = 43

# supported block types 支持的块类型
# 线圈
COILS = 1
# 离散输入
DISCRETE_INPUTS = 2
# 保持寄存器
HOLDING_REGISTERS = 3
# 模拟量输入
ANALOG_INPUTS = 4

程序输出结果如下

在这里插入图片描述

modbus slave监听到数据如下

在这里插入图片描述

000054-Rx:00 01 00 00 00 06 01 03 00 00 00 09 
000055-Tx:00 01 00 00 00 15 01 03 12 00 14 00 15 00 16 00 17 00 00 00 00 00 00 00 00 00 00 
000056-Rx:00 02 00 00 00 06 03 04 00 00 00 09 
000057-Tx:00 02 00 00 00 15 03 04 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
000058-Rx:00 03 00 00 00 06 02 01 00 00 00 08 
000059-Tx:00 03 00 00 00 04 02 01 01 08 
000060-Rx:00 04 00 00 00 06 02 05 00 01 FF 00 
000061-Tx:00 04 00 00 00 06 02 05 00 01 FF 00 
000062-Rx:00 05 00 00 00 06 04 02 00 00 00 08 
000063-Tx:00 05 00 00 00 04 04 02 01 00 
000064-Rx:00 06 00 00 00 06 01 06 00 00 00 14 
000065-Tx:00 06 00 00 00 06 01 06 00 00 00 14 
000066-Rx:00 07 00 00 00 06 01 03 00 00 00 08 
000067-Tx:00 07 00 00 00 13 01 03 10 00 14 00 15 00 16 00 17 00 00 00 00 00 00 00 00 
000068-Rx:00 08 00 00 00 06 02 05 00 00 FF 00 
000069-Tx:00 08 00 00 00 06 02 05 00 00 FF 00 
000070-Rx:00 09 00 00 00 06 02 01 00 00 00 01 
000071-Tx:00 09 00 00 00 04 02 01 01 01 
000072-Rx:00 0A 00 00 00 0F 01 10 00 00 00 04 08 00 14 00 15 00 16 00 17 
000073-Tx:00 0A 00 00 00 06 01 10 00 00 00 04 
000074-Rx:00 0B 00 00 00 06 01 03 00 00 00 04 
000075-Tx:00 0B 00 00 00 0B 01 03 08 00 14 00 15 00 16 00 17 
000076-Rx:00 0C 00 00 00 08 02 0F 00 00 00 04 01 08 
000077-Tx:00 0C 00 00 00 06 02 0F 00 00 00 04 
000078-Rx:00 0D 00 00 00 06 02 01 00 00 00 04 
000079-Tx:00 0D 00 00 00 04 02 01 01 08 

modbus tcp数据格式

modbus tcp数据报文结构

请求:00 00 00 00 00 06 09 03 00 00 00 01

响应:00 00 00 00 00 05 09 03 02 12 34



一次modbus tcp读取保持寄存器的通信分析(省略了ip/tcp头):从左向右分析该数据报文:

请求:

00 00为此次通信事务处理标识符,一般每次通信之后将被要求加1以区别不同的通信数据报文;

00 00表示协议标识符,00 00为modbus协议;

00 06为数据长度,用来指示接下来数据的长度,单位字节;

09为设备地址,用以标识连接在串行线或者网络上的远程服务端的地址。以上七个字节也被称为modbus报文头;

03为功能码,此时代码03为读取保持寄存器数据;

00 00为起始地址;

00 01为寄存器数量,(word数量)。

响应:

00 00为此次通信事务处理标识符,应答报文要求与先前对应的请求保持一致;

00 00为协议标识符,与先前对应的请求保持一致;

00 05为数据长度,用来指示接下来数据的长度,单位字节;

09为设备地址,应答报文要求与先前对应的请求保持一致;

03为功能码,正常情况下应答报文要求与先前对应的请求保持一致,如果出错则返回80h+先前的功能码;

02指示接下来数据的字节长度;

12 34为被读取的保持寄存器中的数据值,即要求被读取的地址为00 00的保持寄存器中的数值为1234h。

对寄存器的数据进行分析

000054-Rx:00 01 00 00 00 06 01 03 00 00 00 09 
000055-Tx:00 01 00 00 00 15 01 03 12 00 14 00 15 00 16 00 17 00 00 00 00 00 00 00 00 00 00

请求

00 01 为此次通信的标识符
00 00 表示协议 ,其中 00 00 表示modbus协议
00 06 表示数据的长度
01 表示为1号设备地址
03 表示功能码 可以和上面的对应
00 00 为起始地址
00 09 为寄存器数量,默认10个也可以自己修改

响应

00 01 为此次通信的标识符
00 00 表示协议 ,其中 00 00 表示modbus协议
00 15 表示数据的长度,16进制中的表示21,后面数据长度为21
01 表示为1号设备地址
03 表示功能码 可以和上面的对应
12 表示接下来数据长度,16进制12表示18 ,后i面每两位代表一位数
00 14 表示20
00 15 表示21
.....
这些数据和python程序返回的一样

对线圈数据进行分析,输入状态的和线圈的分析方法一样:

00 01 00 00 00 06 02 01 00 00 00 0A
00 01 00 00 00 05 02 01 02 3F 02

请求:

00 01为此次通信事务处理标识符,应答报文要求与先前对应的请求保持一致;
00 00为协议标识符,与先前对应的请求保持一致;
00 06为数据长度,用来指示接下来数据的长度,单位字节;
02为设备地址,用以标识连接在串行线或者网络上的远程服务端的地址。以上七个字节也被称为modbus报文头;
01为功能码,此时代码03为读取保持寄存器数据;
00 00为起始地址;
00 0A为线圈个数

响应:

00 01为此次通信事务处理标识符,应答报文要求与先前对应的请求保持一致;
00 00为协议标识符,与先前对应的请求保持一致;
00 05为数据长度,用来指示接下来数据的长度,单位字节;
02为设备地址,用以标识连接在串行线或者网络上的远程服务端的地址。以上七个字节也被称为modbus报文头;
01为功能码,此时代码03为读取保持寄存器数据;
02为数据长度
3F 02 为数据 代表1111 1100 0100 0000 每四位逆序组成一位16进制,
		每两位16进制组成一组数据,组成的数据线先组成的16进制在后面,
		例如1111 1100的逆序是1111(F) 0011(3)  最后组成数据为3F

线圈实际值为下图所示
在这里插入图片描述

对寄存器读取浮点数数据进行分析

寄存器的值

在这里插入图片描述

对返回数据进行分析

000002-Rx:00 01 00 00 00 06 01 03 00 00 00 02
000003-Tx:00 01 00 00 00 07 01 03 04 26 D0 3F 9B

请求

00 01 为此次通信的标识符
00 00 表示协议 ,其中 00 00 表示modbus协议
00 06 表示数据的长度
01 表示为1号设备地址
03 表示功能码 可以和上面的对应
00 00 为起始地址
00 09 为寄存器数量,默认10个也可以自己修改,一个浮点数占四个字节,而一个寄存器只能存储两个字节的数据,所以需要2个寄存器来保存

响应

 00 01 为此次通信的标识符
00 00 表示协议 ,其中 00 00 表示modbus协议
00 15 表示数据的长度,16进制中的表示21,后面数据长度为21
01 表示为1号设备地址
03 表示功能码 可以和上面的对应
04 表示接下来数据长度,16进制12表示18 ,后i面每两位代表一位数
26 D0 3F 9B  四位表示返回的浮点数数据

对26 d0 3f 9b 进行解析

26d0 = 9936
3f9b = 16283

把对26 d0 3f 9b 转换成二进制

26d0= 0010011011010000(高位)
3f9b = 0011111110011011 (低位)
在intel处理器上,低字节在前面,有的平台是相反的。重组数据为
00111111100110110010011011010000
内容 SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM
这里
S 代表符号位,1是负,0是正
E 偏移127的幂,二进制阶码=(EEEEEEEE)-127。
M 24位的尾数保存在23位中,只存储23位,最高位固定为1。此方法用最较少的位数实现了
对于该数据
0 01111111 00110110010011011010000
(1)0表示正

该数为正数

(2)01111111 = 127

  127-127 = 0 向右偏移0位

(3)需要在00110110010011011010000前面加1.

数据为1.00110110010011011010000

(4)应为偏移量为0

最终数据为1.00110110010011011010000

(5)准换成10进制取小数点后6位的
在这里插入图片描述

我在网上也找了个python脚本转化

import struct

def ReadFloat(*args,reverse=False):
    for n,m in args:
        n,m = '%04x'%n,'%04x'%m
    if reverse:
        v = n + m
    else:
        v = m + n
    y_bytes = bytes.fromhex(v)
    y = struct.unpack('!f',y_bytes)[0]
    y = round(y,6)
    return y

def WriteFloat(value,reverse=False):
    y_bytes = struct.pack('!f',value)
    # y_hex = bytes.hex(y_bytes)
    y_hex = ''.join(['%02x' % i for i in y_bytes])
    n,m = y_hex[:-4],y_hex[-4:]
    n,m = int(n,16),int(m,16)
    if reverse:
        v = [n,m]
    else:
        v = [m,n]
    return v

def ReadDint(*args,reverse=False):
    for n,m in args:
        n,m = '%04x'%n,'%04x'%m
    if reverse:
        v = n + m
    else:
        v = m + n
    y_bytes = bytes.fromhex(v)
    y = struct.unpack('!i',y_bytes)[0]
    return y

def WriteDint(value,reverse=False):
    y_bytes = struct.pack('!i',value)
    # y_hex = bytes.hex(y_bytes)
    y_hex = ''.join(['%02x' % i for i in y_bytes])
    n,m = y_hex[:-4],y_hex[-4:]
    n,m = int(n,16),int(m,16)
    if reverse:
        v = [n,m]
    else:
        v = [m,n]
    return v

if __name__ == "__main__":
    print(ReadFloat((9936, 16283)))
    print(WriteFloat(3.16))
    print(ReadDint((1734,6970)))
    print(WriteDint(456787654))


运行结果
在这里插入图片描述

  • 45
    点赞
  • 291
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
### 回答1: 我不太清楚Python实现Modbus TCP的细节,但是可以提供一些指导:可以使用Python的pyModbus库来实现Modbus TCP,它支持主机和从机模式,还支持Modbus RTU和Modbus ASCII协议。 ### 回答2: Python可以使用第三方库来实现Modbus TCP通信。其中一个常用的库是pyModbus库,该库提供了一套丰富的API来构建Modbus通信。 首先,我们需要安装pyModbus库。可以使用pip来安装,命令如下: ``` pip install pymodbus ``` 然后,我们可以使用以下代码来实现Modbus TCP通信: ```python from pymodbus.client.sync import ModbusTcpClient # 连接到Modbus服务器 client = ModbusTcpClient('127.0.0.1', port=502) # 连接后需要调用connect方法 client.connect() # 读取保持寄存器的值 result = client.read_holding_registers(address=0, count=10, unit=1) if result.isError(): print('读取失败') else: print(result.registers) # 入保持寄存器的值 result = client.write_register(address=0, value=1234, unit=1) if result.isError(): print('入失败') else: print('入成功') # 断开连接 client.close() ``` 上面的代码首先创建一个ModbusTcpClient对象,并连接到Modbus服务器。然后可以使用API来读取或入保持寄存器的值。最后,使用close方法断开连接。 这样,我们就可以使用Python实现Modbus TCP通信了。需要注意的是,具体的地址和寄存器的数量要根据实际情况进行调整。 ### 回答3: Python可以通过使用第三方库来实现Modbus TCP通信。其中一个常用的库是`pymodbus`。下面是一个简单的示例,用于演示如何使用Python实现Modbus TCP通信: 首先,你需要确保你已经安装了`pymodbus`库。可以使用以下命令来安装: ```python pip install pymodbus ``` 接下来,创建一个Python脚本,并导入所需的模块: ```python from pymodbus.client.sync import ModbusTcpClient # 创建Modbus TCP客户端 client = ModbusTcpClient('localhost', port=502) # 连接到Modbus TCP服务器 client.connect() # 读取Modbus寄存器的值 result = client.read_holding_registers(address=0, count=1, unit=1) # 检查结果并打印值 if not result.isError(): print("Modbus TCP通信成功!") print("寄存器值:", result.registers[0]) else: print("Modbus TCP通信失败!") # 断开与Modbus TCP服务器的连接 client.close() ``` 在上面的示例中,我们首先创建了一个Modbus TCP客户端,然后连接到Modbus TCP服务器。然后,我们使用`read_holding_registers`函数从寄存器中读取一个值,并检查返回结果是否有错误。最后,我们关闭与Modbus TCP服务器的连接。 请注意,上述示例适用于Modbus TCP通信中的读操作。如果您需要进行操作或其他类型的操作,请参考`pymodbus`库的文档以了解更多详细信息。 希望这个简单的示例能帮助你理解如何使用Python实现Modbus TCP通信

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值