python 操作TK示波器(NI-VISA)
NI-VISA这是一种美国的一家公司的协议,主要用来和仪器通信,当然这只是一种通信的格式,具体的操作我们还是要参照示波器的说明书。
我们直接采用Python里面自带的NI—VISA库文件。pip install pyvisa,然后安装好NI-VISA的驱动,百度到官网即可下载安装。
通过VISA发送相应命令(示波器编程文档有命令集)即可完成对示波器的控制,并且通过VISA可以接收返回值,比如波形数据等。
这里是通过USB来与示波器通信
1 rm = visa.ResourceManager()
2 # res = rm.list_resources()
3 # print(rm)
4 # print(res)
5 self.inst = rm.open_resource('USB0::0x0699::0x0528::C019161::INSTR')
第一行是得到visa资源管理器,第二行的res会是返回当前与电脑连接的端口地址,采用print()将其打印出来即可看到你的示波器地址。然后就可以注释掉了,然后使用第五行的代码即可打开示波器通信通道。
源码如下:
1 import matplotlib.pyplot as plt
2 import visa
3 import time
4 from datetime import datetime # std library
5
6 class Tektronix_MSO64:
7 def __init__(self):
8 visa_dll = 'c:/windows/system32/visa32.dll'
9 self.rm = visa.ResourceManager()
10 # res = rm.list_resources()
11 # print(rm)
12 # print(res)
13 self.inst = self.rm.open_resource('USB0::0x0699::0x0528::C019161::INSTR')
14 ##############################################
15 self.inst.write("*IDN?")
16 print(self.inst.read())
17 self.inst.write('CLEAR')
18 self.inst.write('ACQuire:MODe?')
19 print(self.inst.read())
20 self.inst.timeout = 25000
21 self.inst.write('ACQUIRE:STOPAFTER RUNSTOP')
22 self.inst.write('ACQuire:STATE RUN')
23
24
25 def set_HORIZONTAL(self,POSITION,SCALE):#HORIZONTAL position,HORIZONTAL scale /us
26 self.inst.write('HORIZONTAL:POSITION %s'%POSITION)
27 self.inst.write('HORIZONTAL:SCALE %se-6'%SCALE)
28
29 def open_ch(self,ch):#关闭相应通道
30 self.inst.write('DISplay:GLObal:CH%s:STATE ON'%ch)
31
32 def close_ch(self,ch):#打开相应通道
33 self.inst.write('DISplay:GLObal:CH%s:STATE OFF'%ch)
34
35 def vertical_ch(self,ch,scale,position):#通道,ch scale/mv,ch POSition,
36 self.inst.write('CH%s:BANDWIDTH FULl'%ch)#at its maximum bandwidth
37 self.inst.write('CH%s:SCAle %sE-3'%(ch,scale))
38 self.inst.write('CH%s:POSition %s'%(ch,position))
39 self.inst.write('CH%s:COUPLING DC'%ch)#直流
40 self.inst.write('CH%s:TERMINATION 10.0E+5'%ch)#1兆欧
41
42 def trigger_set(self,ch,level):#通道,触发电压
43 self.inst.write('TRIGGER:A:EDGE:COUPLING DC')#边沿触发
44 self.inst.write('TRIGGER:A:EDGE:SOURCE CH%s'%ch)
45 self.inst.write('TRIGGER:A:EDGE:SLOPE RISE')#上升沿触发
46 self.inst.write('TRIGGER:A:LEVEL:CH4 %s'%level)
47
48 def begin_trigger(self):#开启一次触发
49 self.inst.write('ACQuire:STOPAfter SEQuence')
50 while 1:#等触发了才借宿
51 time.sleep(1)
52 self.inst.write('TRIGGER:STATE?')
53 TRIGGER_STATE =self.inst.read()
54 if TRIGGER_STATE[0] == "S":
55 print('have triggered')
56 break
57
58 def data_caul(self,ch):#通道
59 self.inst.write('DATA:SOURCE CH%s'%ch)
60 self.inst.write('DATa:ENCdg ASCIi')
61 self.inst.write('WFMOUTPRE:BYT_NR 4')
62 self.inst.write('DATA:START 1')
63 self.inst.write('DATA:STOP 250e6')
64 self.inst.write('WFMOUTPRE?')
65 preamble= self.inst.read()
66 #获取HORIZONTAL:POSITION
67 self.inst.write('HORIZONTAL:POSITION?')
68 HORIZONTAL_p=self.inst.read()
69 HORIZONTAL_pfloat=float(HORIZONTAL_p)
70 #获取HORIZONTAL:SCALE
71 self.inst.write('HORIZONTAL:SCALE?')
72 HORIZONTAL_S=self.inst.read()
73 HORIZONTAL_Sfloat=float(HORIZONTAL_S)
74 #获取ch POSition
75 self.inst.write('CH%s:POSition?'%ch)
76 divus_str = self.inst.read()
77 divus_float = float(divus_str)
78 #获取ch SCAle
79 self.inst.write('CH%s:SCAle?'%ch)
80 div_str = self.inst.read()
81 div_float = float(div_str)
82 #########################################################获取采样点数目
83 j=0
84 point_str=' '
85 for i in range(0,len(preamble)):
86 if preamble[i]==',':
87 j+=1
88 elif j==4:
89 point_str=point_str+preamble[i]
90 elif j==5:
91 point_len=len(point_str)
92 point_str=point_str[2:(point_len-6)]
93 break
94 point_int=int(point_str)
95 print('point_num:%d'%point_int)
96 ######################################################数据处理
97 data = self.inst.query('CURVE?')
98 x = []
99 dat = [' ']
100 dat1 = []
101 j = 0
102 for i in range(0, len(data)):
103 if data[i] == ',':
104 dat1.append(float(dat[j])/32000*div_float*5-div_float*divus_float)
105 x.append((int(j)/point_int*HORIZONTAL_Sfloat*10-HORIZONTAL_Sfloat*10*HORIZONTAL_pfloat/100))
106 j += 1
107 dat.append(' ')
108 else:
109 dat[j] = dat[j] + data[i]
110 plt.plot(x, dat1)
111
112 def close(self):
113 self.inst.close()
114 self.rm.close()
115
116 def get_screen(self):
117 self.inst.write('SAVE:IMAGE "E:/waveform_screen.bmp"')
118 time.sleep(1)
119 self.inst.write('FILESYSTEM:READFILE "E:/waveform_screen.bmp"')
120 img = self.inst.read_raw()
121 dt = datetime.now()
122 fileName = dt.strftime("%Y%m%d_%H%M%S.bmp") # 以当前时间建立文件名
123 imgFile = open('./waveform/' + fileName, "wb") # 打开图片文件,如果没有就会新建一个
124 imgFile.write(img)
125 imgFile.close()
126 self.inst.write('FILESYSTEM:DELETE "E:/waveform_screen.bmp"')
127
128
129
130
131
132 if __name__ == "__main__":
133 fig = plt.figure()
134 my=Tektronix_MSO64()
135 my.set_HORIZONTAL(10,200)
136 my.open_ch(4)
137 my.open_ch(3)
138 my.open_ch(2)
139 my.open_ch(1)
140 my.vertical_ch(4,2000,1)
141 my.vertical_ch(3,2000,2)
142 my.vertical_ch(2,2000,2)
143 my.vertical_ch(1,2000,2)
144 my.trigger_set(4,2)
145 my.begin_trigger()
146 my.data_caul(4)
147 my.data_caul(3)
148 my.data_caul(2)
149 my.data_caul(1)
150 my.get_screen()
151 plt.show()
152 my.close()
根据示波器编程文档,通过visa发送相应命令,接收相应返回值即可完成对示波器的控制,获取数据等,具体命令可以参考相应的编程文档。
此代码具有以下功能:
设置水平轴相关设置;
设置通道相关设置;
打开,关闭相应通道;
设置触发;
开启一次触发;
获取波形数据,并处理数据,然后通过plot()显示出来;
获取截屏图片,保存到pc本地;
下面是其他控制代码。可以设置测量方式,读取泰克示波器的上升沿等
# coding=utf-8
from datetime import datetime
import pyvisa
import time
class Tektronix_MSO64:
def __init__(self):
rm = pyvisa.ResourceManager("C:/Windows/System32/visa32.dll")
self.inst = rm.open_resource('USB0::0x0699::0x0368::C031376::INSTR')
self.inst.write("*IDN?") # 返回示波器识别码
# print(self.inst.read())
self.inst.write('*CLS') # 清除示波器状态
self.inst.write('*ESR?') # 查询标准状态寄存器的内容
# print(self.inst.read())
self.inst.write('ALLEV?') # 使示波器返回所有事件及其消息
# print(self.inst.read())
# self.inst.write('FACTORY') # 恢复出厂设置
self.inst.timeout = 50000
def close(self):
self.inst.write('*CLS') # 清除示波器状态
self.inst.write('*ESR?') # 查询标准状态寄存器的内容
# print(self.inst.read())
# self.inst.write('FACTORY') # 恢复出厂设置
self.inst.close()
def set_horizontal(self, VOLTS, SCALE):
self.inst.write('CH1:VOLTS %s' % VOLTS) # 设置示波器的垂直刻度
self.inst.write('HOR:MAIN:SCALE %se-3' % SCALE) # 设置示波器的水平刻度
self.inst.write('TRIG:MAIN:LEVEL 2.4') # 触发装置设置为2.4V
def operate_set(self):
self.inst.write('AUTORANGE:STATE ON') # 启动自动量程功能
self.inst.write('ACQUIRE:STOPAFTER SEQUENCE') # 按下RUN/STOP按钮将示波器设置为停止采集
self.inst.write('ACQuire:STATE ON') # 开始采集数据,将采集次数重置为0
# self.inst.write('*OPC?') # 查询OPC操作是否已完成
# print(self.inst.read())
def period_measure(self):
self.inst.write('MEASU:IMMED:TYPE PERIOD') # 设置为测量周期
self.inst.write('MEASU:IMMED:VALUE?') # 执行前面命令指定的立即示波器测量
global reperiod
str_rperiod = self.inst.read()
str_rperiod = str_rperiod[str_rperiod.rfind(' '):]
rperiod = float(str_rperiod) * 1000
rperiod = '%.2f' % rperiod
reperiod = float(rperiod)
print('实测周期:', reperiod)
def frequency_measure(self):
self.inst.write('MEASU:IMMED:TYPE FREQ') # 设置为测量频率
self.inst.write('MEASU:IMMED:VALUE?') # 执行前面命令指定的立即示波器测量
global rfrequent
str_frequency = self.inst.read()
str_frequency = str_frequency[str_frequency.rfind(' '):]
rfrequency = float(str_frequency)
rfrequency = '%.2f' % rfrequency
rfrequent = float(rfrequency)
print('实测频率:', rfrequent)
def duty_measure(self):
self.inst.write('MEASU:IMMED:TYPE PDUTY') # 设置为测量占空比
self.inst.write('MEASU:IMMED:VALUE?') # 执行前面命令指定的立即示波器测量
global reduty
str_duty = self.inst.read()
str_duty = str_duty[str_duty.rfind(' '):]
rduty = float(str_duty)
rduty = '%.2f' % rduty
reduty = float(rduty)
print('实测占空比:', reduty)
def rise_time_measure(self):
self.inst.write('MEASU:IMMED:TYPE RISE') # 设置为测量上升时间
self.inst.write('MEASU:IMMED:VALUE?') # 执行前面命令指定的立即示波器测量
str_rise = self.inst.read()
str_rise = str_rise[str_rise.rfind(' '):]
rise = float(str_rise)
rise = '%.2f' % rise
riser = float(rise)
print('实测上升时间:', riser)
def positive_pulse_width_measure(self):
self.inst.write('MEASU:IMMED:TYPE PWIDTH') # 设置为测量正脉冲宽度
self.inst.write('MEASU:IMMED:VALUE?') # 执行前面命令指定的立即示波器测量
str_positive_pulse_width = self.inst.read()
str_positive_pulse_width = str_positive_pulse_width[str_positive_pulse_width.rfind(' ')]
positive_pulse_width = float(str_positive_pulse_width)
positive_pulse_width = '%.2f' % positive_pulse_width
print('实测正脉冲宽度为:', positive_pulse_width)
def negative_pulse_width_measure(self):
self.inst.write('MEASU:IMMED:TYPE NWIDTH') # 设置为测量负脉冲宽度
self.inst.write('MEASU:IMMED:VALUE?') # 执行前面命令指定的立即示波器测量
str_negative_pulse_width = self.inst.read()
str_negative_pulse_width = str_negative_pulse_width[str_negative_pulse_width.rfind(' ')]
negative_pulse_width = float(str_negative_pulse_width)
negative_pulse_width = '%.2f' % negative_pulse_width
print('实测负脉冲宽度:', negative_pulse_width)
def basic_set(self):
self.inst.write('*ESR?') # 查询标准状态寄存器的内容
# print(self.inst.read())
self.inst.write('ALLEV?') # 使示波器返回所有事件及其消息
# print(self.inst.read())
self.inst.write('WFMPRE?') # 查询波形数据的编码类型
# print(self.inst.read())
def waveform_save(self):
self.inst.write('RECALL:WAVEFORM' 'D:\TST-PRD\TST-01.CSV')
self.inst.write('SELECT:REFC')
def get_screen(self):
self.inst.write('SAVE:IMAGE "D:/waveform_screen.bmp"')
time.sleep(1)
self.inst.write('FILESYSTEM:READFILE "D:/waveform_screen.bmp"')
img = self.inst.read_raw()
dt = datetime.now()
fileName = dt.strftime("%Y%m%d_%H%M%S.bmp") # 以当前时间建立文件名
imgFile = open('./waveform/' + fileName, "wb") # 打开图片文件,如果没有就会新建一个
imgFile.write(img)
imgFile.close()
self.inst.write('FILESYSTEM:DELETE "D:/waveform_screen.bmp"')
def oscilloscoper():
rm = Tektronix_MSO64()
rm.set_horizontal(2.0, 10)
# rm.operate_set()
rm.period_measure()
rm.frequency_measure()
rm.duty_measure()
rm.basic_set()
rm.close()
if __name__ == "__main__":
oscill = Tektronix_MSO64()
oscill.set_horizontal(2.0, 1)
# oscill.operate_set()
oscill.period_measure()
oscill.frequency_measure()
oscill.duty_measure()
# oscill.waveform_save()
oscill.basic_set()
# oscill.get_screen()