pip install modbus_tk
https://blog.csdn.net/qq_40423339/article/details/96284979
链接:https://pan.baidu.com/s/10C_3VL04Ycb5C_-YfrPj_w
提取码:jhuv
复制这段内容后打开百度网盘手机App,操作更方便哦
在通过rtu通信的时候我们需要下载modbusslave和modbuspol和vspd.exe
打开slave,点击connection-connect,配置好参数选择OK,开始监听
简单修改设备id为1,function为03 Holding Register,点击ok
# -*- 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()
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处理器上,低字节在前面,有的平台是相反的。
3886
0011100010000110
404E
0100000001001110
总数据(小端(404E 3886))
0 10000000 10011100011100010000110
0 128 1.10011100011100010000110
128-127 = 1
右移一位
最终数据,精度问题会有缺失
11.0011100011100010000110
3.2221999168395996
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))