line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Lab::Instrument::Keithley2400; |
2
|
|
|
|
|
|
|
#ABSTRACT: Keithley 2400 SourceMeter |
3
|
|
|
|
|
|
|
$Lab::Instrument::Keithley2400::VERSION = '3.880'; |
4
|
1
|
|
|
1
|
|
1938
|
use v5.20; |
|
1
|
|
|
|
|
4
|
|
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
22
|
|
7
|
1
|
|
|
1
|
|
5
|
use Lab::Instrument; |
|
1
|
|
|
|
|
9
|
|
|
1
|
|
|
|
|
17
|
|
8
|
1
|
|
|
1
|
|
5
|
use Lab::Instrument::Source; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
39
|
|
9
|
1
|
|
|
1
|
|
6
|
use Time::HiRes qw/usleep/, qw/time/; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
8
|
|
10
|
1
|
|
|
1
|
|
108
|
use Carp; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
10288
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our @ISA = ('Lab::Instrument'); |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our %fields = ( |
15
|
|
|
|
|
|
|
supported_connections => |
16
|
|
|
|
|
|
|
[ 'VISA', 'VISA_GPIB', 'VISA_RS232', 'RS232', 'GPIB', 'DEBUG' ], |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# default settings for the supported connections |
19
|
|
|
|
|
|
|
connection_settings => { |
20
|
|
|
|
|
|
|
gpib_board => 0, |
21
|
|
|
|
|
|
|
gpib_address => undef, |
22
|
|
|
|
|
|
|
timeout => 2 |
23
|
|
|
|
|
|
|
}, |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
device_settings => { |
26
|
|
|
|
|
|
|
gate_protect => 0, |
27
|
|
|
|
|
|
|
gp_equal_level => 1e-5, |
28
|
|
|
|
|
|
|
gp_max_units_per_second => 0.002, |
29
|
|
|
|
|
|
|
gp_max_units_per_step => 0.001, |
30
|
|
|
|
|
|
|
gp_max_step_per_second => 2, |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
read_default => 'device' |
33
|
|
|
|
|
|
|
}, |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
device_cache => { id => 'Keithley 2400' } |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub new { |
40
|
0
|
|
|
0
|
1
|
|
my $proto = shift; |
41
|
0
|
|
0
|
|
|
|
my $class = ref($proto) || $proto; |
42
|
0
|
|
|
|
|
|
my $self = $class->SUPER::new(@_); |
43
|
0
|
|
|
|
|
|
$self->${ \( __PACKAGE__ . '::_construct' ) }(__PACKAGE__); |
|
0
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
|
45
|
0
|
|
|
|
|
|
$self->{armed} = 0; |
46
|
0
|
|
|
|
|
|
return $self; |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub _device_init { |
50
|
0
|
|
|
0
|
|
|
my $self = shift; |
51
|
|
|
|
|
|
|
|
52
|
0
|
|
|
|
|
|
$self->set_source_autooutputoff(0); |
53
|
0
|
|
|
|
|
|
$self->set_sense_concurrent('ON'); |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
#$self->set_sense_onfunction('ALL'); <-- Don't know why this was here, but it changes the sense function at the device init (bad idea) |
56
|
|
|
|
|
|
|
|
57
|
0
|
|
|
|
|
|
$self->clear_sweep(); |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub reset { |
61
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
62
|
0
|
|
|
|
|
|
$self->write("*RST"); |
63
|
0
|
|
|
|
|
|
return "RESET"; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# ------------------------------------ OUTPUT --------------------------------------------- |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
sub set_output { |
69
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
70
|
0
|
|
|
|
|
|
my ($value) = $self->_check_args( \@_, ['value'] ); |
71
|
|
|
|
|
|
|
|
72
|
0
|
|
|
|
|
|
my $current_level = undef; # for internal use only |
73
|
|
|
|
|
|
|
|
74
|
0
|
0
|
|
|
|
|
if ( not defined $value ) { |
75
|
0
|
|
|
|
|
|
return $self->get_output(); |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
0
|
0
|
|
|
|
|
if ( $self->device_settings()->{gate_protect} ) { |
79
|
0
|
0
|
0
|
|
|
|
if ( $self->get_output() == 1 and $value == 0 ) { |
|
|
0
|
0
|
|
|
|
|
80
|
0
|
|
|
|
|
|
$self->set_level(0); |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
elsif ( $self->get_output() == 0 and $value == 1 ) { |
83
|
0
|
|
|
|
|
|
$current_level = $self->get_level(); |
84
|
0
|
|
|
|
|
|
$self->set_level(0); |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
0
|
|
|
|
|
|
$self->wait(); |
89
|
|
|
|
|
|
|
|
90
|
0
|
0
|
|
|
|
|
if ( $value == 1 ) { |
|
|
0
|
|
|
|
|
|
91
|
0
|
|
|
|
|
|
$self->write(":OUTPUT ON"); |
92
|
|
|
|
|
|
|
|
93
|
0
|
0
|
|
|
|
|
if ( defined $current_level ) { |
94
|
0
|
|
|
|
|
|
$self->set_level($current_level); |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
elsif ( $value == 0 ) { |
99
|
0
|
|
|
|
|
|
$self->write(":OUTPUT OFF"); |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
else { |
103
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
104
|
|
|
|
|
|
|
"$value is not a valid output status (on = 1 | off = 0)"); |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
0
|
|
|
|
|
|
return $self->{'device_cache'}->{'output'} = $self->get_output(); |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub get_output { # basic setting |
111
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
112
|
0
|
|
|
|
|
|
my ($read_mode) = $self->_check_args( \@_, ['read_from'] ); |
113
|
|
|
|
|
|
|
|
114
|
0
|
0
|
0
|
|
|
|
if ( not defined $read_mode or not $read_mode =~ /device|cache/ ) { |
115
|
0
|
|
|
|
|
|
$read_mode = $self->device_settings()->{read_default}; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
0
|
0
|
0
|
|
|
|
if ( $read_mode eq 'cache' |
119
|
|
|
|
|
|
|
and defined $self->{'device_cache'}->{'output'} ) { |
120
|
0
|
|
|
|
|
|
return $self->{'device_cache'}->{'output'}; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
0
|
|
|
|
|
|
return $self->{'device_cache'}->{'output'} = $self->query(":OUTPUT?"); |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub set_output_offstate { # advanced settings |
127
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
128
|
0
|
|
|
|
|
|
my $offstate = shift; |
129
|
|
|
|
|
|
|
|
130
|
0
|
0
|
|
|
|
|
if ( not defined $offstate ) { |
|
|
0
|
|
|
|
|
|
131
|
0
|
|
|
|
|
|
return $self->query(":OUTPUT:SMODE?"); |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
elsif ( $offstate |
134
|
|
|
|
|
|
|
=~ /\b(HIMPEDANCE|HIMP|himpedance|himp|NORMAL|NORM|normal|norm|ZERO|zero|GUARD|GUAR|guard|guar)\b/ |
135
|
|
|
|
|
|
|
) { |
136
|
0
|
|
|
|
|
|
return $self->query(":OUTPUT:SMODE $offstate; :OUTPUT:SMODE?"); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
else { |
139
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
140
|
|
|
|
|
|
|
"unexpected value for OUTPUT OFF STATE in sub set_output_off_state. Expected values are HIMPEDANCE, NORMAL, ZERO or GUARD." |
141
|
|
|
|
|
|
|
); |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
#--------------------------------------SOURCE---------------------------------------------- |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# ------------------------------------ SENSE 1 subsystem ----------------------------------- |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub set_sense_terminals { # advanced settings |
150
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
151
|
0
|
|
|
|
|
|
my $terminals = shift; |
152
|
|
|
|
|
|
|
|
153
|
0
|
0
|
|
|
|
|
if ( $terminals =~ /\b(FRONT|FRON|front|fron|REAR|rear)\b/ ) { |
154
|
0
|
|
|
|
|
|
return $self->query( |
155
|
|
|
|
|
|
|
sprintf( ":ROUTE:TERMINALS %s; :ROUTE:TERMINALS?", $terminals ) ); |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
else { |
158
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
159
|
|
|
|
|
|
|
"unexpected value for TERMINAL in sub set_terminals. Expected values are FRONT or REAR." |
160
|
|
|
|
|
|
|
); |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
sub set_sense_concurrent { # advanced settings |
165
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
166
|
0
|
|
|
|
|
|
my $value = shift; |
167
|
|
|
|
|
|
|
|
168
|
0
|
0
|
|
|
|
|
if ( $value =~ /\b(ON|on|1|OFF|off|0)\b/ ) { |
169
|
0
|
|
|
|
|
|
return $self->query( |
170
|
|
|
|
|
|
|
sprintf( ":SENSE:FUNCTION:CONCURRENT %s; CONCURRENT?", $value ) ); |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
else { |
173
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
174
|
|
|
|
|
|
|
"unexpected value in sub set_concurrent. Expected values are ON, OFF, 1 or 0." |
175
|
|
|
|
|
|
|
); |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub set_sense_onfunction { # advanced settings |
180
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
181
|
0
|
|
|
|
|
|
my $list = shift; |
182
|
0
|
|
|
|
|
|
my @list = split( ",", $list ); |
183
|
|
|
|
|
|
|
|
184
|
0
|
0
|
|
|
|
|
if ( not defined $list ) { |
185
|
0
|
|
|
|
|
|
goto RETURN; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
# switch all function off first |
189
|
0
|
|
|
|
|
|
$self->write(":SENSE:FUNCTION:OFF:ALL"); |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
# switch on/off the concurrent-mode |
192
|
0
|
0
|
0
|
|
|
|
if ( ( my $length = @list ) > 1 or $list =~ /\b(ALL|all)\b/ ) { |
193
|
0
|
|
|
|
|
|
$self->set_sense_concurrent('ON'); |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
else { |
196
|
0
|
|
|
|
|
|
$self->set_sense_concurrent('OFF'); |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# check input data |
200
|
0
|
|
|
|
|
|
foreach my $onfunction (@list) { |
201
|
0
|
0
|
|
|
|
|
if ( $onfunction |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=~ /\b(CURRENT|CURR|current|curr|VOLTAGE|VOLT|voltage|volt)\b/ ) { |
203
|
0
|
|
|
|
|
|
$self->write( sprintf( ":SENSE:FUNCTION:ON '%s'", $onfunction ) ); |
204
|
0
|
|
|
|
|
|
$self->write(":FORMAT:DATA ASCII; :FORMAT:ELEMENTS $onfunction") |
205
|
|
|
|
|
|
|
; # select Format for reading DATA |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
elsif ( $onfunction =~ /\b(RESISTANCE|RES|resistance|res)\b/ ) { |
208
|
0
|
|
|
|
|
|
$self->write( sprintf( ":SENSE:FUNCTION:ON '%s'", $onfunction ) ); |
209
|
0
|
|
|
|
|
|
$self->write(":FORMAT:DATA ASCII; :FORMAT:ELEMENTS $onfunction") |
210
|
|
|
|
|
|
|
; # select Format for reading DATA |
211
|
0
|
|
|
|
|
|
$self->set_sense_resistancemode('MAN'); |
212
|
0
|
|
|
|
|
|
$self->set_sense_resistance_zerocompensated('OFF'); |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
elsif ( $onfunction =~ /\b(ALL|all)\b/ ) { |
215
|
0
|
|
|
|
|
|
$self->write(":SENSE:FUNCTION:ON:ALL"); |
216
|
0
|
|
|
|
|
|
$self->write(":FORMAT:DATA ASCII; :FORMAT:ELEMENTS $onfunction") |
217
|
|
|
|
|
|
|
; # select Format for reading DATA |
218
|
0
|
|
|
|
|
|
$self->set_sense_resistancemode('MAN'); |
219
|
0
|
|
|
|
|
|
$self->set_sense_resistance_zerocompensated('OFF'); |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
elsif ( $onfunction =~ /\b(OFF|off|NONE|none)\b/ ) { |
222
|
0
|
|
|
|
|
|
$self->write(":SENSE:FUNCTION:OFF:ALL"); |
223
|
0
|
|
|
|
|
|
return; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
else { |
226
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
227
|
|
|
|
|
|
|
"unexpected value in sub set_onfunction. Expected values are CURRENT, VOLTAGE, RESISTNCE and ALL." |
228
|
|
|
|
|
|
|
); |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
# read out onfunctions |
233
|
|
|
|
|
|
|
RETURN: |
234
|
0
|
|
|
|
|
|
my $onfunctions = $self->query(":SENSE:FUNCTION:ON?"); |
235
|
0
|
|
|
|
|
|
my @onfunctions = split( ",", $onfunctions ); |
236
|
0
|
|
|
|
|
|
$onfunctions = ""; |
237
|
0
|
|
|
|
|
|
foreach my $onfunction (@onfunctions) { |
238
|
0
|
0
|
|
|
|
|
if ( $onfunction |
239
|
|
|
|
|
|
|
=~ /(VOLTAGE|VOLT|voltage|volt|CURRENT|CURR|current|curr|RESISTANCE|RES|resistance|res)/ |
240
|
|
|
|
|
|
|
) { |
241
|
0
|
|
|
|
|
|
$onfunction = $1; |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
else { |
244
|
0
|
|
|
|
|
|
$onfunction = "NONE"; |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
} |
247
|
0
|
|
|
|
|
|
$onfunctions = join( ",", @onfunctions ); |
248
|
|
|
|
|
|
|
|
249
|
0
|
|
|
|
|
|
return $onfunctions; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub set_sense_resistancemode { # advanced settings |
253
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
254
|
0
|
|
|
|
|
|
my $mode = shift; |
255
|
|
|
|
|
|
|
|
256
|
0
|
0
|
|
|
|
|
if ( $mode =~ /\b(AUTO|auto|MAN|man)\b/ ) { |
257
|
0
|
|
|
|
|
|
$self->write( sprintf( ":SENSE:RESISTANCE:MODE %s", $mode ) ); |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
else { |
260
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
261
|
|
|
|
|
|
|
"unexpected value for MODE in sub set_resistancemode. Expected values are AUTO or MAN." |
262
|
|
|
|
|
|
|
); |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
sub set_sense_resistance_zerocompensated { # advanced settings |
267
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
268
|
0
|
|
|
|
|
|
my $zerocompensation = shift; |
269
|
|
|
|
|
|
|
|
270
|
0
|
0
|
|
|
|
|
if ( $zerocompensation =~ /\b(ON|on|1|OFF|off|0)\b/ ) { |
271
|
0
|
|
|
|
|
|
$self->query( |
272
|
|
|
|
|
|
|
sprintf( ":SENSE:RES:OCOM %s; OCOM?", $zerocompensation ) ); |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
else { |
275
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
276
|
|
|
|
|
|
|
"unexpected value for ZEROCOMPENSTION in sub set_resistance_zerocompensated. Expected values are ON, OFF, 1 or 0." |
277
|
|
|
|
|
|
|
); |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
sub set_sense_range { # basic setting |
282
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
283
|
0
|
|
|
|
|
|
my $function = shift; |
284
|
0
|
|
|
|
|
|
my $range = shift; |
285
|
0
|
|
|
|
|
|
my $llimit = shift; |
286
|
0
|
|
|
|
|
|
my $ulimit = shift; |
287
|
|
|
|
|
|
|
|
288
|
0
|
0
|
|
|
|
|
if ( $function =~ /\b(CURRENT|CURR|current|curr)\b/ ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
289
|
0
|
0
|
0
|
|
|
|
if ( $range |
|
|
0
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=~ /\b(AUTO|auto|UP|up|DOWN|down|MIN|min|MAX|max|DEF|def)\b/ ) { |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
#pass |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
elsif ( ( $range >= -1.05 && $range <= 1.05 ) ) { |
295
|
0
|
|
|
|
|
|
$range = sprintf( "%.5f", $range ); |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
else { |
298
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
299
|
|
|
|
|
|
|
"unexpected value for 'RANGE' in sub set_sense_range. Expected values are between -1.05 and 1.05." |
300
|
|
|
|
|
|
|
); |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
elsif ( $function =~ /\b(VOLTAGE|VOLT|voltage|volt)\b/ ) { |
305
|
0
|
0
|
0
|
|
|
|
if ( $range |
|
|
0
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=~ /\b(AUTO|auto|UP|up|DOWN|down|MIN|min|MAX|max|DEF|def)\b/ ) { |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
#pass |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
elsif ( ( $range >= -210 && $range <= 210 ) ) { |
311
|
0
|
|
|
|
|
|
$range = sprintf( "%.1f", $range ); |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
else { |
314
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
315
|
|
|
|
|
|
|
"unexpected value for 'RANGE' in sub set_sense_range. Expected values are between -210 and 210." |
316
|
|
|
|
|
|
|
); |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
elsif ( $function =~ /\b(RESISTANCE|RES|resistance|res)\b/ ) { |
321
|
0
|
0
|
0
|
|
|
|
if ( $range |
|
|
0
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=~ /\b(AUTO|auto|UP|up|DOWN|down|MIN|min|MAX|max|DEF|def)\b/ ) { |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
#pass |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
elsif ( ( $range >= 0 && $range <= 2.1e8 ) ) { |
327
|
0
|
|
|
|
|
|
$range = sprintf( "%.1f", $range ); |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
else { |
330
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
331
|
|
|
|
|
|
|
"unexpected value in sub set_sense_range for 'RANGE'. Expected values are between 0 and 2.1E8." |
332
|
|
|
|
|
|
|
); |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
else { |
337
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
338
|
|
|
|
|
|
|
"unexpected value for FUNCTION in sub set_range. Function can be CURRENT[:DC], VOLTAGE[:DC] or RESISTANCE" |
339
|
|
|
|
|
|
|
); |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
# set range |
343
|
0
|
|
|
|
|
|
my $cmd; |
344
|
0
|
0
|
|
|
|
|
if ( $range =~ /\b(AUTO|auto)\b/ ) { |
345
|
0
|
0
|
0
|
|
|
|
if ( defined $llimit |
|
|
|
0
|
|
|
|
|
346
|
|
|
|
|
|
|
and defined $ulimit |
347
|
|
|
|
|
|
|
and $llimit <= $ulimit |
348
|
|
|
|
|
|
|
) # warning: the values for llimit and ulimit are not checked by this function |
349
|
|
|
|
|
|
|
{ |
350
|
0
|
|
|
|
|
|
$cmd = sprintf( |
351
|
|
|
|
|
|
|
":SENSE:%s:RANGE:AUTO ON; LLIMIT %.5f; ULIMIT %.5f; :SENSE:%s:RANGE?", |
352
|
|
|
|
|
|
|
$function, $llimit, $ulimit, $function |
353
|
|
|
|
|
|
|
); |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
else { |
356
|
0
|
|
|
|
|
|
$cmd = sprintf( |
357
|
|
|
|
|
|
|
":SENSE:%s:RANGE:AUTO ON; :SENSE:%s:RANGE?", |
358
|
|
|
|
|
|
|
$function, $function |
359
|
|
|
|
|
|
|
); |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
else { |
363
|
|
|
|
|
|
|
|
364
|
0
|
0
|
|
|
|
|
if ( $range > $self->set_complience($function) ) { |
365
|
0
|
|
|
|
|
|
print Lab::Exception::CorruptParameter->new( |
366
|
|
|
|
|
|
|
"Error setting RANGE. Can't exceed Complience."); |
367
|
0
|
|
|
|
|
|
$range = $self->set_complience($function); |
368
|
|
|
|
|
|
|
} |
369
|
0
|
|
|
|
|
|
$cmd = sprintf(":SENSE:$function:RANGE $range; RANGE?"); |
370
|
|
|
|
|
|
|
} |
371
|
0
|
|
|
|
|
|
my $return_range = $self->query($cmd); |
372
|
|
|
|
|
|
|
|
373
|
0
|
|
|
|
|
|
printf( "set RANGE for %s to %s.", $function, $return_range ); |
374
|
0
|
|
|
|
|
|
return $return_range; |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
sub set_compliance { # basic setting |
378
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
379
|
0
|
|
|
|
|
|
my ( $complience, $function ) |
380
|
|
|
|
|
|
|
= $self->_check_args( \@_, [ 'value', 'function' ] ); |
381
|
|
|
|
|
|
|
|
382
|
0
|
0
|
0
|
|
|
|
if ( not defined $function and not defined $complience ) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
383
|
0
|
|
|
|
|
|
$function = $self->set_source_mode(); |
384
|
0
|
|
|
|
|
|
return $self->query( |
385
|
|
|
|
|
|
|
sprintf( ":SENSE:%s:PROTECTION:LEVEL?", $function ) ); |
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
elsif ( not defined $complience |
388
|
|
|
|
|
|
|
and $function =~ /\b\d+(e\d+|E\d+|exp\d+|EXP\d+)?\b/ |
389
|
|
|
|
|
|
|
or $function =~ /\b(MIN|min|MAX|max|DEF|def|AUTO|auto)\b/ ) { |
390
|
0
|
|
|
|
|
|
$complience = $function; |
391
|
0
|
|
|
|
|
|
$function = $self->set_source_mode(); |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
elsif ( not defined $complience ) { |
394
|
0
|
|
|
|
|
|
return $self->query( |
395
|
|
|
|
|
|
|
sprintf( ":SENSE:%s:PROTECTION:LEVEL?", $function ) ); |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
|
398
|
0
|
0
|
|
|
|
|
if ( not defined $function ) { |
399
|
0
|
|
|
|
|
|
$function = $self->get_source_function(); |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
|
402
|
0
|
0
|
|
|
|
|
if ( $function =~ /\b(CURRENT|CURR|current|curr)\b/ ) { |
|
|
0
|
|
|
|
|
|
403
|
0
|
0
|
0
|
|
|
|
if ( $complience < -210 or $complience > 210 ) { |
404
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
405
|
|
|
|
|
|
|
"unexpected value for COMPLIENCE in sub set_comlience. Expected values are between -210 and +210V." |
406
|
|
|
|
|
|
|
); |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
elsif ( $function =~ /\b(VOLTAGE|VOLT|voltage|volt)\b/ ) { |
411
|
0
|
0
|
0
|
|
|
|
if ( $complience < -1.05 or $complience > 1.05 ) { |
412
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
413
|
|
|
|
|
|
|
"unexpected value for COMPLIENCE in sub set_comlience. Expected values are between -1.05 and +1.05A." |
414
|
|
|
|
|
|
|
); |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
# check if $complience is valid with respect to the selected RANGE; $comlience >= 0.1%xRANGE |
419
|
|
|
|
|
|
|
#if ($complience < 0.001*$self->query(sprintf(":SENSE:%s:RANGE?",$function))){ |
420
|
|
|
|
|
|
|
# Lab::Exception::CorruptParameter->throw("unexpected value for COMPLIENCE in sub set_complience. COMPLIENCE must be greater than 0.001xRANGE."); |
421
|
|
|
|
|
|
|
# } |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
# set complience |
424
|
|
|
|
|
|
|
|
425
|
0
|
0
|
|
|
|
|
if ( $function =~ /\b(CURRENT|CURR|current|curr)\b/ ) { |
|
|
0
|
|
|
|
|
|
426
|
0
|
|
|
|
|
|
return $self->query( |
427
|
|
|
|
|
|
|
sprintf( |
428
|
|
|
|
|
|
|
":SENSE:VOLTAGE:PROTECTION:LEVEL %e; LEVEL?", $complience |
429
|
|
|
|
|
|
|
) |
430
|
|
|
|
|
|
|
); |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
elsif ( $function =~ /\b(VOLTAGE|VOLT|voltage|volt)\b/ ) { |
433
|
0
|
|
|
|
|
|
return $self->query( |
434
|
|
|
|
|
|
|
sprintf( |
435
|
|
|
|
|
|
|
":SENSE:CURRENT:PROTECTION:LEVEL %e; LEVEL?", $complience |
436
|
|
|
|
|
|
|
) |
437
|
|
|
|
|
|
|
); |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
sub set_sense_nplc { # basic setting |
442
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
443
|
0
|
|
|
|
|
|
my $function = shift; |
444
|
0
|
|
|
|
|
|
my $nplc = shift; |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
# return settings if no new values are given |
447
|
0
|
0
|
|
|
|
|
if ( not defined $nplc ) { |
448
|
0
|
0
|
0
|
|
|
|
if ( not defined $function ) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
449
|
0
|
|
|
|
|
|
$function = $self->query(":SOURCE:FUNCTION:MODE?"); |
450
|
0
|
|
|
|
|
|
chomp $function; |
451
|
0
|
|
|
|
|
|
$nplc = $self->query(":SENSE:$function:NPLC?"); |
452
|
0
|
|
|
|
|
|
chomp($nplc); |
453
|
0
|
|
|
|
|
|
return $nplc; |
454
|
|
|
|
|
|
|
} |
455
|
|
|
|
|
|
|
elsif ( $function |
456
|
|
|
|
|
|
|
=~ /\b(CURRENT|CURR|current|curr|VOLTAGE|VOLT|voltage|volt|RESISTANCE|RES|resistance|res)\b/ |
457
|
|
|
|
|
|
|
) { |
458
|
0
|
|
|
|
|
|
$nplc = $self->query(":SENSE:$function:NPLC?"); |
459
|
0
|
|
|
|
|
|
chomp($nplc); |
460
|
0
|
|
|
|
|
|
return $nplc; |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
elsif ( ( $function >= 0.01 && $function <= 1000 ) |
463
|
|
|
|
|
|
|
or $function =~ /\b(MAX|max|MIN|min|DEF|def)\b/ ) { |
464
|
0
|
|
|
|
|
|
$nplc = $function; |
465
|
0
|
|
|
|
|
|
$function = $self->query(":SOURCE:FUNCTION:MODE?"); |
466
|
0
|
|
|
|
|
|
chomp $function; |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
else { |
469
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
470
|
|
|
|
|
|
|
"unexpected value for FUNCTION in sub set_sense_nplc. Expected values are CURRENT:AC, CURRENT:DC, VOLTAGE:AC, VOLTAGE:DC, RESISTANCE, FRESISTANCE, TEMPERATURE" |
471
|
|
|
|
|
|
|
); |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
0
|
0
|
0
|
|
|
|
if ( ( $nplc < 0.01 && $nplc > 1000 ) |
|
|
|
0
|
|
|
|
|
477
|
|
|
|
|
|
|
and not $nplc =~ /\b(MAX|max|MIN|min|DEF|def)\b/ ) { |
478
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
479
|
|
|
|
|
|
|
"unexpected value for NPLC in sub set_sense_nplc. Expected values are between 0.01 and 1000 POWER LINE CYCLES or MIN/MAX/DEF." |
480
|
|
|
|
|
|
|
); |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
|
483
|
0
|
0
|
|
|
|
|
if ( $function |
484
|
|
|
|
|
|
|
=~ /\b(CURRENT|CURR|current|curr|VOLTAGE|VOLT|voltage|volt|RESISTANCE|RES|resistance|res)\b/ |
485
|
|
|
|
|
|
|
) { |
486
|
0
|
0
|
|
|
|
|
if ( $nplc > 10 ) { |
487
|
0
|
|
|
|
|
|
my $averaging = $nplc / 10; |
488
|
0
|
|
|
|
|
|
print "sub set_nplc: use AVERAGING of " |
489
|
|
|
|
|
|
|
. $self->set_sense_averaging($averaging) . "\n"; |
490
|
0
|
|
|
|
|
|
$nplc /= $averaging; |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
else { |
493
|
0
|
|
|
|
|
|
$self->set_sense_averaging('OFF'); |
494
|
|
|
|
|
|
|
} |
495
|
0
|
0
|
|
|
|
|
if ( $nplc =~ /\b(MAX|max|MIN|min|DEF|def)\b/ ) { |
|
|
0
|
|
|
|
|
|
496
|
0
|
|
|
|
|
|
return $self->query( |
497
|
|
|
|
|
|
|
sprintf( ":SENSE:%s:NPLC %s; NPLC?", $function, $nplc ) ); |
498
|
|
|
|
|
|
|
} |
499
|
|
|
|
|
|
|
elsif ( $nplc =~ /\b\d+(e\d+|E\d+|exp\d+|EXP\d+)?\b/ ) { |
500
|
0
|
|
|
|
|
|
return $self->query( |
501
|
|
|
|
|
|
|
sprintf( ":SENSE:%s:NPLC %e; NPLC?", $function, $nplc ) ); |
502
|
|
|
|
|
|
|
} |
503
|
|
|
|
|
|
|
else { |
504
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
505
|
|
|
|
|
|
|
"unexpected value for NPLC in sub set_sense_nplc. Expected values are between 0.01 and 10 POWER LINE CYCLES or MIN/MAX/DEF." |
506
|
|
|
|
|
|
|
); |
507
|
|
|
|
|
|
|
} |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
else { |
510
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
511
|
|
|
|
|
|
|
"unexpected value for FUNCTION in sub set_sense_nplc. Expected values are CURRENT:AC, CURRENT:DC, VOLTAGE:AC, VOLTAGE:DC, RESISTANCE, FRESISTANCE, TEMPERATURE" |
512
|
|
|
|
|
|
|
); |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
} |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
sub get_sense_nplc { |
517
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
518
|
0
|
|
|
|
|
|
my $function = shift; |
519
|
|
|
|
|
|
|
|
520
|
0
|
|
|
|
|
|
my $nplc; |
521
|
|
|
|
|
|
|
|
522
|
0
|
0
|
|
|
|
|
if ( not defined $function ) { |
|
|
0
|
|
|
|
|
|
523
|
0
|
|
|
|
|
|
$function = $self->query(":SOURCE:FUNCTION:MODE?"); |
524
|
0
|
|
|
|
|
|
chomp $function; |
525
|
0
|
|
|
|
|
|
$nplc = $self->query(":SENSE:$function:NPLC?"); |
526
|
0
|
|
|
|
|
|
chomp($nplc); |
527
|
0
|
|
|
|
|
|
return $nplc; |
528
|
|
|
|
|
|
|
} |
529
|
|
|
|
|
|
|
elsif ( $function |
530
|
|
|
|
|
|
|
=~ /\b(CURRENT|CURR|current|curr|VOLTAGE|VOLT|voltage|volt|RESISTANCE|RES|resistance|res)\b/ |
531
|
|
|
|
|
|
|
) { |
532
|
0
|
|
|
|
|
|
$nplc = $self->query(":SENSE:$function:NPLC?"); |
533
|
0
|
|
|
|
|
|
chomp($nplc); |
534
|
0
|
|
|
|
|
|
return $nplc; |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
sub set_sense_averaging { # advanced settings |
540
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
541
|
0
|
|
|
|
|
|
my $count = shift; |
542
|
0
|
|
|
|
|
|
my $filter = shift; |
543
|
|
|
|
|
|
|
|
544
|
0
|
0
|
0
|
|
|
|
if ( not defined $count and not defined $filter ) { |
545
|
0
|
|
|
|
|
|
return $self->query(":SENSE:AVERAGE:COUNT?"); |
546
|
|
|
|
|
|
|
} |
547
|
|
|
|
|
|
|
|
548
|
0
|
0
|
0
|
|
|
|
if ( $count >= 1 and $count <= 100 ) { |
|
|
0
|
|
|
|
|
|
549
|
0
|
0
|
0
|
|
|
|
if ( |
|
|
0
|
|
|
|
|
|
550
|
|
|
|
|
|
|
defined $filter |
551
|
|
|
|
|
|
|
and |
552
|
|
|
|
|
|
|
( $filter =~ /\b(REPEAT|REP|repeat|rep|MOVING|MOV|moving|mov)\b/ ) |
553
|
|
|
|
|
|
|
) { |
554
|
0
|
|
|
|
|
|
return $self->query( |
555
|
|
|
|
|
|
|
sprintf( |
556
|
|
|
|
|
|
|
":SENSE:AVERAGE:TCONTROL %s; COUNT %d; STATE ON; COUNT?", |
557
|
|
|
|
|
|
|
$filter, $count |
558
|
|
|
|
|
|
|
) |
559
|
|
|
|
|
|
|
); |
560
|
|
|
|
|
|
|
} |
561
|
|
|
|
|
|
|
elsif ( not defined $filter ) { |
562
|
0
|
|
|
|
|
|
return $self->query( |
563
|
|
|
|
|
|
|
sprintf( |
564
|
|
|
|
|
|
|
":SENSE:AVERAGE:TCONTROL MOV; COUNT %d; STATE ON; COUNT?", |
565
|
|
|
|
|
|
|
$count |
566
|
|
|
|
|
|
|
) |
567
|
|
|
|
|
|
|
); |
568
|
|
|
|
|
|
|
} |
569
|
|
|
|
|
|
|
else { |
570
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
571
|
|
|
|
|
|
|
"unexpected value for FILTER in sub set_averaging. Expected values are REPEAT or MOVING." |
572
|
|
|
|
|
|
|
); |
573
|
|
|
|
|
|
|
} |
574
|
|
|
|
|
|
|
} |
575
|
|
|
|
|
|
|
elsif ( $count =~ /\b(OFF|off|0)\b/ ) { |
576
|
0
|
|
|
|
|
|
return $self->query( |
577
|
|
|
|
|
|
|
sprintf(":SENSE:AVERAGE:STATE OFF; TCONTROL MOV; STATE?") ); |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
else { |
580
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
581
|
|
|
|
|
|
|
"unexpected value for COUNT in sub set_averaging. Expected values are between 1 and 100 or 0 or OFF to turn off averaging" |
582
|
|
|
|
|
|
|
); |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
} |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
# ------------------------------------ SOURCE subsystem ----------------------------------- |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
sub set_source_autooutputoff { # advanced settings |
589
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
590
|
0
|
|
|
|
|
|
my $mode = shift; |
591
|
|
|
|
|
|
|
|
592
|
0
|
0
|
|
|
|
|
if ( $mode =~ /\b(ON|on|1|OFF|off|0)\b/ ) { |
|
|
0
|
|
|
|
|
|
593
|
0
|
|
|
|
|
|
return $self->query( |
594
|
|
|
|
|
|
|
sprintf( ":SOURCE:CLEAR:AUTO %s; :SOURCE:CLEAR:AUTO?", $mode ) ); |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
elsif ( not defined $mode ) { |
597
|
0
|
|
|
|
|
|
return $self->query(":SOURCE:CLEAR:AUTO OFF; :SOURCE:CLEAR:AUTO?"); |
598
|
|
|
|
|
|
|
} |
599
|
|
|
|
|
|
|
else { |
600
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
601
|
|
|
|
|
|
|
"unexpected value for MODE in sub set_sourceautooutputoff. Expected values are ON, OFF, 1 or 0." |
602
|
|
|
|
|
|
|
); |
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
} |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
sub set_source_sourcingmode { # advanced settings |
607
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
608
|
0
|
|
|
|
|
|
my $function = shift; |
609
|
0
|
|
|
|
|
|
my $mode = shift; |
610
|
|
|
|
|
|
|
|
611
|
0
|
0
|
0
|
|
|
|
if ( $function =~ /\b(CURRENT|CURR|current|curr)\b/ |
612
|
|
|
|
|
|
|
or $function =~ /\b(VOLTAGE|VOLT|voltage|volt)\b/ ) { |
613
|
0
|
0
|
0
|
|
|
|
if ( $mode =~ /\b(FIXED|FIX|fixed|fix)\b/ |
|
|
|
0
|
|
|
|
|
614
|
|
|
|
|
|
|
or $mode =~ /\b(LIST|list)\b/ |
615
|
|
|
|
|
|
|
or $mode =~ /\b(SWEEP|SWE|sweep|swe)\b/ ) { |
616
|
0
|
|
|
|
|
|
return $self->query( |
617
|
|
|
|
|
|
|
sprintf( |
618
|
|
|
|
|
|
|
":SOURCE:%s:MODE %s; :SOURCE:%s:MODE?", |
619
|
|
|
|
|
|
|
$function, $mode, $function |
620
|
|
|
|
|
|
|
) |
621
|
|
|
|
|
|
|
); |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
else { |
624
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
625
|
|
|
|
|
|
|
"unexpected value for MODE in sub set_sourcingmode. Expected values are FIXED, LIST or SWEEP." |
626
|
|
|
|
|
|
|
); |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
} |
629
|
|
|
|
|
|
|
else { |
630
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
631
|
|
|
|
|
|
|
"unexpected value for FUNCTION in sub set_sourcingmode. Expected values are CURRENT or VOLTAGE." |
632
|
|
|
|
|
|
|
); |
633
|
|
|
|
|
|
|
} |
634
|
|
|
|
|
|
|
} |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
sub set_source_range { # basic setting |
637
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
638
|
0
|
|
|
|
|
|
my $function = shift; |
639
|
0
|
|
|
|
|
|
my $range = shift; |
640
|
|
|
|
|
|
|
|
641
|
0
|
0
|
0
|
|
|
|
if ( not defined $function and not defined $range ) { |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
642
|
0
|
|
|
|
|
|
$function = $self->set_source_mode(); |
643
|
0
|
|
|
|
|
|
return $self->query( sprintf( ":SOURCE:%s:RANGE?", $function ) ); |
644
|
|
|
|
|
|
|
} |
645
|
|
|
|
|
|
|
elsif ( not defined $range |
646
|
|
|
|
|
|
|
and $function =~ /\b\d+(e\d+|E\d+|exp\d+|EXP\d+)?\b/ |
647
|
|
|
|
|
|
|
or $function =~ /\b(MIN|min|MAX|max|DEF|def|AUTO|auto)\b/ ) { |
648
|
0
|
|
|
|
|
|
$range = $function; |
649
|
0
|
|
|
|
|
|
$function = $self->set_source_mode(); |
650
|
|
|
|
|
|
|
} |
651
|
|
|
|
|
|
|
|
652
|
0
|
0
|
|
|
|
|
if ( $function =~ /\b(CURRENT|CURR|current|curr)\b/ ) { |
|
|
0
|
|
|
|
|
|
653
|
0
|
0
|
0
|
|
|
|
if ( ( $range >= -1.05 && $range <= 1.05 ) || $range eq "AUTO" ) { |
|
|
|
0
|
|
|
|
|
654
|
0
|
|
|
|
|
|
$range = sprintf( "%.5f", $range ); |
655
|
|
|
|
|
|
|
} |
656
|
|
|
|
|
|
|
else { |
657
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
658
|
|
|
|
|
|
|
"unexpected value in sub set_source_range for 'RANGE'. Expected values are between -1.05 and 1.05." |
659
|
|
|
|
|
|
|
); |
660
|
|
|
|
|
|
|
} |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
elsif ( $function =~ /\b(VOLTAGE|VOLT|voltage|volt)\b/ ) { |
664
|
0
|
0
|
0
|
|
|
|
if ( ( $range >= -210 && $range <= 210 ) || $range eq "AUTO" ) { |
|
|
|
0
|
|
|
|
|
665
|
0
|
|
|
|
|
|
$range = sprintf( "%.1f", $range ); |
666
|
|
|
|
|
|
|
} |
667
|
|
|
|
|
|
|
else { |
668
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
669
|
|
|
|
|
|
|
"unexpected value in sub set_source_range for 'RANGE'. Expected values are between -210 and 210." |
670
|
|
|
|
|
|
|
); |
671
|
|
|
|
|
|
|
} |
672
|
|
|
|
|
|
|
} |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
else { |
675
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
676
|
|
|
|
|
|
|
"unexpected value in sub set_source_range. Function can be CURRENT or VOLTAGE" |
677
|
|
|
|
|
|
|
); |
678
|
|
|
|
|
|
|
} |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
# set range |
681
|
0
|
0
|
|
|
|
|
if ( $range =~ /\b(AUTO|auto)\b/ ) { |
|
|
0
|
|
|
|
|
|
682
|
0
|
|
|
|
|
|
$self->query( sprintf( ":SENSE:%s:RANGE:AUTO ON", $function ) ); |
683
|
0
|
|
|
|
|
|
return "AUTO"; |
684
|
|
|
|
|
|
|
} |
685
|
|
|
|
|
|
|
elsif ( $range =~ /\b(MIN|min|MAX|max|DEF|def)\b/ ) { |
686
|
0
|
|
|
|
|
|
return $self->query( |
687
|
|
|
|
|
|
|
sprintf( ":SOURCE:%s:RANGE %s; RANGE?", $function, $range ) ); |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
else { |
690
|
0
|
|
|
|
|
|
return $self->query( |
691
|
|
|
|
|
|
|
sprintf( ":SOURCE:%s:RANGE %.5f; RANGE?", $function, $range ) ); |
692
|
|
|
|
|
|
|
} |
693
|
|
|
|
|
|
|
} |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
sub _set_source_amplitude { # internal/advanced use only |
696
|
0
|
|
|
0
|
|
|
my $self = shift; |
697
|
0
|
|
|
|
|
|
my $function = shift; |
698
|
0
|
|
|
|
|
|
my $value = shift; |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
# check trigger status |
701
|
0
|
|
|
|
|
|
my $triggerstatus = $self->query("TRIGGER:SEQUENCE:SOURCE?"); |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
# check input data |
704
|
0
|
0
|
0
|
|
|
|
if ( not defined $value and not defined $function ) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
705
|
0
|
|
|
|
|
|
$function = $self->set_source_mode(); |
706
|
0
|
|
|
|
|
|
return $self->query( sprintf( ":SOURCE:%s?", $function ) ); |
707
|
|
|
|
|
|
|
} |
708
|
|
|
|
|
|
|
elsif ( |
709
|
|
|
|
|
|
|
not defined $value |
710
|
|
|
|
|
|
|
and ( $function =~ /\b(CURRENT|CURR|current|curr)\b/ |
711
|
|
|
|
|
|
|
or $function =~ /\b(VOLTAGE|VOLT|voltage|volt)\b/ ) |
712
|
|
|
|
|
|
|
) { |
713
|
0
|
0
|
|
|
|
|
if ( $triggerstatus =~ /\b(IMMEDIATE|IMM|immediate|imm)\b/ ) { |
714
|
0
|
|
|
|
|
|
return $self->query( sprintf( ":SOURCE:%s?", $function ) ); |
715
|
|
|
|
|
|
|
} |
716
|
|
|
|
|
|
|
else { |
717
|
0
|
|
|
|
|
|
return $self->query( |
718
|
|
|
|
|
|
|
sprintf( ":SOURCE:%s:TRIGGERED?", $function ) ); |
719
|
|
|
|
|
|
|
} |
720
|
|
|
|
|
|
|
} |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
elsif ( not defined $value and $function >= -210 and $function <= 210 ) { |
723
|
0
|
|
|
|
|
|
$value = $function; |
724
|
0
|
|
|
|
|
|
$function = $self->set_source_mode(); |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
0
|
0
|
0
|
|
|
|
if ( |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
728
|
|
|
|
|
|
|
( |
729
|
|
|
|
|
|
|
$function =~ /\b(VOLTAGE|VOLT|voltage|volt)\b/ |
730
|
|
|
|
|
|
|
and $value >= -210 |
731
|
|
|
|
|
|
|
and $value <= 210 |
732
|
|
|
|
|
|
|
) |
733
|
|
|
|
|
|
|
or ( $function =~ /\b(CURRENT|CURR|current|curr)\b/ |
734
|
|
|
|
|
|
|
and $value >= -1.05 |
735
|
|
|
|
|
|
|
and $value <= 1.05 ) |
736
|
|
|
|
|
|
|
) { |
737
|
|
|
|
|
|
|
# check if new value is within the current range |
738
|
0
|
0
|
|
|
|
|
if ( $value <= $self->set_source_range($function) ) { |
739
|
0
|
|
|
|
|
|
print Lab::Exception::CorruptParameter->new( |
740
|
|
|
|
|
|
|
"WARNING: setting new OUTPUT value. Value not within current range setting. Change range setting to fit with new output setting." |
741
|
|
|
|
|
|
|
); |
742
|
0
|
|
|
|
|
|
$self->set_source_range( $function, $value ); |
743
|
|
|
|
|
|
|
} |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
# set source output amplitude |
746
|
0
|
0
|
|
|
|
|
if ( $triggerstatus =~ /\b(IMMEDIATE|IMM|immediate|imm)\b/ ) { |
747
|
0
|
0
|
|
|
|
|
if ( $function =~ /\b(VOLTAGE|VOLT|voltage|volt)\b/ ) { |
748
|
0
|
0
|
|
|
|
|
if ( $self->get_output('STATE') =~ /\b(OFF|off)\b/ ) { |
749
|
0
|
|
|
|
|
|
return $self->_set_voltage($value); |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
else { |
752
|
0
|
|
|
|
|
|
return $self->set_voltage($value); |
753
|
|
|
|
|
|
|
} |
754
|
|
|
|
|
|
|
} |
755
|
|
|
|
|
|
|
else { |
756
|
0
|
|
|
|
|
|
return $self->set_current($value); |
757
|
|
|
|
|
|
|
} |
758
|
|
|
|
|
|
|
} |
759
|
|
|
|
|
|
|
else { |
760
|
0
|
|
|
|
|
|
return $self->query( |
761
|
|
|
|
|
|
|
sprintf( |
762
|
|
|
|
|
|
|
":SOURCE:%s:TRIGGERED %e; TRIGGERED?", |
763
|
|
|
|
|
|
|
$function, $value |
764
|
|
|
|
|
|
|
) |
765
|
|
|
|
|
|
|
); |
766
|
|
|
|
|
|
|
} |
767
|
|
|
|
|
|
|
} |
768
|
|
|
|
|
|
|
else { |
769
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
770
|
|
|
|
|
|
|
"unexpected value in sub _set_source_amplitude. Expected values are between -210.. +210 V or -1.05..+1.05 A" |
771
|
|
|
|
|
|
|
); |
772
|
|
|
|
|
|
|
} |
773
|
|
|
|
|
|
|
} |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
sub set_source_voltagelimit { # advanced settings |
776
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
777
|
0
|
|
|
|
|
|
my $limit = shift; |
778
|
|
|
|
|
|
|
|
779
|
0
|
0
|
0
|
|
|
|
if ( not defined $limit ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
780
|
0
|
|
|
|
|
|
return $self->query(":SOURCE:VOLTAGE:PROTECTION:LIMIT?"); |
781
|
|
|
|
|
|
|
} |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
elsif ( $limit >= -210 and $limit <= 210 ) { |
784
|
0
|
|
|
|
|
|
return $self->query( |
785
|
|
|
|
|
|
|
sprintf( |
786
|
|
|
|
|
|
|
":SOURCE:VOLTAGE:PROTECTION:LIMIT |
787
|
|
|
|
|
|
|
; LIMIT?", $limit |
788
|
|
|
|
|
|
|
) |
789
|
|
|
|
|
|
|
); |
790
|
|
|
|
|
|
|
} |
791
|
|
|
|
|
|
|
elsif ( $limit =~ /\b(NONE|none|MIN|min|MAX|max|DEF|def)\b/ ) { |
792
|
0
|
|
|
|
|
|
return $self->query( |
793
|
|
|
|
|
|
|
sprintf( ":SOURCE:VOLTAGE:PROTECTION:LIMIT %s; LIMIT?", $limit ) |
794
|
|
|
|
|
|
|
); |
795
|
|
|
|
|
|
|
} |
796
|
|
|
|
|
|
|
else { |
797
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
798
|
|
|
|
|
|
|
"unexpected value for VOLTAGE LIMIT in sub set_source_voltagelimit. Expected values are between -210..+210 V." |
799
|
|
|
|
|
|
|
); |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
} |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
sub _set_source_delay { # internal/advanced use only |
805
|
0
|
|
|
0
|
|
|
my $self = shift; |
806
|
0
|
|
|
|
|
|
my $delay = shift; |
807
|
|
|
|
|
|
|
|
808
|
0
|
0
|
|
|
|
|
if ( not defined $delay ) { |
809
|
0
|
|
|
|
|
|
$delay = $self->query(":SOURCE:DELAY?"); |
810
|
0
|
|
|
|
|
|
return chomp $delay; |
811
|
|
|
|
|
|
|
} |
812
|
|
|
|
|
|
|
|
813
|
0
|
0
|
0
|
|
|
|
if ( $delay >= 0 and $delay <= 999.9999 ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
814
|
0
|
|
|
|
|
|
$self->write(":SOURCE:DELAY:AUTO OFF"); |
815
|
0
|
|
|
|
|
|
return $self->query( |
816
|
|
|
|
|
|
|
sprintf( ":SOURCE:DELAY %.4f; :SOURCE:DELAY?", $delay ) ); |
817
|
|
|
|
|
|
|
} |
818
|
|
|
|
|
|
|
elsif ( $delay =~ /\b(MIN|min|MAX|max|DEF|def)\b/ ) { |
819
|
0
|
|
|
|
|
|
$self->write(":SOURCE:DELAY:AUTO OFF"); |
820
|
0
|
|
|
|
|
|
return $self->query( |
821
|
|
|
|
|
|
|
sprintf( ":SOURCE:DELAY %s; :SOURCE:DELAY?", $delay ) ); |
822
|
|
|
|
|
|
|
} |
823
|
|
|
|
|
|
|
elsif ( $delay =~ /\b(AUTO|auto)\b/ ) { |
824
|
0
|
|
|
|
|
|
return $self->query(":SOURCE:DELAY:AUTO ON; :SOURCE:DELAY:AUTO?"); |
825
|
|
|
|
|
|
|
} |
826
|
|
|
|
|
|
|
else { |
827
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
828
|
|
|
|
|
|
|
"unexpected value for DELAY in sub _set_source_delay. Expected values are between 0..999.9999 or AUTO" |
829
|
|
|
|
|
|
|
); |
830
|
|
|
|
|
|
|
} |
831
|
|
|
|
|
|
|
} |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
sub init_source { # |
834
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
835
|
0
|
|
|
|
|
|
my $function = shift; |
836
|
0
|
|
|
|
|
|
my $range = shift; |
837
|
0
|
|
|
|
|
|
my $complience = shift; |
838
|
|
|
|
|
|
|
|
839
|
0
|
|
|
|
|
|
my $sense; |
840
|
0
|
|
|
|
|
|
print "init source ..."; |
841
|
0
|
|
|
|
|
|
$self->set_source_autooutputoff("OFF"); |
842
|
0
|
|
|
|
|
|
$self->set_source_sourcingmode( $function, 'FIXED' ); |
843
|
0
|
|
|
|
|
|
$self->_set_source_delay('DEF'); |
844
|
|
|
|
|
|
|
|
845
|
0
|
0
|
|
|
|
|
if ( $self->set_sense_onfunction() |
846
|
|
|
|
|
|
|
=~ /\b(RESISTANCE|RES|resistance|res)\b/ ) { |
847
|
0
|
|
|
|
|
|
$self->set_sense_resistancemode('MAN'); |
848
|
0
|
|
|
|
|
|
$sense = 'RES'; |
849
|
|
|
|
|
|
|
} |
850
|
0
|
|
|
|
|
|
$self->set_source_mode($function); |
851
|
0
|
0
|
|
|
|
|
$self->set_sense_onfunction( |
852
|
|
|
|
|
|
|
$function =~ /\b(CURRENT|CURR|current|curr)\b/ ? 'VOLT' : 'CURR' ) |
853
|
|
|
|
|
|
|
; # important for always beeing able to set the complience |
854
|
0
|
|
|
|
|
|
$self->set_source_range( $function, $range ); |
855
|
0
|
0
|
|
|
|
|
if ( defined $complience ) { |
856
|
0
|
|
|
|
|
|
$self->set_complience( $function, $complience ); |
857
|
|
|
|
|
|
|
} |
858
|
0
|
0
|
|
|
|
|
if ( defined $sense ) { |
859
|
0
|
|
|
|
|
|
$self->set_sense_onfunction($sense); |
860
|
|
|
|
|
|
|
} |
861
|
0
|
|
|
|
|
|
$self->set_output("ON"); |
862
|
0
|
|
|
|
|
|
print "ok!\n"; |
863
|
0
|
|
|
|
|
|
return; |
864
|
|
|
|
|
|
|
} |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
#--------------!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!------------------------------------------ |
867
|
|
|
|
|
|
|
sub set_source_function { # basic setting |
868
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
869
|
0
|
|
|
|
|
|
my ($function) = $self->_check_args( \@_, ['function'] ); |
870
|
|
|
|
|
|
|
|
871
|
0
|
0
|
0
|
|
|
|
if ( $function =~ /\b(CURRENT|CURR|current|curr)\b/ |
872
|
|
|
|
|
|
|
or $function =~ /\b(VOLTAGE|VOLT|voltage|volt)\b/ ) { |
873
|
0
|
|
|
|
|
|
return $self->query( |
874
|
|
|
|
|
|
|
sprintf( |
875
|
|
|
|
|
|
|
":SOURCE:FUNCTION:MODE %s; :SOURCE:FUNCTION:MODE?", |
876
|
|
|
|
|
|
|
$function |
877
|
|
|
|
|
|
|
) |
878
|
|
|
|
|
|
|
); |
879
|
|
|
|
|
|
|
} |
880
|
|
|
|
|
|
|
else { |
881
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( $self->get_id() |
882
|
|
|
|
|
|
|
. ": unexpected value for MODE in sub set_sourcemode. Expected values are ON, OFF, 1 or 0." |
883
|
|
|
|
|
|
|
); |
884
|
|
|
|
|
|
|
} |
885
|
|
|
|
|
|
|
} |
886
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
sub get_source_function { |
888
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
889
|
|
|
|
|
|
|
|
890
|
0
|
|
|
|
|
|
my $function = $self->query(":SOURCE:FUNCTION:MODE?"); |
891
|
0
|
|
|
|
|
|
chomp $function; |
892
|
0
|
0
|
|
|
|
|
if ( $function eq 'CURR' ) { $function = 'CURRENT'; } |
|
0
|
0
|
|
|
|
|
|
893
|
0
|
|
|
|
|
|
elsif ( $function eq 'VOLT' ) { $function = 'VOLTAGE'; } |
894
|
0
|
|
|
|
|
|
return $function; |
895
|
|
|
|
|
|
|
} |
896
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
sub _set_level { |
898
|
0
|
|
|
0
|
|
|
my $self = shift; |
899
|
0
|
|
|
|
|
|
my ( $value, $function ) |
900
|
|
|
|
|
|
|
= $self->_check_args( \@_, [ 'value', 'function' ] ); |
901
|
|
|
|
|
|
|
|
902
|
0
|
0
|
|
|
|
|
if ( not defined $function ) { |
903
|
0
|
|
|
|
|
|
$function = $self->get_source_function(); |
904
|
|
|
|
|
|
|
} |
905
|
|
|
|
|
|
|
|
906
|
0
|
|
|
|
|
|
$self->write( sprintf( ":SOURCE:$function %3.5f;", $value ) ); |
907
|
|
|
|
|
|
|
} |
908
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
sub get_level { |
910
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
911
|
0
|
|
|
|
|
|
my ($function) = $self->_check_args( \@_, ['function'] ); |
912
|
|
|
|
|
|
|
|
913
|
0
|
0
|
|
|
|
|
if ( not defined $function ) { |
914
|
0
|
|
|
|
|
|
$function = $self->get_source_function(); |
915
|
|
|
|
|
|
|
} |
916
|
|
|
|
|
|
|
|
917
|
0
|
|
|
|
|
|
return $self->query(":SOURCE:$function?"); |
918
|
|
|
|
|
|
|
} |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
sub _sweep_to_level { |
921
|
0
|
|
|
0
|
|
|
my $self = shift; |
922
|
|
|
|
|
|
|
} |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
sub sweep_to_level { |
925
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
926
|
|
|
|
|
|
|
|
927
|
0
|
|
|
|
|
|
$self->config_sweep(@_); |
928
|
0
|
|
|
|
|
|
$self->trg(); |
929
|
0
|
|
|
|
|
|
$self->wait(); |
930
|
|
|
|
|
|
|
} |
931
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
sub config_sweep { |
933
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
934
|
0
|
|
|
|
|
|
my ( $target, $time, $rate, $function ) |
935
|
|
|
|
|
|
|
= $self->_check_args( \@_, [ 'points', 'time', 'rate', 'function' ] ); |
936
|
|
|
|
|
|
|
|
937
|
0
|
|
|
|
|
|
$self->{armed} = 0; |
938
|
|
|
|
|
|
|
|
939
|
0
|
0
|
|
|
|
|
if ( not defined $function ) { |
940
|
0
|
|
|
|
|
|
$function = $self->get_source_function(); |
941
|
|
|
|
|
|
|
} |
942
|
|
|
|
|
|
|
|
943
|
0
|
0
|
|
|
|
|
if ( not $self->get_output() ) { |
944
|
0
|
|
|
|
|
|
Lab::Exception::Error->throw( error => $self->get_id() |
945
|
|
|
|
|
|
|
. " :Can't configure a sweep when output is off!" ); |
946
|
|
|
|
|
|
|
} |
947
|
|
|
|
|
|
|
|
948
|
0
|
|
|
|
|
|
my $nplc_max = 10; |
949
|
0
|
|
|
|
|
|
my $points_max |
950
|
|
|
|
|
|
|
= 2500; # maximum possible number of points, see manual 5.66 |
951
|
|
|
|
|
|
|
|
952
|
0
|
|
|
|
|
|
my $start = $self->get_level($function); |
953
|
|
|
|
|
|
|
|
954
|
0
|
0
|
0
|
|
|
|
if ( defined $time and defined $rate ) { |
|
|
0
|
0
|
|
|
|
|
955
|
0
|
|
|
|
|
|
croak('Please give either a time OR rate. Not both!'); |
956
|
|
|
|
|
|
|
} |
957
|
|
|
|
|
|
|
elsif ( defined $rate and not defined $time ) { |
958
|
0
|
|
|
|
|
|
$time = abs( $start - $target ) / $rate; |
959
|
|
|
|
|
|
|
} |
960
|
|
|
|
|
|
|
|
961
|
0
|
0
|
|
|
|
|
if ( $target == $start ) { return; } |
|
0
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
|
963
|
0
|
|
|
|
|
|
my $points; |
964
|
|
|
|
|
|
|
|
965
|
0
|
|
|
|
|
|
$self->set_sense_nplc(0.01); |
966
|
|
|
|
|
|
|
|
967
|
0
|
|
|
|
|
|
my $points = int( $time / ( 0.01 / 50 ) ); |
968
|
0
|
|
|
|
|
|
my $delay = 0; |
969
|
|
|
|
|
|
|
|
970
|
0
|
0
|
|
|
|
|
if ( $points > $points_max ) { |
971
|
0
|
|
|
|
|
|
$points = $points_max; |
972
|
|
|
|
|
|
|
|
973
|
0
|
|
|
|
|
|
$delay = ( $time / $points ) - ( 0.01 / 50 ); |
974
|
|
|
|
|
|
|
} |
975
|
|
|
|
|
|
|
|
976
|
0
|
|
|
|
|
|
my $t0 = time; |
977
|
0
|
|
|
|
|
|
$self->write("SOURCE:SWEEP:DIRECTION UP"); |
978
|
|
|
|
|
|
|
|
979
|
0
|
|
|
|
|
|
$self->write("SOUR:SWE:SPAC LIN"); |
980
|
|
|
|
|
|
|
|
981
|
0
|
|
|
|
|
|
$self->write( sprintf( "SOUR:%s:STAR %3.5f", $function, $start ) ); |
982
|
|
|
|
|
|
|
|
983
|
0
|
|
|
|
|
|
$self->write( sprintf( "SOUR:%s:STOP %3.5f", $function, $target ) ); |
984
|
|
|
|
|
|
|
|
985
|
0
|
|
|
|
|
|
$self->write("SOUR:SWE:POIN $points"); |
986
|
|
|
|
|
|
|
|
987
|
0
|
|
|
|
|
|
$self->write( sprintf( "SOUR:DEL %3.4f", $delay ) ); |
988
|
|
|
|
|
|
|
|
989
|
0
|
|
|
|
|
|
$self->write("TRIG:COUN $points"); |
990
|
|
|
|
|
|
|
|
991
|
0
|
|
|
|
|
|
$self->{armed} = 1; |
992
|
|
|
|
|
|
|
|
993
|
0
|
|
|
|
|
|
my $t1 = time; |
994
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
#print "TIME TO PROGRAM: ".($t1-$t0)."\n"; |
996
|
|
|
|
|
|
|
} |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
sub trg { # basic setting |
999
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
1000
|
0
|
0
|
|
|
|
|
if ( !$self->{armed} ) { return; } |
|
0
|
|
|
|
|
|
|
1001
|
|
|
|
|
|
|
|
1002
|
0
|
|
|
|
|
|
my $function = $self->get_source_function(); |
1003
|
0
|
|
|
|
|
|
$self->write("SOUR:$function:MODE SWE"); |
1004
|
0
|
|
|
|
|
|
$self->write(":INITIATE:IMMEDIATE"); |
1005
|
|
|
|
|
|
|
} |
1006
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
sub wait { # basic |
1008
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
1009
|
0
|
|
|
|
|
|
my $timeout = shift; |
1010
|
|
|
|
|
|
|
|
1011
|
0
|
0
|
|
|
|
|
if ( not defined $timeout ) { |
1012
|
0
|
|
|
|
|
|
$timeout = 100; |
1013
|
|
|
|
|
|
|
} |
1014
|
|
|
|
|
|
|
|
1015
|
|
|
|
|
|
|
#my $status=Lab::VISA::viSetAttribute($self->{vi}->{instr}, $Lab::VISA::VI_ATTR_TMO_VALUE, $timeout); |
1016
|
|
|
|
|
|
|
#if ($status != $Lab::VISA::VI_SUCCESS) { Lab::Exception::CorruptParameter->throw("Error while setting baud: $status");} |
1017
|
|
|
|
|
|
|
|
1018
|
0
|
|
|
|
|
|
print "waiting for data ... \n"; |
1019
|
0
|
|
|
|
|
|
while ( $self->active() ) { |
1020
|
0
|
|
|
|
|
|
usleep(1e3); |
1021
|
|
|
|
|
|
|
} |
1022
|
|
|
|
|
|
|
|
1023
|
|
|
|
|
|
|
#my $status=Lab::VISA::viSetAttribute($self->{vi}->{instr}, $Lab::VISA::VI_ATTR_TMO_VALUE, 3000); |
1024
|
|
|
|
|
|
|
#if ($status != $Lab::VISA::VI_SUCCESS) { Lab::Exception::CorruptParameter->throw("Error while setting baud: $status");} |
1025
|
|
|
|
|
|
|
} |
1026
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
sub active { # basic |
1028
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
1029
|
0
|
|
|
|
|
|
my $timeout = shift; |
1030
|
|
|
|
|
|
|
|
1031
|
0
|
0
|
|
|
|
|
if ( not defined $timeout ) { |
1032
|
0
|
|
|
|
|
|
$timeout = 100; |
1033
|
|
|
|
|
|
|
} |
1034
|
|
|
|
|
|
|
|
1035
|
|
|
|
|
|
|
# check if measurement has been finished |
1036
|
0
|
0
|
|
|
|
|
if ( $self->query( ":STATUS:OPERATION:CONDITION?", { timeout => 100 } ) |
1037
|
|
|
|
|
|
|
>= 1024 ) { |
1038
|
0
|
|
|
|
|
|
$self->{armed} = 0; |
1039
|
0
|
|
|
|
|
|
my $current_level = $self->get_level(); |
1040
|
0
|
|
|
|
|
|
my $function = $self->get_source_function(); |
1041
|
|
|
|
|
|
|
|
1042
|
0
|
|
|
|
|
|
$self->clear_sweep(); |
1043
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
#$self->write("SOURCE:SWEEP:DIRECTION DOWN"); |
1045
|
|
|
|
|
|
|
|
1046
|
0
|
|
|
|
|
|
return 0; |
1047
|
|
|
|
|
|
|
} |
1048
|
|
|
|
|
|
|
else { |
1049
|
0
|
|
|
|
|
|
return 1; |
1050
|
|
|
|
|
|
|
} |
1051
|
|
|
|
|
|
|
} |
1052
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
# -------------------------------------- CONFIG MEASUREMNT and SOURCE SWEEP -------------------------------- |
1054
|
|
|
|
|
|
|
# |
1055
|
|
|
|
|
|
|
# |
1056
|
|
|
|
|
|
|
# sweep is working, but you can't define the duration of the sweep properly when performing also measurements. |
1057
|
|
|
|
|
|
|
# If no ONFUNCTIONS are defined, the duration of the sweep is well defined. |
1058
|
|
|
|
|
|
|
# |
1059
|
|
|
|
|
|
|
# |
1060
|
|
|
|
|
|
|
# In the case of doing source-measurement-sweeps, the duration of the sweep is enlarged and depends on the settings like ... |
1061
|
|
|
|
|
|
|
# The number of points per sweep as well as the integration time (NPLC) give a nonlinear contribution to the total duration of the sweep. |
1062
|
|
|
|
|
|
|
# It alo depends on the number of ONFUNCTIONS. |
1063
|
|
|
|
|
|
|
# Example: Points = 2500, NPLC = 0.01, averaging = OFF, all other delays for source and trigger are set to 0 |
1064
|
|
|
|
|
|
|
# --> sweep takes 9 sec --> 2500 x NPLC/50Hz = 0.5 sec |
1065
|
|
|
|
|
|
|
# Points = 2500, NPLC = 0.02, averaging = OFF, all other delays for source and trigger are set to 0 |
1066
|
|
|
|
|
|
|
# --> sweep takes 11 sec --> 2500 x NPLC/50Hz = 1.0 sec |
1067
|
|
|
|
|
|
|
# Points = 2500, NPLC = 0.10, averaging = OFF, all other delays for source and trigger are set to 0 |
1068
|
|
|
|
|
|
|
# --> sweep takes 37 sec --> 2500 x NPLC/50Hz = 5.0 sec |
1069
|
|
|
|
|
|
|
# Points = 2500, NPLC = 1.00, averaging = OFF, all other delays for source and trigger are set to 0 |
1070
|
|
|
|
|
|
|
# --> sweep takes 158 sec --> 2500 x NPLC/50Hz = 50.0 sec |
1071
|
|
|
|
|
|
|
# It is similar when choosing e.g. 1000 Points. Maybe you won't see the Problem when choosing only 100 points. |
1072
|
|
|
|
|
|
|
# |
1073
|
|
|
|
|
|
|
# BUT: Where does the difference come from ??? |
1074
|
|
|
|
|
|
|
# |
1075
|
|
|
|
|
|
|
# It's the same when performing only a triggered measurment operation. |
1076
|
|
|
|
|
|
|
# |
1077
|
|
|
|
|
|
|
|
1078
|
|
|
|
|
|
|
sub get_value { # basic setting |
1079
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
1080
|
0
|
|
|
|
|
|
my ( $function, $read_mode ) |
1081
|
|
|
|
|
|
|
= $self->_check_args( \@_, [ 'function', 'read_mode' ] ); |
1082
|
0
|
|
|
|
|
|
my $result; |
1083
|
0
|
|
|
|
|
|
$result = $self->write(":TRIG:COUN 1"); |
1084
|
0
|
0
|
|
|
|
|
if ( not defined $function ) { |
|
|
0
|
|
|
|
|
|
1085
|
0
|
|
|
|
|
|
$result = $self->device_cache()->{value} = $self->query(':READ?'); |
1086
|
|
|
|
|
|
|
} |
1087
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
elsif ( $function |
1089
|
|
|
|
|
|
|
=~ /\b(CURRENT|current|CURR|curr|VOLTAGE|voltage|VOLT|volt|RESISTANCE|resistance|RES|res)\b/ |
1090
|
|
|
|
|
|
|
) { |
1091
|
0
|
|
|
|
|
|
$result = $self->query( ":MEASURE:" . $function . "?" ); |
1092
|
|
|
|
|
|
|
} |
1093
|
|
|
|
|
|
|
else { |
1094
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1095
|
|
|
|
|
|
|
"unexpected value for 'function' in sub get_value. Function can be CURRENT:AC, CURRENT:DC, VOLTAGE:AC, VOLTAGE:DC, RESISTANCE, FRESISTANCE, PERIOD, FREQUENCY, TEMPERATURE, DIODE" |
1096
|
|
|
|
|
|
|
); |
1097
|
|
|
|
|
|
|
} |
1098
|
|
|
|
|
|
|
|
1099
|
0
|
|
|
|
|
|
my @result = split( /,/, $result ); |
1100
|
0
|
|
|
|
|
|
return $self->device_cache()->{value} = $result[1]; |
1101
|
|
|
|
|
|
|
} |
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
sub config_measurement { # |
1104
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
1105
|
0
|
|
|
|
|
|
my $function = shift; |
1106
|
0
|
|
|
|
|
|
my $nop = shift; |
1107
|
0
|
|
|
|
|
|
my $time = shift; |
1108
|
0
|
|
|
|
|
|
my $range = shift; |
1109
|
|
|
|
|
|
|
|
1110
|
0
|
0
|
|
|
|
|
if ( not defined $range ) { |
1111
|
0
|
|
|
|
|
|
$range = "AUTO"; |
1112
|
|
|
|
|
|
|
} |
1113
|
|
|
|
|
|
|
|
1114
|
0
|
|
|
|
|
|
$self->set_sense_onfunction($function); |
1115
|
|
|
|
|
|
|
|
1116
|
0
|
0
|
|
|
|
|
if ( $function =~ /\b(RESISTANCE|RES|resistance|res)\b/ ) { |
1117
|
0
|
|
|
|
|
|
$self->set_sense_resistancemode('MAN'); |
1118
|
0
|
|
|
|
|
|
$self->set_sense_resistance_zerocompensated('OFF'); |
1119
|
|
|
|
|
|
|
} |
1120
|
|
|
|
|
|
|
|
1121
|
0
|
0
|
|
|
|
|
if ( $function eq $self->set_source_mode() ) { |
|
|
0
|
|
|
|
|
|
1122
|
0
|
|
|
|
|
|
$self->set_source_range( $self->set_source_mode(), $range ); |
1123
|
|
|
|
|
|
|
} |
1124
|
|
|
|
|
|
|
elsif ( $function =~ /\b(ALL|all)\b/ ) { |
1125
|
0
|
|
|
|
|
|
$self->set_source_range( $self->set_source_mode(), $range ); |
1126
|
|
|
|
|
|
|
} |
1127
|
|
|
|
|
|
|
else { |
1128
|
0
|
0
|
|
|
|
|
if ( $range <= $self->set_complience() ) { |
1129
|
0
|
|
|
|
|
|
$self->set_sense_range( $function, $range ); |
1130
|
|
|
|
|
|
|
} |
1131
|
|
|
|
|
|
|
else { |
1132
|
0
|
|
|
|
|
|
$self->set_sense_range( $function, $self->set_complience() ); |
1133
|
|
|
|
|
|
|
} |
1134
|
|
|
|
|
|
|
} |
1135
|
|
|
|
|
|
|
|
1136
|
0
|
|
|
|
|
|
my $nplc = ( $time * 50 ) / $nop; |
1137
|
0
|
0
|
|
|
|
|
if ( $nplc < 0.01 ) { |
1138
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1139
|
|
|
|
|
|
|
"unexpected value for TIME in sub config_measurement. Expected values are between 0.21 ... 20000 sec." |
1140
|
|
|
|
|
|
|
); |
1141
|
|
|
|
|
|
|
} |
1142
|
0
|
|
|
|
|
|
print "nplc = " . $self->set_sense_nplc($nplc) . "\n"; |
1143
|
0
|
|
|
|
|
|
$self->_set_source_delay(0); |
1144
|
0
|
|
|
|
|
|
$self->_set_trigger_delay(0); |
1145
|
|
|
|
|
|
|
|
1146
|
0
|
|
|
|
|
|
$self->_init_buffer($nop); |
1147
|
|
|
|
|
|
|
} |
1148
|
|
|
|
|
|
|
|
1149
|
|
|
|
|
|
|
sub clear_sweep { # |
1150
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
1151
|
0
|
|
|
|
|
|
my $function = $self->get_source_function(); |
1152
|
0
|
|
|
|
|
|
$self->write("SOURCE:$function:MODE FIX"); |
1153
|
|
|
|
|
|
|
} |
1154
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
sub config_sweep2 { # basic setting |
1156
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
1157
|
0
|
|
|
|
|
|
my $stop = shift; |
1158
|
0
|
|
|
|
|
|
my $nop = shift; |
1159
|
0
|
|
|
|
|
|
my $time = shift; |
1160
|
|
|
|
|
|
|
|
1161
|
0
|
0
|
|
|
|
|
if ( $time >= 2 ) { |
1162
|
0
|
|
|
|
|
|
$time = $time - 2 |
1163
|
|
|
|
|
|
|
; # this is a correction, because a typical sweep alwas takes 2 seconds longer than programmed. Reason unknown! |
1164
|
|
|
|
|
|
|
} |
1165
|
|
|
|
|
|
|
else { |
1166
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1167
|
|
|
|
|
|
|
"unexpected value for TIME in sub config_sweep. Expected values are between 2 ... 9999." |
1168
|
|
|
|
|
|
|
); |
1169
|
|
|
|
|
|
|
} |
1170
|
|
|
|
|
|
|
|
1171
|
0
|
|
|
|
|
|
my $function = $self->query(":SOURCE:FUNCTION:MODE?"); |
1172
|
0
|
|
|
|
|
|
chomp $function; |
1173
|
|
|
|
|
|
|
|
1174
|
0
|
|
|
|
|
|
print "set output = " . $self->set_output("ON") . "\n"; |
1175
|
0
|
|
|
|
|
|
my $start = $self->_set_source_amplitude(); |
1176
|
|
|
|
|
|
|
|
1177
|
0
|
|
|
|
|
|
print "--- config SWEEP ----\n"; |
1178
|
0
|
|
|
|
|
|
print "start = " . $self->_set_sweep_start($start); |
1179
|
0
|
0
|
|
|
|
|
if ( $start != $self->_set_source_amplitude() ) { |
1180
|
0
|
|
|
|
|
|
$self->_set_source_amplitude($start); |
1181
|
|
|
|
|
|
|
} |
1182
|
0
|
|
|
|
|
|
print "stop = " . $self->_set_sweep_stop($stop); |
1183
|
0
|
|
|
|
|
|
print "nop = " . $self->_set_sweep_nop($nop); |
1184
|
0
|
|
|
|
|
|
print "step = " . $self->query(":SOURCE:$function:STEP?") . "\n"; |
1185
|
|
|
|
|
|
|
|
1186
|
0
|
|
|
|
|
|
print "source_delay = " . $self->_set_source_delay( ($time) / $nop ); |
1187
|
0
|
|
|
|
|
|
print "trigger_delay = " . $self->_set_trigger_delay(0); |
1188
|
0
|
|
|
|
|
|
print "integrationtime = "; |
1189
|
0
|
|
|
|
|
|
my $tc = $self->set_sense_nplc(10) / 50; |
1190
|
0
|
|
|
|
|
|
print "$tc\n\n"; |
1191
|
|
|
|
|
|
|
|
1192
|
0
|
|
|
|
|
|
print "set_sourcingmode: " |
1193
|
|
|
|
|
|
|
. $self->set_source_sourcingmode( $function, "SWEEP" ); |
1194
|
0
|
|
|
|
|
|
print "ranging = " . $self->_set_sweep_ranging('FIXED'); |
1195
|
0
|
|
|
|
|
|
print "spacing = " . $self->_set_sweep_spacing('LIN'); |
1196
|
0
|
|
|
|
|
|
print "set ONFUNCTIONS = " . $self->set_sense_onfunction('OFF'); |
1197
|
0
|
|
|
|
|
|
print "set sourc mode = " . $self->set_source_mode($function); |
1198
|
|
|
|
|
|
|
|
1199
|
0
|
|
|
|
|
|
print "init BUFFER: " . $self->_init_buffer($nop) . "\n"; |
1200
|
|
|
|
|
|
|
|
1201
|
0
|
|
|
|
|
|
print "ready to SWEEP\n"; |
1202
|
|
|
|
|
|
|
} |
1203
|
|
|
|
|
|
|
|
1204
|
|
|
|
|
|
|
sub config_IV { # basic setting |
1205
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
1206
|
0
|
|
|
|
|
|
my $start = shift; |
1207
|
0
|
|
|
|
|
|
my $stop = shift; |
1208
|
0
|
|
|
|
|
|
my $nop = shift; |
1209
|
0
|
|
|
|
|
|
my $nplc = shift; |
1210
|
0
|
|
|
|
|
|
my $ranging = shift; |
1211
|
0
|
|
|
|
|
|
my $spacing = shift; |
1212
|
|
|
|
|
|
|
|
1213
|
|
|
|
|
|
|
# check DATA |
1214
|
0
|
0
|
|
|
|
|
if ( not defined $spacing ) { |
1215
|
0
|
|
|
|
|
|
$spacing = 'LIN'; |
1216
|
|
|
|
|
|
|
} |
1217
|
0
|
0
|
|
|
|
|
if ( not defined $ranging ) { |
1218
|
0
|
|
|
|
|
|
$ranging = 'FIXED'; |
1219
|
|
|
|
|
|
|
} |
1220
|
0
|
0
|
|
|
|
|
if ( not defined $nplc ) { |
1221
|
0
|
|
|
|
|
|
$nplc = 1; |
1222
|
|
|
|
|
|
|
} |
1223
|
0
|
0
|
|
|
|
|
if ( not defined $nop ) { |
1224
|
0
|
|
|
|
|
|
$nop = 2500; |
1225
|
|
|
|
|
|
|
} |
1226
|
|
|
|
|
|
|
|
1227
|
|
|
|
|
|
|
# config SWEPP parameters |
1228
|
0
|
|
|
|
|
|
print "\n--- config SWEEP ----\n"; |
1229
|
|
|
|
|
|
|
|
1230
|
0
|
|
|
|
|
|
print "set sourc mode = " . $self->set_source_mode('VOLT'); |
1231
|
0
|
|
|
|
|
|
print "set ONFUNCTIONS = " . $self->set_sense_onfunction('CURR,VOLT'); |
1232
|
0
|
|
|
|
|
|
print "set output = " . $self->set_output("ON") . "\n"; |
1233
|
|
|
|
|
|
|
|
1234
|
0
|
|
|
|
|
|
print "start = " . $self->_set_sweep_start($start); |
1235
|
0
|
0
|
|
|
|
|
if ( $start != $self->_set_source_amplitude() ) { |
1236
|
0
|
|
|
|
|
|
$self->_set_source_amplitude($start); |
1237
|
|
|
|
|
|
|
} |
1238
|
0
|
|
|
|
|
|
print "stop = " . $self->_set_sweep_stop($stop); |
1239
|
0
|
|
|
|
|
|
print "nop = " . $self->_set_sweep_nop($nop); |
1240
|
0
|
|
|
|
|
|
print "step = " . $self->query(":SOURCE:VOLT:STEP?") . "\n"; |
1241
|
|
|
|
|
|
|
|
1242
|
0
|
|
|
|
|
|
print "source_delay = " . $self->_set_source_delay(0); |
1243
|
0
|
|
|
|
|
|
print "trigger_delay = " . $self->_set_trigger_delay(0); |
1244
|
0
|
|
|
|
|
|
print "integrationtime = "; |
1245
|
0
|
|
|
|
|
|
my $tc = $self->set_sense_nplc($nplc) / 50; |
1246
|
0
|
|
|
|
|
|
print "$tc\n\n"; |
1247
|
|
|
|
|
|
|
|
1248
|
0
|
|
|
|
|
|
print "set_sourcingmode: " |
1249
|
|
|
|
|
|
|
. $self->set_source_sourcingmode( 'VOLT', "SWEEP" ); |
1250
|
0
|
|
|
|
|
|
print "ranging = " . $self->_set_sweep_ranging($ranging); |
1251
|
0
|
|
|
|
|
|
print "spacing = " . $self->_set_sweep_spacing($spacing); |
1252
|
0
|
|
|
|
|
|
print "init BUFFER: " . $self->_init_buffer($nop) . "\n"; |
1253
|
|
|
|
|
|
|
|
1254
|
0
|
|
|
|
|
|
print "ready to record an IV-trace.\n"; |
1255
|
|
|
|
|
|
|
} |
1256
|
|
|
|
|
|
|
|
1257
|
|
|
|
|
|
|
sub config_VI { # basic setting |
1258
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
1259
|
0
|
|
|
|
|
|
my $start = shift; |
1260
|
0
|
|
|
|
|
|
my $stop = shift; |
1261
|
0
|
|
|
|
|
|
my $nop = shift; |
1262
|
0
|
|
|
|
|
|
my $nplc = shift; |
1263
|
0
|
|
|
|
|
|
my $ranging = shift; |
1264
|
0
|
|
|
|
|
|
my $spacing = shift; |
1265
|
|
|
|
|
|
|
|
1266
|
|
|
|
|
|
|
# check DATA |
1267
|
0
|
0
|
|
|
|
|
if ( not defined $spacing ) { |
1268
|
0
|
|
|
|
|
|
$spacing = 'LIN'; |
1269
|
|
|
|
|
|
|
} |
1270
|
0
|
0
|
|
|
|
|
if ( not defined $ranging ) { |
1271
|
0
|
|
|
|
|
|
$ranging = 'FIXED'; |
1272
|
|
|
|
|
|
|
} |
1273
|
0
|
0
|
|
|
|
|
if ( not defined $nplc ) { |
1274
|
0
|
|
|
|
|
|
$nplc = 1; |
1275
|
|
|
|
|
|
|
} |
1276
|
0
|
0
|
|
|
|
|
if ( not defined $nop ) { |
1277
|
0
|
|
|
|
|
|
$nop = 2500; |
1278
|
|
|
|
|
|
|
} |
1279
|
|
|
|
|
|
|
|
1280
|
|
|
|
|
|
|
# config SWEPP parameters |
1281
|
0
|
|
|
|
|
|
print "\n--- config SWEEP ----\n"; |
1282
|
|
|
|
|
|
|
|
1283
|
0
|
|
|
|
|
|
print "set sourc mode = " . $self->set_source_mode('CURR'); |
1284
|
0
|
|
|
|
|
|
print "set ONFUNCTIONS = " . $self->set_sense_onfunction('VOLT,CURR'); |
1285
|
0
|
|
|
|
|
|
print "set output = " . $self->set_output("ON") . "\n"; |
1286
|
|
|
|
|
|
|
|
1287
|
0
|
|
|
|
|
|
print "start = " . $self->_set_sweep_start($start); |
1288
|
0
|
0
|
|
|
|
|
if ( $start != $self->_set_source_amplitude() ) { |
1289
|
0
|
|
|
|
|
|
$self->_set_source_amplitude($start); |
1290
|
|
|
|
|
|
|
} |
1291
|
0
|
|
|
|
|
|
print "stop = " . $self->_set_sweep_stop($stop); |
1292
|
0
|
|
|
|
|
|
print "nop = " . $self->_set_sweep_nop($nop); |
1293
|
0
|
|
|
|
|
|
print "step = " . $self->query(":SOURCE:CURR:STEP?") . "\n"; |
1294
|
|
|
|
|
|
|
|
1295
|
0
|
|
|
|
|
|
print "source_delay = " . $self->_set_source_delay(0); |
1296
|
0
|
|
|
|
|
|
print "trigger_delay = " . $self->_set_trigger_delay(0); |
1297
|
0
|
|
|
|
|
|
print "integrationtime = "; |
1298
|
0
|
|
|
|
|
|
my $tc = $self->set_sense_nplc($nplc) / 50; |
1299
|
0
|
|
|
|
|
|
print "$tc\n\n"; |
1300
|
|
|
|
|
|
|
|
1301
|
0
|
|
|
|
|
|
print "set_sourcingmode: " |
1302
|
|
|
|
|
|
|
. $self->set_source_sourcingmode( 'CURR', "SWEEP" ); |
1303
|
0
|
|
|
|
|
|
print "ranging = " . $self->_set_sweep_ranging($ranging); |
1304
|
0
|
|
|
|
|
|
print "spacing = " . $self->_set_sweep_spacing($spacing); |
1305
|
|
|
|
|
|
|
|
1306
|
0
|
|
|
|
|
|
print "init BUFFER: " . $self->_init_buffer($nop) . "\n"; |
1307
|
|
|
|
|
|
|
|
1308
|
0
|
|
|
|
|
|
print "ready to record an VI-trace.\n"; |
1309
|
|
|
|
|
|
|
} |
1310
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
sub get_data { # basic setting |
1312
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
1313
|
0
|
|
|
|
|
|
my @data = $self->_read_buffer(); |
1314
|
0
|
|
|
|
|
|
$self->_clear_buffer(); |
1315
|
0
|
|
|
|
|
|
$self->write(':TRIGGER:CLEAR'); |
1316
|
0
|
|
|
|
|
|
$self->write( sprintf( ":TRIGGER:COUNT %d", 1 ) ); |
1317
|
0
|
|
|
|
|
|
return @data; |
1318
|
|
|
|
|
|
|
} |
1319
|
|
|
|
|
|
|
|
1320
|
|
|
|
|
|
|
sub abort { # basic |
1321
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
1322
|
0
|
|
|
|
|
|
$self->write(":ABORT"); |
1323
|
|
|
|
|
|
|
} |
1324
|
|
|
|
|
|
|
|
1325
|
|
|
|
|
|
|
sub _set_sweep_ranging { # internal/advanced use only |
1326
|
0
|
|
|
0
|
|
|
my $self = shift; |
1327
|
0
|
|
|
|
|
|
my $ranging = shift; |
1328
|
|
|
|
|
|
|
|
1329
|
0
|
0
|
|
|
|
|
if ( $ranging =~ /\b(BEST|best|FIXED|FIX|fixed|fix|AUTO|auto)\b/ ) { |
1330
|
0
|
|
|
|
|
|
return $self->query( |
1331
|
|
|
|
|
|
|
sprintf( |
1332
|
|
|
|
|
|
|
":SOURCE:SWEEP:RANGING %s; :SOURCE:SWEEP:RANGING?", |
1333
|
|
|
|
|
|
|
$ranging |
1334
|
|
|
|
|
|
|
) |
1335
|
|
|
|
|
|
|
); |
1336
|
|
|
|
|
|
|
} |
1337
|
|
|
|
|
|
|
else { |
1338
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1339
|
|
|
|
|
|
|
"unexpected vlaue for RANGING in sub _set_sweep_ranging. Expected values are BEST, FIXED or AUTO." |
1340
|
|
|
|
|
|
|
); |
1341
|
|
|
|
|
|
|
} |
1342
|
|
|
|
|
|
|
} |
1343
|
|
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
sub _set_sweep_spacing { # internal/advanced use only |
1345
|
0
|
|
|
0
|
|
|
my $self = shift; |
1346
|
0
|
|
|
|
|
|
my $spacing = shift; |
1347
|
|
|
|
|
|
|
|
1348
|
0
|
0
|
|
|
|
|
if ( $spacing |
1349
|
|
|
|
|
|
|
=~ /\b(LINEAR|LIN|linear|lin|LOGARITHMIC|LOG|logarithmic|log)\b/ ) { |
1350
|
0
|
|
|
|
|
|
return $self->query( |
1351
|
|
|
|
|
|
|
sprintf( |
1352
|
|
|
|
|
|
|
":SOURCE:SWEEP:SPACING %s; :SOURCE:SWEEP:SPACING?", |
1353
|
|
|
|
|
|
|
$spacing |
1354
|
|
|
|
|
|
|
) |
1355
|
|
|
|
|
|
|
); |
1356
|
|
|
|
|
|
|
} |
1357
|
|
|
|
|
|
|
else { |
1358
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1359
|
|
|
|
|
|
|
"unexpected vlaue for SPACING in sub set_sweep_spaceing. Expected values are LIN or LOG." |
1360
|
|
|
|
|
|
|
); |
1361
|
|
|
|
|
|
|
} |
1362
|
|
|
|
|
|
|
} |
1363
|
|
|
|
|
|
|
|
1364
|
|
|
|
|
|
|
sub _set_sweep_start { # internal/advanced use only |
1365
|
0
|
|
|
0
|
|
|
my $self = shift; |
1366
|
0
|
|
|
|
|
|
my $function = shift; |
1367
|
0
|
|
|
|
|
|
my $start = shift; |
1368
|
|
|
|
|
|
|
|
1369
|
0
|
0
|
0
|
|
|
|
if ( not defined $start and $function >= -210 and $function <= 210 ) { |
|
|
|
0
|
|
|
|
|
1370
|
0
|
|
|
|
|
|
$start = $function; |
1371
|
0
|
|
|
|
|
|
$function = $self->query(":SOURCE:FUNCTION:MODE?"); |
1372
|
0
|
|
|
|
|
|
chomp $function; |
1373
|
|
|
|
|
|
|
} |
1374
|
|
|
|
|
|
|
else { |
1375
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1376
|
|
|
|
|
|
|
"unexpected value in sub _set_sweep_start. Expected values are between -210.. +210 V or -1.05..+1.05 A" |
1377
|
|
|
|
|
|
|
); |
1378
|
|
|
|
|
|
|
} |
1379
|
|
|
|
|
|
|
|
1380
|
0
|
0
|
0
|
|
|
|
if ( $function =~ /\b(CURRENT|CURR|current|curr)\b/ |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1381
|
|
|
|
|
|
|
and ( $start < -1.05 or $start > 1.05 ) ) { |
1382
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1383
|
|
|
|
|
|
|
"unexpected value in sub _set_sweep_start. Expected values are between -1.05 and 1.05." |
1384
|
|
|
|
|
|
|
); |
1385
|
|
|
|
|
|
|
} |
1386
|
|
|
|
|
|
|
elsif ( $function =~ /\b(VOLTAGE|VOLT|voltage|volt)\b/ |
1387
|
|
|
|
|
|
|
and ( $start < -210 or $start > 210 ) ) { |
1388
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1389
|
|
|
|
|
|
|
"unexpected value in sub _set_sweep_start. Expected values are between -210 and 210." |
1390
|
|
|
|
|
|
|
); |
1391
|
|
|
|
|
|
|
} |
1392
|
|
|
|
|
|
|
elsif ($function =~ /\b(VOLTAGE|VOLT|voltage|volt)\b/ |
1393
|
|
|
|
|
|
|
or $function =~ /\b(CURRENT|CURR|current|curr)\b/ ) { |
1394
|
|
|
|
|
|
|
|
1395
|
|
|
|
|
|
|
# set startvalue for sweep |
1396
|
0
|
|
|
|
|
|
return $self->query( |
1397
|
|
|
|
|
|
|
sprintf( |
1398
|
|
|
|
|
|
|
":SOURCE:%s:START %.11f; :SOURCE:%s:START?", |
1399
|
|
|
|
|
|
|
$function, $start, $function |
1400
|
|
|
|
|
|
|
) |
1401
|
|
|
|
|
|
|
); |
1402
|
|
|
|
|
|
|
} |
1403
|
|
|
|
|
|
|
else { |
1404
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1405
|
|
|
|
|
|
|
"unexpected value in sub _set_sweep_start. Function can be CURRENT or VOLTAGE, startvalue is expected to be between -1.05...+1.05A or -210...+210V" |
1406
|
|
|
|
|
|
|
); |
1407
|
|
|
|
|
|
|
} |
1408
|
|
|
|
|
|
|
} |
1409
|
|
|
|
|
|
|
|
1410
|
|
|
|
|
|
|
sub _set_sweep_stop { # internal/advanced use only |
1411
|
0
|
|
|
0
|
|
|
my $self = shift; |
1412
|
0
|
|
|
|
|
|
my $function = shift; |
1413
|
0
|
|
|
|
|
|
my $stop = shift; |
1414
|
|
|
|
|
|
|
|
1415
|
0
|
0
|
0
|
|
|
|
if ( not defined $stop and $function >= -210 and $function <= 210 ) { |
|
|
|
0
|
|
|
|
|
1416
|
0
|
|
|
|
|
|
$stop = $function; |
1417
|
0
|
|
|
|
|
|
$function = $self->query(":SOURCE:FUNCTION:MODE?"); |
1418
|
0
|
|
|
|
|
|
chomp $function; |
1419
|
|
|
|
|
|
|
} |
1420
|
|
|
|
|
|
|
else { |
1421
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1422
|
|
|
|
|
|
|
"unexpected value in sub _set_sweep_stop. Expected values are between -210.. +210 V or -1.05..+1.05 A" |
1423
|
|
|
|
|
|
|
); |
1424
|
|
|
|
|
|
|
} |
1425
|
|
|
|
|
|
|
|
1426
|
0
|
0
|
0
|
|
|
|
if ( $function =~ /\b(CURRENT|CURR|current|curr)\b/ |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1427
|
|
|
|
|
|
|
and ( $stop < -1.05 or $stop > 1.05 ) ) { |
1428
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1429
|
|
|
|
|
|
|
"unexpected value in sub _set_sweep_start. Expected values are between -1.05 and 1.05." |
1430
|
|
|
|
|
|
|
); |
1431
|
|
|
|
|
|
|
} |
1432
|
|
|
|
|
|
|
elsif ( $function =~ /\b(VOLTAGE|VOLT|voltage|volt)\b/ |
1433
|
|
|
|
|
|
|
and ( $stop < -210 or $stop > 210 ) ) { |
1434
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1435
|
|
|
|
|
|
|
"unexpected value in sub _set_sweep_start. Expected values are between -210 and 210." |
1436
|
|
|
|
|
|
|
); |
1437
|
|
|
|
|
|
|
} |
1438
|
|
|
|
|
|
|
elsif ($function =~ /\b(VOLTAGE|VOLT|voltage|volt)\b/ |
1439
|
|
|
|
|
|
|
or $function =~ /\b(CURRENT|CURR|current|curr)\b/ ) { |
1440
|
|
|
|
|
|
|
|
1441
|
|
|
|
|
|
|
# set stop value for sweep |
1442
|
0
|
|
|
|
|
|
return $self->query( |
1443
|
|
|
|
|
|
|
sprintf( |
1444
|
|
|
|
|
|
|
":SOURCE:%s:STOP %.11f; :SOURCE:%s:STOP?", |
1445
|
|
|
|
|
|
|
$function, $stop, $function |
1446
|
|
|
|
|
|
|
) |
1447
|
|
|
|
|
|
|
); |
1448
|
|
|
|
|
|
|
} |
1449
|
|
|
|
|
|
|
else { |
1450
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1451
|
|
|
|
|
|
|
"unexpected value in sub _set_sweep_stop. Function can be CURRENT or VOLTAGE, startvalue is expected to be between -1.05...+1.05A or -210...+210V" |
1452
|
|
|
|
|
|
|
); |
1453
|
|
|
|
|
|
|
} |
1454
|
|
|
|
|
|
|
} |
1455
|
|
|
|
|
|
|
|
1456
|
|
|
|
|
|
|
sub _set_sweep_step { # internal/advanced use only |
1457
|
0
|
|
|
0
|
|
|
my $self = shift; |
1458
|
0
|
|
|
|
|
|
my $function = shift; |
1459
|
0
|
|
|
|
|
|
my $step = shift; |
1460
|
|
|
|
|
|
|
|
1461
|
0
|
0
|
0
|
|
|
|
if ( not defined $step and $function >= -420 and $function <= 420 ) { |
|
|
|
0
|
|
|
|
|
1462
|
0
|
|
|
|
|
|
$step = $function; |
1463
|
0
|
|
|
|
|
|
$function = $self->query(":SOURCE:FUNCTION:MODE?"); |
1464
|
0
|
|
|
|
|
|
chomp $function; |
1465
|
|
|
|
|
|
|
} |
1466
|
|
|
|
|
|
|
else { |
1467
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1468
|
|
|
|
|
|
|
"unexpected value in sub _set_sweep_step. Expected values are between -420.. +420V or -2.1..+2.1A" |
1469
|
|
|
|
|
|
|
); |
1470
|
|
|
|
|
|
|
} |
1471
|
|
|
|
|
|
|
|
1472
|
0
|
0
|
0
|
|
|
|
if ( $function =~ /\b(CURRENT|CURR|current|curr)\b/ |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1473
|
|
|
|
|
|
|
and ( $step < -2.1 or $step > 2.1 ) ) { |
1474
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1475
|
|
|
|
|
|
|
"unexpected value in sub _set_sweep_step. Expected values are between -2.1 and 2.1A." |
1476
|
|
|
|
|
|
|
); |
1477
|
|
|
|
|
|
|
} |
1478
|
|
|
|
|
|
|
elsif ( $function =~ /\b(VOLTAGE|VOLT|voltage|volt)\b/ |
1479
|
|
|
|
|
|
|
and ( $step < -420 or $step > 420 ) ) { |
1480
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1481
|
|
|
|
|
|
|
"unexpected value in sub _set_sweep_step. Expected values are between -420 and 420A." |
1482
|
|
|
|
|
|
|
); |
1483
|
|
|
|
|
|
|
} |
1484
|
|
|
|
|
|
|
else { |
1485
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1486
|
|
|
|
|
|
|
"unexpected value in sub _set_sweep_step. Function can be CURRENT or VOLTAGE, startvalue is expected to be between -420.. +420V or -2.1..+2.1A" |
1487
|
|
|
|
|
|
|
); |
1488
|
|
|
|
|
|
|
} |
1489
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
# check if step matches to start and stop values |
1491
|
0
|
|
|
|
|
|
my $start = $self->query(":SOURCE:%s:START?"); |
1492
|
0
|
|
|
|
|
|
my $stop = $self->query(":SOURCE:%s:STOP?"); |
1493
|
|
|
|
|
|
|
|
1494
|
0
|
0
|
|
|
|
|
if ( int( ( $stop - $start ) / $step ) != ( $stop - $start ) / $step ) { |
1495
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1496
|
|
|
|
|
|
|
"ERROR in sub _set_sweep_step. STOP-START/STEP must be an integer value." |
1497
|
|
|
|
|
|
|
); |
1498
|
|
|
|
|
|
|
} |
1499
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
# set startvalue for sweep |
1501
|
0
|
|
|
|
|
|
$self->query( sprintf( ":SOURCE:%s:STEP %f.11", $function, $step ) ); |
1502
|
0
|
|
|
|
|
|
return abs( ( $stop - $start ) / $step + 1 ); # return number of points |
1503
|
|
|
|
|
|
|
} |
1504
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
sub _set_sweep_nop { # internal/advanced use only |
1506
|
0
|
|
|
0
|
|
|
my $self = shift; |
1507
|
0
|
|
|
|
|
|
my $nop = shift; |
1508
|
|
|
|
|
|
|
|
1509
|
0
|
0
|
0
|
|
|
|
if ( $nop >= 1 and $nop <= 2500 ) { |
1510
|
0
|
|
|
|
|
|
$self->_set_trigger_count($nop); |
1511
|
0
|
|
|
|
|
|
return $self->query( |
1512
|
|
|
|
|
|
|
sprintf( ":SOURCE:SWEEP:POINTS %d; POINTS?", $nop ) ); |
1513
|
|
|
|
|
|
|
} |
1514
|
|
|
|
|
|
|
else { |
1515
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1516
|
|
|
|
|
|
|
"unexpected value in sub _set_sweep_step. Expected values are between 1..2500" |
1517
|
|
|
|
|
|
|
); |
1518
|
|
|
|
|
|
|
} |
1519
|
|
|
|
|
|
|
} |
1520
|
|
|
|
|
|
|
|
1521
|
|
|
|
|
|
|
# ------------------------------------ DATA BUFFER ---------------------------------------- |
1522
|
|
|
|
|
|
|
|
1523
|
|
|
|
|
|
|
sub _clear_buffer { # internal/advanced use only |
1524
|
0
|
|
|
0
|
|
|
my $self = shift; |
1525
|
0
|
|
|
|
|
|
$self->write(":DATA:FEED:CONTROL NEVER"); |
1526
|
0
|
|
|
|
|
|
$self->write(":DATA:CLEAR"); |
1527
|
|
|
|
|
|
|
} |
1528
|
|
|
|
|
|
|
|
1529
|
|
|
|
|
|
|
sub _init_buffer { # internal/advanced use only |
1530
|
0
|
|
|
0
|
|
|
my $self = shift; |
1531
|
0
|
|
|
|
|
|
my $nop = shift; |
1532
|
|
|
|
|
|
|
|
1533
|
0
|
|
|
|
|
|
$self->_clear_buffer(); |
1534
|
|
|
|
|
|
|
|
1535
|
0
|
|
|
|
|
|
my $function = $self->set_sense_onfunction(); |
1536
|
0
|
0
|
|
|
|
|
if ( $function eq "NONE" ) { |
1537
|
0
|
|
|
|
|
|
$self->query( |
1538
|
|
|
|
|
|
|
sprintf( |
1539
|
|
|
|
|
|
|
":FORMAT:DATA ASCII; :FORMAT:ELEMENTS %s; ELEMENTS?", |
1540
|
|
|
|
|
|
|
$self->set_source_mode() |
1541
|
|
|
|
|
|
|
) |
1542
|
|
|
|
|
|
|
); # select Format for reading DATA |
1543
|
|
|
|
|
|
|
} |
1544
|
|
|
|
|
|
|
else { |
1545
|
0
|
|
|
|
|
|
$self->query( |
1546
|
|
|
|
|
|
|
sprintf( |
1547
|
|
|
|
|
|
|
":FORMAT:DATA ASCII; :FORMAT:ELEMENTS %s; ELEMENTS?", |
1548
|
|
|
|
|
|
|
$function |
1549
|
|
|
|
|
|
|
) |
1550
|
|
|
|
|
|
|
); # select Format for reading DATA |
1551
|
|
|
|
|
|
|
} |
1552
|
|
|
|
|
|
|
|
1553
|
0
|
0
|
0
|
|
|
|
if ( $nop >= 2 && $nop <= 2500 ) { |
1554
|
0
|
|
|
|
|
|
my $return_nop = $self->query( |
1555
|
|
|
|
|
|
|
sprintf( ":DATA:POINTS %d; :DATA:POINTS?", $nop ) ); |
1556
|
0
|
|
|
|
|
|
$self->write(":DATA:FEED SENSE"); # select raw-data to be stored. |
1557
|
0
|
|
|
|
|
|
$self->write(":DATA:FEED:CONTROL NEXT"); # enable data storage |
1558
|
0
|
|
|
|
|
|
$self->write( sprintf( ":TRIGGER:COUNT %d", $return_nop ) ) |
1559
|
|
|
|
|
|
|
; # set samplecount to buffersize. this setting may not be most general. |
1560
|
0
|
|
|
|
|
|
return $return_nop; |
1561
|
|
|
|
|
|
|
} |
1562
|
|
|
|
|
|
|
else { |
1563
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1564
|
|
|
|
|
|
|
"unexpected value in sub set_nop_for_buffer. Must be between 2 and 2500." |
1565
|
|
|
|
|
|
|
); |
1566
|
|
|
|
|
|
|
} |
1567
|
|
|
|
|
|
|
} |
1568
|
|
|
|
|
|
|
|
1569
|
|
|
|
|
|
|
sub _read_buffer { # internal/advanced use only |
1570
|
0
|
|
|
0
|
|
|
my $self = shift; |
1571
|
0
|
|
|
|
|
|
my $print = shift; |
1572
|
|
|
|
|
|
|
|
1573
|
|
|
|
|
|
|
# wait until data are available |
1574
|
0
|
|
|
|
|
|
$self->wait(); |
1575
|
|
|
|
|
|
|
|
1576
|
|
|
|
|
|
|
# get number of ONFUNCTIONS |
1577
|
0
|
|
|
|
|
|
my $onfunctions = $self->set_sense_onfunction(); |
1578
|
0
|
|
|
|
|
|
my @list = split( ",", $onfunctions ); |
1579
|
0
|
|
|
|
|
|
my $num_of_onfunctions = @list; |
1580
|
|
|
|
|
|
|
|
1581
|
|
|
|
|
|
|
# enlarge Query-TIMEOUT |
1582
|
|
|
|
|
|
|
my $status = Lab::VISA::viSetAttribute( |
1583
|
|
|
|
|
|
|
$self->{vi}->{instr}, |
1584
|
0
|
|
|
|
|
|
$Lab::VISA::VI_ATTR_TMO_VALUE, 20000 |
1585
|
|
|
|
|
|
|
); |
1586
|
0
|
0
|
|
|
|
|
if ( $status != $Lab::VISA::VI_SUCCESS ) { |
1587
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1588
|
|
|
|
|
|
|
"Error while setting baud: $status"); |
1589
|
|
|
|
|
|
|
} |
1590
|
|
|
|
|
|
|
|
1591
|
|
|
|
|
|
|
# read data |
1592
|
0
|
|
|
|
|
|
print "please wait while reading DATA ... \n"; |
1593
|
0
|
|
|
|
|
|
my $data = $self->connection()->LongQuery("DATA:DATA?"); |
1594
|
0
|
|
|
|
|
|
chomp $data; |
1595
|
0
|
|
|
|
|
|
my @data = split( ",", $data ); |
1596
|
|
|
|
|
|
|
|
1597
|
|
|
|
|
|
|
# Query-TIMEOUT back to default value |
1598
|
|
|
|
|
|
|
my $status = Lab::VISA::viSetAttribute( |
1599
|
|
|
|
|
|
|
$self->{vi}->{instr}, |
1600
|
0
|
|
|
|
|
|
$Lab::VISA::VI_ATTR_TMO_VALUE, 3000 |
1601
|
|
|
|
|
|
|
); |
1602
|
0
|
0
|
|
|
|
|
if ( $status != $Lab::VISA::VI_SUCCESS ) { |
1603
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1604
|
|
|
|
|
|
|
"Error while setting baud: $status"); |
1605
|
|
|
|
|
|
|
} |
1606
|
|
|
|
|
|
|
|
1607
|
|
|
|
|
|
|
# split data ( more than one onfunction ) |
1608
|
0
|
0
|
|
|
|
|
if ( $num_of_onfunctions > 1 ) { |
1609
|
0
|
|
|
|
|
|
my @DATA; |
1610
|
0
|
|
|
|
|
|
my $num = @data; |
1611
|
|
|
|
|
|
|
|
1612
|
0
|
|
|
|
|
|
for ( my $i = 0; $i < @data; $i++ ) { |
1613
|
0
|
|
|
|
|
|
$DATA[ $i % $num_of_onfunctions ] |
1614
|
|
|
|
|
|
|
[ int( $i / $num_of_onfunctions ) ] = $data[$i]; |
1615
|
|
|
|
|
|
|
} |
1616
|
|
|
|
|
|
|
|
1617
|
0
|
0
|
|
|
|
|
if ( $print eq "PRINT" ) { |
1618
|
0
|
|
|
|
|
|
foreach my $item (@DATA) { |
1619
|
0
|
|
|
|
|
|
foreach my $i (@$item) { |
1620
|
0
|
|
|
|
|
|
print "$i\t"; |
1621
|
|
|
|
|
|
|
} |
1622
|
0
|
|
|
|
|
|
print "\n"; |
1623
|
|
|
|
|
|
|
} |
1624
|
|
|
|
|
|
|
} |
1625
|
|
|
|
|
|
|
|
1626
|
0
|
|
|
|
|
|
return @DATA; |
1627
|
|
|
|
|
|
|
} |
1628
|
|
|
|
|
|
|
|
1629
|
0
|
0
|
|
|
|
|
if ( $print eq "PRINT" ) { |
1630
|
0
|
|
|
|
|
|
foreach my $i (@data) { |
1631
|
0
|
|
|
|
|
|
print $i. "\n"; |
1632
|
|
|
|
|
|
|
} |
1633
|
|
|
|
|
|
|
} |
1634
|
|
|
|
|
|
|
|
1635
|
0
|
|
|
|
|
|
return @data; |
1636
|
|
|
|
|
|
|
} |
1637
|
|
|
|
|
|
|
|
1638
|
|
|
|
|
|
|
# -------------------------------------- TRIGGER ---------------------------------------------- |
1639
|
|
|
|
|
|
|
|
1640
|
|
|
|
|
|
|
sub _set_trigger_count { # internal/advanced use only |
1641
|
0
|
|
|
0
|
|
|
my $self = shift; |
1642
|
0
|
|
|
|
|
|
my $triggercount = shift; |
1643
|
|
|
|
|
|
|
|
1644
|
0
|
0
|
0
|
|
|
|
if ( $triggercount >= 1 && $triggercount <= 2500 ) { |
1645
|
0
|
|
|
|
|
|
return $self->query( |
1646
|
|
|
|
|
|
|
sprintf( ":TRIGGER:COUNT %d; COUNT?", $triggercount ) ); |
1647
|
|
|
|
|
|
|
} |
1648
|
|
|
|
|
|
|
else { |
1649
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1650
|
|
|
|
|
|
|
"unexpected value for TRIGGERCOUNT in sub _set_trigger_count. Must be between 1 and 2500." |
1651
|
|
|
|
|
|
|
); |
1652
|
|
|
|
|
|
|
} |
1653
|
|
|
|
|
|
|
} |
1654
|
|
|
|
|
|
|
|
1655
|
|
|
|
|
|
|
sub _set_trigger_delay { # internal/advanced use only |
1656
|
0
|
|
|
0
|
|
|
my $self = shift; |
1657
|
0
|
|
|
|
|
|
my $triggerdelay = shift; |
1658
|
|
|
|
|
|
|
|
1659
|
0
|
0
|
|
|
|
|
if ( not defined $triggerdelay ) { |
1660
|
0
|
|
|
|
|
|
$triggerdelay = $self->query(":TRIGGER:DELAY?"); |
1661
|
0
|
|
|
|
|
|
return chomp $triggerdelay; |
1662
|
|
|
|
|
|
|
} |
1663
|
|
|
|
|
|
|
|
1664
|
0
|
0
|
0
|
|
|
|
if ( $triggerdelay >= 0 && $triggerdelay <= 999999.999 ) { |
|
|
0
|
|
|
|
|
|
1665
|
0
|
|
|
|
|
|
print "triggerdelay = " . $triggerdelay . "\n"; |
1666
|
0
|
|
|
|
|
|
return $self->query( |
1667
|
|
|
|
|
|
|
sprintf( ":TRIGGER:DELAY %.3f; DELAY?", $triggerdelay ) ); |
1668
|
|
|
|
|
|
|
} |
1669
|
|
|
|
|
|
|
elsif ( $triggerdelay =~ /\b(MIN|min|MAX|max|DEF|def)\b/ ) { |
1670
|
0
|
|
|
|
|
|
print "triggerdelay = " . $triggerdelay . "\n"; |
1671
|
0
|
|
|
|
|
|
return $self->query( |
1672
|
|
|
|
|
|
|
sprintf( ":TRIGGER:DELAY %s; DELAY?", $triggerdelay ) ); |
1673
|
|
|
|
|
|
|
} |
1674
|
|
|
|
|
|
|
else { |
1675
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1676
|
|
|
|
|
|
|
"unexpected value for TRIGGERDELAY in sub _set_trigger_delay. Must be between 0 and 999999.999sec." |
1677
|
|
|
|
|
|
|
); |
1678
|
|
|
|
|
|
|
} |
1679
|
|
|
|
|
|
|
} |
1680
|
|
|
|
|
|
|
|
1681
|
|
|
|
|
|
|
sub _set_timer { # internal/advanced use only |
1682
|
0
|
|
|
0
|
|
|
my $self = shift; |
1683
|
0
|
|
|
|
|
|
my $timer = shift; |
1684
|
|
|
|
|
|
|
|
1685
|
0
|
0
|
0
|
|
|
|
if ( $timer >= 0 && $timer <= 999999.999 ) { |
1686
|
0
|
|
|
|
|
|
$self->write( sprintf( ":ARM:TIMER %.3f", $timer ) ); |
1687
|
|
|
|
|
|
|
} |
1688
|
|
|
|
|
|
|
else { |
1689
|
0
|
|
|
|
|
|
Lab::Exception::CorruptParameter->throw( |
1690
|
|
|
|
|
|
|
"unexpected value for TIMER in sub _set_timer. Must be between 0 and 999999.999sec." |
1691
|
|
|
|
|
|
|
); |
1692
|
|
|
|
|
|
|
} |
1693
|
|
|
|
|
|
|
} |
1694
|
|
|
|
|
|
|
|
1695
|
|
|
|
|
|
|
# -----------------------------------------DISPLAY -------------------------------- |
1696
|
|
|
|
|
|
|
|
1697
|
|
|
|
|
|
|
sub display_on { # |
1698
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
1699
|
0
|
|
|
|
|
|
$self->write(":DISPLAY:ENABLE ON"); |
1700
|
|
|
|
|
|
|
} |
1701
|
|
|
|
|
|
|
|
1702
|
|
|
|
|
|
|
sub display_off { # |
1703
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
1704
|
0
|
|
|
|
|
|
$self->write(":DISPLAY:ENABLE OFF") |
1705
|
|
|
|
|
|
|
; # when display is disabled, the instrument operates at a higher speed. Frontpanel commands are frozen. |
1706
|
|
|
|
|
|
|
} |
1707
|
|
|
|
|
|
|
|
1708
|
|
|
|
|
|
|
sub display { |
1709
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
1710
|
0
|
|
|
|
|
|
my $data = shift; |
1711
|
|
|
|
|
|
|
|
1712
|
0
|
0
|
|
|
|
|
if ( not defined $data ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1713
|
0
|
|
|
|
|
|
return $self->display_text(); |
1714
|
|
|
|
|
|
|
} |
1715
|
|
|
|
|
|
|
elsif ( $data =~ /\b(ON|on)\b/ ) { |
1716
|
0
|
|
|
|
|
|
return $self->display_on(); |
1717
|
|
|
|
|
|
|
} |
1718
|
|
|
|
|
|
|
elsif ( $data =~ /\b(OFF|off)\b/ ) { |
1719
|
0
|
|
|
|
|
|
return $self->display_off(); |
1720
|
|
|
|
|
|
|
} |
1721
|
|
|
|
|
|
|
elsif ( $data =~ /\b(CLEAR|clear)\b/ ) { |
1722
|
0
|
|
|
|
|
|
return $self->display_clear(); |
1723
|
|
|
|
|
|
|
} |
1724
|
|
|
|
|
|
|
else { |
1725
|
0
|
|
|
|
|
|
return $self->display_text($data); |
1726
|
|
|
|
|
|
|
} |
1727
|
|
|
|
|
|
|
} |
1728
|
|
|
|
|
|
|
|
1729
|
|
|
|
|
|
|
sub display_text { # |
1730
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
1731
|
0
|
|
|
|
|
|
my $text = shift; |
1732
|
|
|
|
|
|
|
|
1733
|
0
|
0
|
|
|
|
|
if ($text) { |
1734
|
0
|
|
|
|
|
|
chomp( $text |
1735
|
|
|
|
|
|
|
= $self->query("DISPLAY:TEXT:DATA '$text'; STATE 1; DATA?") ); |
1736
|
0
|
|
|
|
|
|
$text =~ s/\"//g; |
1737
|
0
|
|
|
|
|
|
return $text; |
1738
|
|
|
|
|
|
|
} |
1739
|
|
|
|
|
|
|
else { |
1740
|
0
|
|
|
|
|
|
chomp( $text = $self->query("DISPLAY:TEXT:DATA?") ); |
1741
|
0
|
|
|
|
|
|
$text =~ s/\"//g; |
1742
|
0
|
|
|
|
|
|
return $text; |
1743
|
|
|
|
|
|
|
} |
1744
|
|
|
|
|
|
|
} |
1745
|
|
|
|
|
|
|
|
1746
|
|
|
|
|
|
|
sub display_clear { # |
1747
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
1748
|
0
|
|
|
|
|
|
$self->write("DISPlay:TEXT:STATE 0"); |
1749
|
|
|
|
|
|
|
} |
1750
|
|
|
|
|
|
|
|
1751
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------------------- |
1752
|
|
|
|
|
|
|
|
1753
|
|
|
|
|
|
|
1; |
1754
|
|
|
|
|
|
|
|
1755
|
|
|
|
|
|
|
__END__ |
1756
|
|
|
|
|
|
|
|
1757
|
|
|
|
|
|
|
=pod |
1758
|
|
|
|
|
|
|
|
1759
|
|
|
|
|
|
|
=encoding UTF-8 |
1760
|
|
|
|
|
|
|
|
1761
|
|
|
|
|
|
|
=head1 NAME |
1762
|
|
|
|
|
|
|
|
1763
|
|
|
|
|
|
|
Lab::Instrument::Keithley2400 - Keithley 2400 SourceMeter |
1764
|
|
|
|
|
|
|
|
1765
|
|
|
|
|
|
|
=head1 VERSION |
1766
|
|
|
|
|
|
|
|
1767
|
|
|
|
|
|
|
version 3.880 |
1768
|
|
|
|
|
|
|
|
1769
|
|
|
|
|
|
|
=head1 SYNOPSIS |
1770
|
|
|
|
|
|
|
|
1771
|
|
|
|
|
|
|
use Lab::Instrument::Keithley2400; |
1772
|
|
|
|
|
|
|
my $DMM=new Lab::Instrument::Keithley2400(0,GPIB-address); |
1773
|
|
|
|
|
|
|
print $DMM->get_value(); |
1774
|
|
|
|
|
|
|
|
1775
|
|
|
|
|
|
|
=head1 DESCRIPTION |
1776
|
|
|
|
|
|
|
|
1777
|
|
|
|
|
|
|
The Lab::Instrument::Keithley2400 class implements an interface to the Keithley 2400 digital multimeter. |
1778
|
|
|
|
|
|
|
|
1779
|
|
|
|
|
|
|
=head1 CAVEATS |
1780
|
|
|
|
|
|
|
|
1781
|
|
|
|
|
|
|
The Keithley2400 instrument driver is in a quite bad condition and would need a major revision. |
1782
|
|
|
|
|
|
|
However it works within the XPRESS Voltage sweep for list and step mode pretty well. |
1783
|
|
|
|
|
|
|
|
1784
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
1785
|
|
|
|
|
|
|
|
1786
|
|
|
|
|
|
|
my $DMM=new(\%options); |
1787
|
|
|
|
|
|
|
|
1788
|
|
|
|
|
|
|
=head1 METHODS |
1789
|
|
|
|
|
|
|
|
1790
|
|
|
|
|
|
|
=head2 get_value |
1791
|
|
|
|
|
|
|
|
1792
|
|
|
|
|
|
|
$value=$DMM->get_value(<$function>); |
1793
|
|
|
|
|
|
|
|
1794
|
|
|
|
|
|
|
Request a measurement value using the current instrument settings. |
1795
|
|
|
|
|
|
|
$function is an optional parameter. If $function is defined, a measurement using $function as the operating mode will be requested. |
1796
|
|
|
|
|
|
|
|
1797
|
|
|
|
|
|
|
=over 4 |
1798
|
|
|
|
|
|
|
|
1799
|
|
|
|
|
|
|
=item <$function> |
1800
|
|
|
|
|
|
|
|
1801
|
|
|
|
|
|
|
C<FUNCTION> can be one of the measurement methods of the Keithley2000. |
1802
|
|
|
|
|
|
|
|
1803
|
|
|
|
|
|
|
"current" --> DC current measurement |
1804
|
|
|
|
|
|
|
"voltage" --> DC voltage measurement |
1805
|
|
|
|
|
|
|
"resisitance" --> resistance measurement (2-wire) |
1806
|
|
|
|
|
|
|
"fresistance" --> resistance measurement (4-wire) |
1807
|
|
|
|
|
|
|
|
1808
|
|
|
|
|
|
|
=back |
1809
|
|
|
|
|
|
|
|
1810
|
|
|
|
|
|
|
=head2 get_temperature |
1811
|
|
|
|
|
|
|
|
1812
|
|
|
|
|
|
|
$value=$DMM->get_value($sensor, <$function>, <$range>); |
1813
|
|
|
|
|
|
|
|
1814
|
|
|
|
|
|
|
Make a measurement defined by $function with the previously specified range |
1815
|
|
|
|
|
|
|
and integration time. |
1816
|
|
|
|
|
|
|
|
1817
|
|
|
|
|
|
|
=over 4 |
1818
|
|
|
|
|
|
|
|
1819
|
|
|
|
|
|
|
=item $sensor |
1820
|
|
|
|
|
|
|
|
1821
|
|
|
|
|
|
|
C<SENSOR> can be one of the Temperature-Diodes defined in Lab::Instrument::TemperatureDiodes. |
1822
|
|
|
|
|
|
|
|
1823
|
|
|
|
|
|
|
=item <$function> |
1824
|
|
|
|
|
|
|
|
1825
|
|
|
|
|
|
|
FUNCTION can be one of the measurement methods of the Keithley2400. |
1826
|
|
|
|
|
|
|
|
1827
|
|
|
|
|
|
|
"diode" --> read out temperatuer diode |
1828
|
|
|
|
|
|
|
"resisitance" --> resistance measurement (2-wire) |
1829
|
|
|
|
|
|
|
"fresistance" --> resistance measurement (4-wire) |
1830
|
|
|
|
|
|
|
|
1831
|
|
|
|
|
|
|
=item <$range> |
1832
|
|
|
|
|
|
|
|
1833
|
|
|
|
|
|
|
RANGE is given in terms of amps or ohms and can be C< 1e-5 | 1e-4 | 1e-3 | MIN | MAX | DEF > or C< 0...101e6 | MIN | MAX | DEF | AUTO >. |
1834
|
|
|
|
|
|
|
C<DEF> is default C<AUTO> activates the AUTORANGE-mode. |
1835
|
|
|
|
|
|
|
C<DEF> will be set, if no value is given. |
1836
|
|
|
|
|
|
|
|
1837
|
|
|
|
|
|
|
=back |
1838
|
|
|
|
|
|
|
|
1839
|
|
|
|
|
|
|
=head2 set_output |
1840
|
|
|
|
|
|
|
|
1841
|
|
|
|
|
|
|
$output = $K6221->set_output($value); |
1842
|
|
|
|
|
|
|
|
1843
|
|
|
|
|
|
|
Switch device OUTPUT ON/OFF or set new OUTPUT value. |
1844
|
|
|
|
|
|
|
If no parameter is given, the current device output value will be returned. |
1845
|
|
|
|
|
|
|
|
1846
|
|
|
|
|
|
|
=over |
1847
|
|
|
|
|
|
|
|
1848
|
|
|
|
|
|
|
=item $value |
1849
|
|
|
|
|
|
|
|
1850
|
|
|
|
|
|
|
VALUE can be any numeric value within the current range setting or ON/OFF to switch the device OUTPUT ON/OFF. |
1851
|
|
|
|
|
|
|
|
1852
|
|
|
|
|
|
|
=back |
1853
|
|
|
|
|
|
|
|
1854
|
|
|
|
|
|
|
=head2 get_output |
1855
|
|
|
|
|
|
|
|
1856
|
|
|
|
|
|
|
$output = $K6221->get_output(<$mode>); |
1857
|
|
|
|
|
|
|
|
1858
|
|
|
|
|
|
|
Returns the current device output value or state. |
1859
|
|
|
|
|
|
|
If no parameter is given, the current device output value will be returned. |
1860
|
|
|
|
|
|
|
|
1861
|
|
|
|
|
|
|
=over |
1862
|
|
|
|
|
|
|
|
1863
|
|
|
|
|
|
|
=item <$mode> |
1864
|
|
|
|
|
|
|
|
1865
|
|
|
|
|
|
|
MODE can be 'STATE' to request the current output state (ON/OFF) or 'VALUE' to request the current output value. |
1866
|
|
|
|
|
|
|
|
1867
|
|
|
|
|
|
|
=back |
1868
|
|
|
|
|
|
|
|
1869
|
|
|
|
|
|
|
=head2 config_measurement |
1870
|
|
|
|
|
|
|
|
1871
|
|
|
|
|
|
|
$K2400->config_measurement($function, $number_of_points, <$time>, <$range>); |
1872
|
|
|
|
|
|
|
|
1873
|
|
|
|
|
|
|
Preset the Keithley2400 for a TRIGGERED measurement. |
1874
|
|
|
|
|
|
|
|
1875
|
|
|
|
|
|
|
WARNING: It's not recomended to perform triggered measurments with the KEITHLEY 2000 DMM due to unsolved timing problems!!!!! |
1876
|
|
|
|
|
|
|
|
1877
|
|
|
|
|
|
|
=over 4 |
1878
|
|
|
|
|
|
|
|
1879
|
|
|
|
|
|
|
=item $function |
1880
|
|
|
|
|
|
|
|
1881
|
|
|
|
|
|
|
C<FUNCTION> can be one of the measurement methods of the Keithley2000. |
1882
|
|
|
|
|
|
|
|
1883
|
|
|
|
|
|
|
"current" --> DC current measurement |
1884
|
|
|
|
|
|
|
"voltage" --> DC voltage measurement |
1885
|
|
|
|
|
|
|
"resisitance" --> resistance measurement (2-wire) |
1886
|
|
|
|
|
|
|
"fresistance" --> resistance measurement (4-wire) |
1887
|
|
|
|
|
|
|
|
1888
|
|
|
|
|
|
|
=item $number_of_points |
1889
|
|
|
|
|
|
|
|
1890
|
|
|
|
|
|
|
Preset the NUMBER OF POINTS to be taken for one measurement trace. |
1891
|
|
|
|
|
|
|
The single measured points will be stored in the internal memory of the Keithley2400. |
1892
|
|
|
|
|
|
|
For the Keithley2400 the internal memory is limited to 1024 values. |
1893
|
|
|
|
|
|
|
|
1894
|
|
|
|
|
|
|
=item <$time> |
1895
|
|
|
|
|
|
|
|
1896
|
|
|
|
|
|
|
Preset the TIME duration for one full trace. From TIME the integration time value for each measurement point will be derived [NPLC = (TIME *50Hz)/NOP]. |
1897
|
|
|
|
|
|
|
Expected values are between 0.5 ... 50000 seconds. |
1898
|
|
|
|
|
|
|
|
1899
|
|
|
|
|
|
|
=item <$range> |
1900
|
|
|
|
|
|
|
|
1901
|
|
|
|
|
|
|
RANGE is given in terms of amps, volts or ohms and can be C< 0...+3,03A | MIN | MAX | DEF | AUTO >, C< 0...757V(AC)/1010V(DC) | MIN | MAX | DEF | AUTO > or C< 0...101e6 | MIN | MAX | DEF | AUTO >. |
1902
|
|
|
|
|
|
|
C<DEF> is default C<AUTO> activates the AUTORANGE-mode. |
1903
|
|
|
|
|
|
|
C<DEF> will be set, if no value is given. |
1904
|
|
|
|
|
|
|
|
1905
|
|
|
|
|
|
|
=back |
1906
|
|
|
|
|
|
|
|
1907
|
|
|
|
|
|
|
=head2 trg |
1908
|
|
|
|
|
|
|
|
1909
|
|
|
|
|
|
|
$K2400->trg(); |
1910
|
|
|
|
|
|
|
|
1911
|
|
|
|
|
|
|
Sends a trigger signal via the GPIB-BUS to start the predefined measurement. |
1912
|
|
|
|
|
|
|
The LabVisa-script can immediatally be continued, e.g. to start another triggered measurement using a second Keithley2400. |
1913
|
|
|
|
|
|
|
|
1914
|
|
|
|
|
|
|
=head2 abort |
1915
|
|
|
|
|
|
|
|
1916
|
|
|
|
|
|
|
$K2400->abort(); |
1917
|
|
|
|
|
|
|
|
1918
|
|
|
|
|
|
|
Aborts current (triggered) measurement. |
1919
|
|
|
|
|
|
|
|
1920
|
|
|
|
|
|
|
=head2 active |
1921
|
|
|
|
|
|
|
|
1922
|
|
|
|
|
|
|
$K2400->abort(); |
1923
|
|
|
|
|
|
|
|
1924
|
|
|
|
|
|
|
Returns '1' if the current triggered measurement is still active and '0' if the current triggered measurement has allready been finished. |
1925
|
|
|
|
|
|
|
|
1926
|
|
|
|
|
|
|
=head2 wait |
1927
|
|
|
|
|
|
|
|
1928
|
|
|
|
|
|
|
$K2400->abort(); |
1929
|
|
|
|
|
|
|
|
1930
|
|
|
|
|
|
|
WAIT until triggered measurement has been finished. |
1931
|
|
|
|
|
|
|
|
1932
|
|
|
|
|
|
|
=head2 get_data |
1933
|
|
|
|
|
|
|
|
1934
|
|
|
|
|
|
|
@data = $K2400->get_data(); |
1935
|
|
|
|
|
|
|
|
1936
|
|
|
|
|
|
|
Reads all recorded values from the internal buffer and returnes them as an array of floatingpoint values. |
1937
|
|
|
|
|
|
|
Reading the buffer will start immediately after the triggered measurement has finished. The LabVisa-script cannot be continued until all requested readings have been recieved. |
1938
|
|
|
|
|
|
|
|
1939
|
|
|
|
|
|
|
=head2 set_function |
1940
|
|
|
|
|
|
|
|
1941
|
|
|
|
|
|
|
$K2400->set_function($function); |
1942
|
|
|
|
|
|
|
|
1943
|
|
|
|
|
|
|
Set a new value for the measurement function of the Keithley2400. |
1944
|
|
|
|
|
|
|
|
1945
|
|
|
|
|
|
|
=over 4 |
1946
|
|
|
|
|
|
|
|
1947
|
|
|
|
|
|
|
=item $function |
1948
|
|
|
|
|
|
|
|
1949
|
|
|
|
|
|
|
C<FUNCTION> can be one of the measurement methods of the Keithley2000. |
1950
|
|
|
|
|
|
|
|
1951
|
|
|
|
|
|
|
"current" --> DC current measurement |
1952
|
|
|
|
|
|
|
"voltage" --> DC voltage measurement |
1953
|
|
|
|
|
|
|
"resisitance" --> resistance measurement (2-wire) |
1954
|
|
|
|
|
|
|
"fresistance" --> resistance measurement (4-wire) |
1955
|
|
|
|
|
|
|
|
1956
|
|
|
|
|
|
|
=back |
1957
|
|
|
|
|
|
|
|
1958
|
|
|
|
|
|
|
=head2 set_range |
1959
|
|
|
|
|
|
|
|
1960
|
|
|
|
|
|
|
$K2400->set_range($function,$range); |
1961
|
|
|
|
|
|
|
|
1962
|
|
|
|
|
|
|
Set a new value for the predefined RANGE for the measurement function $function of the Keithley2400. |
1963
|
|
|
|
|
|
|
|
1964
|
|
|
|
|
|
|
=over 4 |
1965
|
|
|
|
|
|
|
|
1966
|
|
|
|
|
|
|
=item $function |
1967
|
|
|
|
|
|
|
|
1968
|
|
|
|
|
|
|
C<FUNCTION> can be one of the measurement methods of the Keithley2000. |
1969
|
|
|
|
|
|
|
|
1970
|
|
|
|
|
|
|
"current" --> DC current measurement |
1971
|
|
|
|
|
|
|
"voltage" --> DC voltage measurement |
1972
|
|
|
|
|
|
|
"resisitance" --> resistance measurement (2-wire) |
1973
|
|
|
|
|
|
|
"fresistance" --> resistance measurement (4-wire) |
1974
|
|
|
|
|
|
|
|
1975
|
|
|
|
|
|
|
=item $range |
1976
|
|
|
|
|
|
|
|
1977
|
|
|
|
|
|
|
RANGE is given in terms of amps, volts or ohms and can be C< 0...+3,03A | MIN | MAX | DEF | AUTO >, C< 0...757V(AC)/1010V(DC) | MIN | MAX | DEF | AUTO > or C< 0...101e6 | MIN | MAX | DEF | AUTO >. |
1978
|
|
|
|
|
|
|
C<DEF> is default C<AUTO> activates the AUTORANGE-mode. |
1979
|
|
|
|
|
|
|
C<DEF> will be set, if no value is given. |
1980
|
|
|
|
|
|
|
|
1981
|
|
|
|
|
|
|
=back |
1982
|
|
|
|
|
|
|
|
1983
|
|
|
|
|
|
|
=head2 set_nplc |
1984
|
|
|
|
|
|
|
|
1985
|
|
|
|
|
|
|
$K2400->set_nplc($function,$nplc); |
1986
|
|
|
|
|
|
|
|
1987
|
|
|
|
|
|
|
Set a new value for the predefined NUMBER of POWER LINE CYCLES for the measurement function $function of the Keithley2400. |
1988
|
|
|
|
|
|
|
|
1989
|
|
|
|
|
|
|
=over 4 |
1990
|
|
|
|
|
|
|
|
1991
|
|
|
|
|
|
|
=item $function |
1992
|
|
|
|
|
|
|
|
1993
|
|
|
|
|
|
|
C<FUNCTION> can be one of the measurement methods of the Keithley2000. |
1994
|
|
|
|
|
|
|
|
1995
|
|
|
|
|
|
|
"current" --> DC current measurement |
1996
|
|
|
|
|
|
|
"voltage" --> DC voltage measurement |
1997
|
|
|
|
|
|
|
"resisitance" --> resistance measurement (2-wire) |
1998
|
|
|
|
|
|
|
"fresistance" --> resistance measurement (4-wire) |
1999
|
|
|
|
|
|
|
|
2000
|
|
|
|
|
|
|
=item $nplc |
2001
|
|
|
|
|
|
|
|
2002
|
|
|
|
|
|
|
Preset the NUMBER of POWER LINE CYCLES which is actually something similar to an integration time for recording a single measurement value. |
2003
|
|
|
|
|
|
|
|
2004
|
|
|
|
|
|
|
The values for $nplc can be any value between 0.01 ... 10. |
2005
|
|
|
|
|
|
|
|
2006
|
|
|
|
|
|
|
Example: |
2007
|
|
|
|
|
|
|
Assuming $nplc to be 10 and assuming a netfrequency of 50Hz this results in an integration time of 10*50Hz = 0.2 seconds for each measured value. Assuming $number_of_points to be 100 it takes in total 20 seconds to record all values for the trace. |
2008
|
|
|
|
|
|
|
|
2009
|
|
|
|
|
|
|
=back |
2010
|
|
|
|
|
|
|
|
2011
|
|
|
|
|
|
|
=head2 set_averaging |
2012
|
|
|
|
|
|
|
|
2013
|
|
|
|
|
|
|
$K2400->set_averaging($count, <$filter>); |
2014
|
|
|
|
|
|
|
|
2015
|
|
|
|
|
|
|
Set a new value for the predefined NUMBER of POWER LINE CYCLES for the measurement function $function of the Keithley2400. |
2016
|
|
|
|
|
|
|
|
2017
|
|
|
|
|
|
|
=over 4 |
2018
|
|
|
|
|
|
|
|
2019
|
|
|
|
|
|
|
=item $count |
2020
|
|
|
|
|
|
|
|
2021
|
|
|
|
|
|
|
COUNT is the number of readings to be taken to fill the AVERAGING FILTER. COUNT can be 1 ... 100. |
2022
|
|
|
|
|
|
|
|
2023
|
|
|
|
|
|
|
=item <$filter> |
2024
|
|
|
|
|
|
|
|
2025
|
|
|
|
|
|
|
FILTER can be MOVING or REPEAT. A detailed description is refered to the user manual. |
2026
|
|
|
|
|
|
|
|
2027
|
|
|
|
|
|
|
=back |
2028
|
|
|
|
|
|
|
|
2029
|
|
|
|
|
|
|
=head2 display_on |
2030
|
|
|
|
|
|
|
|
2031
|
|
|
|
|
|
|
$K2400->display_on(); |
2032
|
|
|
|
|
|
|
|
2033
|
|
|
|
|
|
|
Turn the front-panel display on. |
2034
|
|
|
|
|
|
|
|
2035
|
|
|
|
|
|
|
=head2 display_off |
2036
|
|
|
|
|
|
|
|
2037
|
|
|
|
|
|
|
$K2400->display_off(); |
2038
|
|
|
|
|
|
|
|
2039
|
|
|
|
|
|
|
Turn the front-panel display off. |
2040
|
|
|
|
|
|
|
|
2041
|
|
|
|
|
|
|
=head2 display_text |
2042
|
|
|
|
|
|
|
|
2043
|
|
|
|
|
|
|
$K2400->display_text($text); |
2044
|
|
|
|
|
|
|
print $K2400->display_text(); |
2045
|
|
|
|
|
|
|
|
2046
|
|
|
|
|
|
|
Display a message on the front panel. The multimeter will display up to 12 |
2047
|
|
|
|
|
|
|
characters in a message; any additional characters are truncated. |
2048
|
|
|
|
|
|
|
Without parameter the displayed message is returned. |
2049
|
|
|
|
|
|
|
|
2050
|
|
|
|
|
|
|
=head2 display_clear |
2051
|
|
|
|
|
|
|
|
2052
|
|
|
|
|
|
|
$K2400->display_clear(); |
2053
|
|
|
|
|
|
|
|
2054
|
|
|
|
|
|
|
Clear the message displayed on the front panel. |
2055
|
|
|
|
|
|
|
|
2056
|
|
|
|
|
|
|
=head2 reset |
2057
|
|
|
|
|
|
|
|
2058
|
|
|
|
|
|
|
$K2400->reset(); |
2059
|
|
|
|
|
|
|
|
2060
|
|
|
|
|
|
|
Reset the multimeter to its power-on configuration. |
2061
|
|
|
|
|
|
|
|
2062
|
|
|
|
|
|
|
=head1 SEE ALSO |
2063
|
|
|
|
|
|
|
|
2064
|
|
|
|
|
|
|
=over 4 |
2065
|
|
|
|
|
|
|
|
2066
|
|
|
|
|
|
|
=item L<Lab::Instrument> |
2067
|
|
|
|
|
|
|
|
2068
|
|
|
|
|
|
|
=back |
2069
|
|
|
|
|
|
|
|
2070
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
2071
|
|
|
|
|
|
|
|
2072
|
|
|
|
|
|
|
This software is copyright (c) 2023 by the Lab::Measurement team; in detail: |
2073
|
|
|
|
|
|
|
|
2074
|
|
|
|
|
|
|
Copyright 2015 Christian Butschkow |
2075
|
|
|
|
|
|
|
2016 Simon Reinhardt |
2076
|
|
|
|
|
|
|
2017 Andreas K. Huettel |
2077
|
|
|
|
|
|
|
2020 Andreas K. Huettel |
2078
|
|
|
|
|
|
|
|
2079
|
|
|
|
|
|
|
|
2080
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
2081
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
2082
|
|
|
|
|
|
|
|
2083
|
|
|
|
|
|
|
=cut |