python modbus 实现TCP 通信

python modbus 实现TCP 通信

  • 下载对应pip
  • 实现RTU通信
  • 由于没有硬件设备,采用软件模拟,软件下载地址为
    • 下载安装好开始连接,第一次连接需要激活
    • 模拟创建一个HOLDING_REGISTERS
    • 点击左上角file-new依次创建 以下 模拟器
    • 点击Display-communication开始显示协议传输信息
  • 编写python代码
    • 我对modbus_tk.defines中文件进行简单翻译
    • 程序输出结果如下
    • modbus slave监听到数据如下
    • modbus tcp数据格式
    • 对寄存器的数据进行分析
    • 对线圈数据进行分析,输入状态的和线圈的分析方法一样:
    • 对寄存器读取浮点数数据进行分析
      • 寄存器的值
      • 对返回数据进行分析
      • 对26 d0 3f 9b 进行解析
      • 把对26 d0 3f 9b 转换成二进制
      • 我在网上也找了个python脚本转化

下载对应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,开始监听
python modbus 实现TCP 通信_第1张图片

模拟创建一个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

程序输出结果如下

python modbus 实现TCP 通信_第2张图片

modbus slave监听到数据如下

python modbus 实现TCP 通信_第3张图片

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

线圈实际值为下图所示
python modbus 实现TCP 通信_第4张图片

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

寄存器的值

python modbus 实现TCP 通信_第5张图片

对返回数据进行分析

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 modbus 实现TCP 通信_第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))


运行结果
python modbus 实现TCP 通信_第7张图片

你可能感兴趣的:(python,modbus,tcp)