File Coverage

blib/lib/Lab/Instrument/Keithley2400.pm
Criterion Covered Total %
statement 17 695 2.4
branch 0 318 0.0
condition 0 219 0.0
subroutine 6 64 9.3
pod 15 41 36.5
total 38 1337 2.8


line stmt bran cond sub pod time code
1             package Lab::Instrument::Keithley2400;
2             #ABSTRACT: Keithley 2400 SourceMeter
3             $Lab::Instrument::Keithley2400::VERSION = '3.881';
4 1     1   1879 use v5.20;
  1         4  
5              
6 1     1   6 use strict;
  1         3  
  1         22  
7 1     1   6 use Lab::Instrument;
  1         3  
  1         31  
8 1     1   7 use Lab::Instrument::Source;
  1         2  
  1         26  
9 1     1   6 use Time::HiRes qw/usleep/, qw/time/;
  1         2  
  1         7  
10 1     1   125 use Carp;
  1         2  
  1         10656  
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.881
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