python modbus 实现RTU 通信

python modbus 实现RTU 通信pythonmodbus_tk实现RTU通信下载对应pip由于没有硬件设备,采用软件模拟,软件下载地址为安装vspd.exe用于模拟串口在没有安装前可以看到我们电脑没有对应的串口安装好通过vspd添加串口下载安装好开始连接,第一次连接需要激活模拟创建一个HOLDING_REGISTERS点击左上角file-new依次创建以下模拟器点击Display-communication开始显示协………

下载对应pip

pip install modbus_tk

在通过rtu通信的时候我们需要下载modbusslave和modbuspol和vspd.exe

安装vspd.exe 用于模拟串口

在没有安装前可以看到我们电脑没有对应的串口

在这里插入图片描述

安装好通过vspd添加串口

在这里插入图片描述
可以看见电脑上多了两个端口
在这里插入图片描述

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

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

模拟创建一个HOLDING_REGISTERS

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

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

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

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

在这里插入图片描述

编写python代码

# -*- coding: utf_8 -*-


import serial
import modbus_tk
import modbus_tk.defines as cst
from modbus_tk import modbus_rtu


def mod(PORT="com2"):
    red = []
    alarm = ""
    try:
        # 设定串口为从站
        master = modbus_rtu.RtuMaster(serial.Serial(port=PORT,
                                                    baudrate=9600, bytesize=8, parity='N', stopbits=1))
        master.set_timeout(5.0)
        master.set_verbose(True)

        # 读保持寄存器
        red = master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 9)  # 这里可以修改需要读取的功能码
        print(red)
        alarm = "正常"
        return list(red), alarm

    except Exception as exc:
        print(str(exc))
        alarm = (str(exc))

    return red, alarm  ##如果异常就返回[],故障信息


if __name__ == "__main__":
    mod()

运行结果

在这里插入图片描述

modbus slave监听到的数据如下

在这里插入图片描述

000080-Rx:01 03 00 00 00 09 85 CC
000081-Tx:01 03 12 00 14 00 15 00 16 00 17 00 00 00 00 00 00 00 00 00 00 11 6B

对数据进行分析

000080-Rx:01 03 00 00 00 09 85 CC
000081-Tx:01 03 12 00 14 00 15 00 16 00 17 00 00 00 00 00 00 00 00 00 00 11 6B

详细的报文分析见

https://blog.csdn.net/ouyangxin95/article/details/78169380/
https://blog.csdn.net/qq_26093511/article/details/79251320

读寄存器

请求

01 从机地址
03 功能码
00 00 起始寄存器
00 09 读取寄存器个数
85 cc  CRC校验

响应

01 从机地址
03 功能码
12 返回数据个数,16进制12表示18, 每两位16进制表示一个数,共有9个数
00 14 表示20
00 15 表示21
.....
这些数据和python程序返回的一样
11 6B CRC校验

读线圈的和输入状态的分析一样

000660-Rx:02 01 00 00 00 02 BD F8
000661-Tx:02 01 01 03 11 CD

请求

02 从机地址
01 功能码
00 00 起始寄存器
00 02 读取寄存器个数
BD F8 CRC校验

响应

02 从机地址
01 功能码
01 返回数据个数
03 返回数据  03 起始代表读取了两个寄存器值都为1 显示为11,
     (3F 02 为数据 代表1111 1100 0100 0000 每四位逆序组成一位16进制,
     每两位16进制组成一组数据,组成的数据线先组成的16进制在后面,
     例如1111 1100的逆序是1111(F) 0011(3)  最后组成数据为3F)

读寄存器里面小数数据

000004-Rx:01 03 00 00 00 04 44 09
000005-Tx:01 03 08 38 86 40 4E C6 A8 40 91 5B 67

请求

01 从机地址
03 功能码
00 00 起始寄存器
00 04 读取寄存器个数
44 09  CRC校验

响应

01 从机地址
03 功能码
08 返回数据个数
38 86 40 4E 第一个小数值因为一个浮点数占4个字节,而一个寄存器只能保存两个字节的数据,,因此使用两个寄存器保存一位小数
C6 A8 40 91 第二个小数值
5B 67 CRC校验

对返回数据进行分析

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

原寄存器值为

在这里插入图片描述

38 86 40 4E

3886

0011100010000110

404E

0100000001001110

总数据(小端(404E 3886))

0 10000000 10011100011100010000110
0 128 1.10011100011100010000110

128-127 = 1

右移一位

最终数据,精度问题会有缺失

  11.0011100011100010000110
  3.2221999168395996

C6 A8 40 91

C6A8
1100011010101000
4091
0100000010010001
总数据(小端 4091 C6A8)
0 10000001 00100011100011010101000
0 129 1.00100011100011010101000
129-127 = 2 右移两位
100.100011100011010101000
4.555500030517578

这有个能直接转换,不用你分析的代码

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((14470, 16462)))
    print(ReadFloat(( 50856, 16529)))
    print(WriteFloat(3.2222))
    print(ReadDint((1734,6970)))
    print(WriteDint(456787654))


运行结果
可以看到与我们分析的一致
在这里插入图片描述

今天的文章python modbus 实现RTU 通信分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/29555.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注