仪器控制-python串⼝通信实时获取数据并绘图
本⽂章是为了记录学习仪器控制的历程,虽然是⽤于实验室测样品获得数据⽽设计,但是涉及到xlwings、serial、socket、matplotlib、Qt、多线程、⼆分法查数据的应⽤,对于⾃⼰来说确实是不少挑战。
设计的思路也是基于实验测试的要求:仪器为炉⼦,样品切换控制台、以及测试仪器
1.程序运⾏后出现选择不同的测试选项,点击便开始运⾏测试
2.在升温过程中获取当前温度并与对⽐,如果差值在允许的范围内则触发测试python怎么读取串口数据
3.记录不同样品在五个不同频率点的数据,通过给样品切换控制台发送命令得到不同样品的数据
4.将得到的数据写⼊excel中,并绘制实时数据图
根据1,使⽤Qt设计mainwindow,设置两个pushButton,⽤于实现两种不同的测试
考虑到代码复⽤性,于是将连接仪器获取数据、根据数据绘制图写成两个类,获取数据⽤到serial串⼝连接炉⼦与样品控制台,仪表⽤
RS232串⼝线连接并发送命令,根据仪器的通信协议取得⾃⼰要的温度值,协议规定仪表读指令和写指令的返回值都为⼗个字节长,当前温度为前两个字节,这⾥有个⼩坑,之前⼀直⽤adline()来返回数据,发现总是会出现返回温度明显不符的情况,原来是接受的数据有长有短,于是改成读取⼗个字节长的命令。
from serial import Serial
ls.list_ports
import sys
self.sock =socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.ser=serial.Serial('COM4', 9600, timeout=1) #连接串⼝
port_list = ls.list_portsports()) #打印串⼝信息
self.inputlist = [129, 129, 82, 0, 0, 0, 83, 0] #给炉⼦发送读指令
self.binput = bytes(self.inputlist) #转换成字节形式
self.ser.write(self.binput) #发送命令
self.data=ad(10) #读取返回的结果并赋值
pv=struct.unpack('h', bytes([self.data[0], self.data[1]]))[0] #将字节数据进⾏解码
仪器使⽤GPIB(General-Purpose Interface Bus)通⽤接⼝总线-USB与电脑通信,设置局域⽹,主机发送测试功能命令,发送设置频率命令,发送获取数据命令,得到测试结果
import socket
import sys
try:
t(('192.168.1.99', 2000)) #设置局域⽹,try尝试连接
except socket.timeout:
print('连接失败')
self.sock.send(b':METER:FUNC:1 C;2 D') # 发送测试function
time.sleep(0.1)
freq_list = ['100', '1E3', '1E4', '1E5', '1E6']
for i in freq_list:
freq_setup = ':METER:FREQ '
freq_setup_b = bytes(freq_setup + i, encoding="utf-8")
self.sock.send(freq_setup_b)
time.sleep(0.1)
self.sock.send(b':METER:TRIG')
time.sleep(1.5)
data2 = v(4096)
data_str = data2.decode(encoding="utf-8")
得到数据后写⼊sheets
import xlwings as xw
self.wb = xw.Book(r'C:\Users\TZDM\Desktop\111.xlsx') #打开excel新建四个sheets self.sheet1 = self.wb.sheets.add('A1')
self.sheet2 = self.wb.sheets.add('B2', after='A1')
self.sheet3 = self.wb.sheets.add('C3', after='B2')
self.sheet4 = self.wb.sheets.add('D4', after='C3')
self.sheets_list = [self.sheet1, self.sheet2,self.sheet3,self.sheet4]
mode_list = ['A1', 'B2', 'C3', 'D4'] #样品切换通道命令为发送*A1#的ASCII for i in mode_list:
a = '*'
b = '#'
mode_i = a + i + b
mode = bytes(mode_i, encoding="utf-8")
self.ser_yp.write(mode)
t=0
m=0
for n in range(5):
self.sheets_list[m].range(row, Cp_lie[t]).value = self.Cp[t]
self.sheets_list[m].range(row, D_lie[t]).value = self.D[t]
self.sheets_list[m].range(row, 1).value = self.pv_str
self.sheets_list[m].range(row, 16).value = self.pv2_str
print('成功写⼊数据')
t = t + 1
m=m+1
⽤⼆分法将当前温度与要采取的温度点做对⽐,得到便触发上⾯测试
def dichotomy_pv(self):
num = 0
i = 0
j = p_set) - 1
<_temp() #获取当前温度的函数
while (1):
if (self.pv < (p_set[(i + j) // 2])):
j = (i + j) // 2
else:
i = (i + j) // 2
if (j - i == 1):
if ((p_set[j] - self.pv) > (self.pv - p_set[i])):
else:
break
num = num + 1
print(f'最接近 {self.pv}的下标为{sult}')
print("温度为%d" % p_sult])
当前温度与列表中温度对⽐若能到接近值,则触发测试,再次对⽐温度并写⼊数据,这边使⽤⼆分法也是为了保证如果升温速率过快错过了温度点,⾄少能下⼀个温度测试点能正常获取数据,另外if好像只能对⽐int型数据,因此将引⼊decimal定义⼀个frange函
数,math.isclose能做两个值的相近⽐较
import decimal
import math
def frange(self,x,y,jump):
while x<y:
yield float(x)
x+= decimal.Decimal(jump)
self.dichotomy_pv() # 实时温度pv⽤⼆分法查对应温度查到并返回对应温度点的索引号
print(p_sult]))
if math.isclose(self.pv, p_sult]), abs_tol=0.4): # 对⽐差值
print('OK 差值绝对值⼩于0.4 获取数据并写⼊sheet')
self.samples_data()# 获取数据并写⼊sheet⾥⾯
效果图
得到数据后开线程去绘制数据图:
self.samples_data()# 获取数据并写⼊sheet⾥⾯
th1 = threading.Thread(target=self.draw_pic())
th1.start()
对于得到数据实施绘图是花了⼀些时间去解决的,后⾯想到以运⾏得到的数据做参数,传⼊绘制的函数中,四个数据图的话引⼊matplotlib
与PyQt5新建控件,在控件中添加画布,再plot绘制图形到画布上⾯
import matplotlib
matplotlib.use('Qt5Agg')
# 使⽤ matplotlib中的FigureCanvas (在使⽤ Qt5 Backends中 FigureCanvas继承⾃QtWidgets.QWidget)
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from PyQt5 import QtCore, QtWidgets,QtGui
from PyQt5.QtWidgets import QWidget, QApplication, QGroupBox, QPushButton, QLabel, QHBoxLayout, QVBoxLayout, QGridLayout, QFormLayout, QLineEdit, import matplotlib.pyplot as plt
import sys
class my_main_window(QtWidgets.QDialog):
def __init__(self,parent=None):
# ⽗类初始化⽅法
super(my_main_window,self).__init__(parent)
# ⼏个QWidgets
self.figure = plt.figure()
self.fig_demo = f()
self.canvas1 = FigureCanvas(self.fig_demo)
#```````点击绘制``````````
self.button_plot = QtWidgets.QPushButton("绘制")
layout = QtWidgets.QGridLayout()
layout.addWidget(self.canvas1, 1, 0)
layout.addWidget(self.button_plot)
self.setLayout(layout)
这边是绘制图形函数:
def plot_data(self,Cpp,pvv):
global a_fig
global b_fig
global c_fig
global d_fig
a_fig = plt.subplot(2, 2, 1) #将plot的图排成两列两⾏四个图
b_fig = plt.subplot(2, 2, 2)
c_fig = plt.subplot(2, 2, 3)
d_fig = plt.subplot(2, 2, 4)
Cpp1_flo=float(Cpp[0]) #通过计算将数据处理成最后要绘制的数据 print(Cpp1_flo)
cal_Cpp1=(144*pow(10,10)*Cpp1_flo)
jd_a=int(cal_Cpp1)
self.Cpp_1.append(jd_a) #添加纵坐标的值
self.pv_list.append(pvv) #添加横坐标的值
a_fig.plot(self.pv_list, self.Cpp_1,"bo") #绘制点图
b_fig.plot(self.pv_list, self.Cpp_2,"bo")
c_fig.plot(self.pv_list, self.Cpp_3, "bo")
d_fig.plot(self.pv_list, self.Cpp_4, "bo")
plt.pause(10) #暂停⼗秒以更新图像
plt.ioff() #确保图形不会出现闪退现象
在数据获得类中初始化:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论