python实现modbus协议 03读取多个子站数据——多线程版本
- 提前准备 modbus_slave 这个软件,用于提供数据。
- 安装必要的第三方包
pip install modbus_tk
pip install serial
协议包加串口包
这版不带crc校验,如需验crc版,请留言。 - 先证明一下实现过程
端口配置
实际获取
上代码
import serial
from modbus_tk import modbus_rtu
from modbus_tk import defines as cst
import time
import threading
class F():
def __init__(self, list_id):
self.port = 'com6'
self.flags = 0
self.my_serial_flag= [100 if i == 0 else 0 for i in range(len(list_id)+1)]
self.my_serial = None
self.my_serial = (self.my_serial if self.my_serial else self.my_func_serial())
def get_datas(self, slave_id, start_addr, date_len):
try:
holding_date = self.master.execute(slave_id, cst.READ_HOLDING_REGISTERS, start_addr, date_len)
holding_data125 = list()
for i in range(len(holding_date)):
holding_data125.append('%04x' % (holding_date)[i]) # append()在Tmp1列表末尾添加新的对象
all_holding_data = '0103' + '%02x' % (date_len * 2) + ''.join(holding_data125)
# print('为线程显示', all_holding_data)
self.my_serial_flag[slave_id] = 0
return str(all_holding_data)
except Exception as e:
print('单个子站引发','不重连端口',slave_id)
if self.my_serial_flag[slave_id] >= 10:
# print(111)
pass
else:
# print(222)
self.my_serial_flag[slave_id] += 1
# print(221)
if all(v > 0 for v in self.my_serial_flag):
self.flags = 1
if self.flags: # 如果flags被标记为1才去重新获取连接
self.func(slave_id)
return None
def funb(self, slave_id):
'''
这个相当于与服务器的连接,这个可定义的
:param slave_id:
:return:
'''
while 1:
try:
time.sleep(2)
da = self.get_datas(slave_id, 0, 64)
print(da)
#return da
except Exception as e:
print(self.my_serial_flag)
def my_func_serial(self):
while 1:
try:
self.my_serial = serial.Serial(port=self.port,
baudrate='38400',
bytesize=8,
parity='N',
stopbits=1,
xonxoff=0)
self.master = modbus_rtu.RtuMaster(self.my_serial)
self.master.set_timeout(1)
return self.my_serial
except Exception as e:
print(e, '第一次端口不能成功建立', self.my_serial_flag)
time.sleep(2)
if self.my_serial:
self.my_serial.close()
def func(self, slave_id):
while 1:
try:
time.sleep(1)
if self.flags:
self.my_serial = serial.Serial(port=self.port,
baudrate='38400',
bytesize=8,
parity='N',
stopbits=1,
xonxoff=0)
self.my_serial_flag[slave_id] = 1
self.master = modbus_rtu.RtuMaster(self.my_serial)
self.master.set_timeout(1)
self.flags = 0
return self.my_serial
else:
pass
except Exception as e:
print(e, '引发整个端口重置', self.my_serial_flag)
self.my_serial_flag[slave_id] += 1
time.sleep(2)
if self.my_serial:
self.my_serial.close()
def add_thread(func, *args):
# 用于创建线程
return threading.Thread(target=func, args=args)
def main(ids):
threads_list = []
f = F(ids)
for i, j in enumerate(ids):
i += 1
threads_list.append(add_thread(f.funb, i))
for i in threads_list:
# print('执行线程')
i.start()
if __name__ == '__main__':
list_id = ['6101','6102','6103','5555'] #
main(list_id)
注意项;就是要端口要统一,我端口只提供子站123,即便我向端口要子站4的数据,程序也可照常执行,当子站4有数据时,也可获取子站4数据。