项目要求
项目上提出自动化测试需求,要求能够对板级信号使用示波器等仪器做自动化测量
实现方案
使用PyVISA 方案实现。
VISA (Virtual Instrument Software Architecture) 是一个用于访问测量仪器和控制计算机之间的接口标准,由美国国家仪器公司(National Instruments)推出,用于实现仪器之间的通信和控制。VISA提供了一组标准API函数,可以实现多种通信协议和连接方式的仪器控制。VISA相比于VXI11更加灵活,支持多种接口(底层协议),比如GPIB,RS232,USB, VXIBus等,对于仪器控制有更强大的功能。
Pyvisa是一个基于Python语言开发的访问VISA资源的工具包。通过调用VISA标准API函数来实现与仪器的通信和控制。Pyvisa提供了一组Python的API函数,可以方便地访问VISA库中的函数和方法,从而实现与仪器的数据读取、写入、控制等操作。Pyvisa相比于LabVIEW,Pyvisa是一种跨平台的软件,可以在Linux,Windows和Mac OS上运行,且其拥有更灵活的用户界面,可以自行定制。
如果该脚本运行在服务器上,建议使用Pycharm Professional 或者VSCode + Remote-SSH 插件进行开发,即本地开发,远程部署或调试。
本例使用SCPI命令访问示波器的VISA库,SCPI命令的格式见示波器软件编程手册
脚本实现功能
(1)连接示波器
注意:电脑并没有使用NI-VISA后台,而是使用纯python代码实现的Pyvisa-py, 因此需要提前安装下 pip install -U pyvisa-py
(2)简单设置示波器参数,包括channal 选择,横轴窗口设置,纵轴电压窗口设置,Trigger触发方式选择
(3)波形数据以csv 和图片格式保存到本地
(4)保存示波器的截图到本地
脚本与注释
import timeimport pyvisa as visaimport numpy as npimport matplotlib.pyplot as pltimport pandas as pdfrom datetime import datetimefrom pyvisa.errors import VisaIOErrorfrom PIL import Image# rm = visa.ResourceManager('@py')# rm.list_resources()# Tek = rm.open_resource('TCPIPO::10.163.xxx.xxx::INSTR')# Tek.timeout=10000# print(Tek.query('*IDN?'))# self.inst.write('*RST')# self.inst.write('AUTOSET EXECUTE')class Tektronix_DPO: def __init__(self): self.rm = visa.ResourceManager('@py') self.rm.list_resources() self.inst = self.rm.open_resource('TCPIPO::10.163.xxx.xxx::INSTR') self.inst.timeout=10000 print(self.inst.query('*IDN?')) self.inst.write('CLEAR') self.inst.write('ACQuire:MODe?') self.inst.write('ACQUIRE:STOPAFTER RUNSTOP') self.inst.write('ACQuire:STATE RUN') self.inst.write('autoset EXECUTE') # autoset def set_HORIZONTAL(self, POSITION, SCALE): #horizontal settings self.inst.write('HORIZONTAL:POSITION %s'%POSITION) #position means trigger point on the screen /% self.inst.write('HORIZONTAL:SCALE %se-6'%SCALE) #scale means step /us def open_ch(self,ch): # open channal self.inst.write('DISplay:GLObal:CH%s:STATE ON'%ch) def close_ch(self,ch): # close channal self.inst.write('DISplay:GLObal:CH%s:STATE OFF'%ch) def vertical_ch(self,ch,scale,position): #channal settings, self.inst.write('CH%s:BANDWIDTH FULl'%ch) # at its maximum bandwidth self.inst.write('CH%s:SCAle %sE-3'%(ch,scale)) #channal scale/mv self.inst.write('CH%s:POSition %s'%(ch,position)) #channal divisions above the center graticule self.inst.write('CH%s:COUPLING DC'%ch) # DC coupling self.inst.write('CH%s:TERMINATION 10.0E+5'%ch) #channal input resistence is 1MΩ def trigger_set(self,ch,level): #trigger settings self.inst.write('TRIGGER:A:EDGE:COUPLING DC') # DC trigger coupling with input signal to the trigger circuitry self.inst.write('TRIGGER:A:EDGE:SOURCE CH%s'%ch) self.inst.write('TRIGGER:A:EDGE:SLOPE RISE') #triggers on the rising edge of the signal self.inst.write('TRIGGER:A:LEVEL:CH%s %s'%(ch,level)) # level specifies channal trigger level for seach 1, /V def begin_trigger(self): #start once trigger action self.inst.write('acquire:state 0') # stop self.inst.write('acquire:stopafter SEQUENCE') # single self.inst.write('acquire:state 1') # run self.inst.query('*opc?') # sync def data_caul(self,ch): #calculate the channal value self.inst.write("HEADER 0") self.inst.write('DATA:SOURCE CH%s'%ch) self.inst.write("DAT:ENC SRI") # Signed Binary Format, LSB order self.inst.write("DAT:WIDTH 1") self.inst.write("DAT:START 1") recordLength = int(self.inst.query('horizontal:recordlength?')) self.inst.write("DAT:STOP {0}".format(recordLength)) # Set data stop to match points available # Fetch horizontal scaling factors xinc = float(self.inst.query("WFMO:XINCR?")) xzero = float(self.inst.query("WFMO:XZERO?")) pt_off = int(self.inst.query("WFMO:PT_OFF?")) # Fetch vertical scaling factors ymult = float(self.inst.query("WFMO:YMULT?")) yzero = float(self.inst.query("WFMO:YZERO?")) yoff = float(self.inst.query("WFMO:YOFF?")) # Fetch waveform data and save as csv file rawData = self.inst.query_binary_values('curve?', datatype='b', container=np.array) dataLen = len(rawData) t0 = (-pt_off * xinc) + xzerowith open('horizonal_vector.csv',mode='w') as file: for i in range(0,dataLen): xvalues = t0 + xinc * i # Create timestamp for the data point file.write(str(xvalues)) file.write(",") yvalues= float(rawData[i] - yoff) * ymult + yzero # Convert raw ADC value into a floating point value file.write(str(yvalues)) file.write("\n") # plotting the measurement figure data = pd.read_csv("horizonal_vector.csv") data_x = data.iloc[:,0] data_y = data.iloc[:,1] plt.plot(data_x, data_y) plt.title('channel 1') # plot label plt.xlabel('time (seconds)') # x label plt.ylabel('voltage (volts)') # y label print("look for plot window...") plt.savefig('test.png') #save test picture plt.show() def close(self): self.inst.close() self.rm.close() def get_screen(self): self.inst.write("HARDCopy:PORT FILE;") self.inst.write("EXPort:FORMat PNG") self.inst.write("HARDCopy:FILEName \"C:\\est_Temp\\Temp.png\"") self.inst.write("HARDCopy STARt") self.inst.write("FILESystem:READFile \"C:\\Low_Speed_Test_Temp\\Temp.png\"") imgData = self.inst.read_raw() dt = datetime.now() fileName = dt.strftime("DPO70000_%Y%m%d_%H%M%S.png") # Generate a filename with date and time file = open(fileName, "wb") file.write(imgData) file.close() self.inst.write('FILESystem:DELEte \"C:\\Test_Temp\\Temp.png\"') # Delete image file from instrument's hard disk. if __name__ == "__main__": my=Tektronix_DPO() my.set_HORIZONTAL(0,40E-3) my.open_ch(1) my.vertical_ch(1,200,0) my.trigger_set(1,0) my.begin_trigger() my.data_caul(1) my.get_screen() my.close()
参考
【1】TEK DPO系列示波器编程手册
【2】PyVISA官方文档
【3】TEK 技术交流论坛
来源地址:https://blog.csdn.net/qq_27655845/article/details/129602483