python modbus 实现RTU 通信

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

下载对应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))


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

  • 69
    点赞
  • 390
    收藏
    觉得还不错? 一键收藏
  • 22
    评论
在阿里云的Elasticsearch中,可以使用以下步骤创建索引: 1. 首先,您需要登录到阿里云控制台并进入Elasticsearch服务页面。 2. 在Elasticsearch服务页面上,选择您想要创建索引的集群,并点击集群名称进入集群详情页面。 3. 在集群详情页面上,选择“索引管理”选项卡,并点击“创建索引”按钮。 4. 在创建索引页面上,填写索引的基本信息,例如索引名称、分片数和副本数。分片数和副本数决定了数据的存储和复制方式,您可以根据需求进行设置。 5. 接下来,您可以选择添加索引映射来定义索引中字段的类型和属性。索引映射可以帮助您更好地搜索和分析数据。 6. 如果需要,您还可以为索引添加别名。索引别名是指向一个或多个索引的指针,可以用于简化对索引的访问。 7. 最后,点击“确认创建”按钮,阿里云将开始创建您的索引。请注意,创建索引可能需要一些时间,具体取决于您的数据量和集群性能。 通过以上步骤,您可以在阿里云的Elasticsearch中成功创建索引。请确保在创建索引时仔细设置索引映射和别名,以便更好地管理和使用您的数据。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [ElasticSearch 索引创建](https://blog.csdn.net/weishuai90/article/details/129679518)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值