File Coverage

blib/lib/Lab/Instrument/HP34420A.pm
Criterion Covered Total %
statement 23 196 11.7
branch 0 86 0.0
condition 0 23 0.0
subroutine 8 33 24.2
pod 17 20 85.0
total 48 358 13.4


line stmt bran cond sub pod time code
1             package Lab::Instrument::HP34420A;
2             #ABSTRACT: HP/Agilent 34420A digital multimeter
3             $Lab::Instrument::HP34420A::VERSION = '3.880';
4 1     1   1765 use v5.20;
  1         4  
5              
6 1     1   5 use strict;
  1         4  
  1         32  
7 1     1   10 use Scalar::Util qw(weaken);
  1         3  
  1         43  
8 1     1   17 use Lab::Instrument;
  1         6  
  1         17  
9 1     1   6 use Carp;
  1         5  
  1         46  
10 1     1   7 use Data::Dumper;
  1         2  
  1         73  
11 1     1   7 use Lab::Instrument::Multimeter;
  1         2  
  1         2727  
12              
13             our @ISA = ("Lab::Instrument::Multimeter");
14              
15             our %fields = (
16             supported_connections => ['GPIB'],
17              
18             # default settings for the supported connections
19             connection_settings => {
20             gpib_board => 0,
21             gpib_address => undef,
22             },
23              
24             device_settings => {
25             pl_freq => 50,
26             },
27              
28             device_cache => {
29              
30             # TO DO: add range and resolution + get/setter
31             }
32              
33             );
34              
35             sub new {
36 0     0 1   my $proto = shift;
37 0   0       my $class = ref($proto) || $proto;
38 0           my $self = $class->SUPER::new(@_);
39 0           $self->${ \( __PACKAGE__ . '::_construct' ) }(__PACKAGE__);
  0            
40 0           return $self;
41             }
42              
43             #
44             # first, all internal stuff
45             #
46              
47             #
48             # all methods that fill in general Multimeter methods
49             #
50              
51             sub _display_clear {
52 0     0     my $self = shift;
53 0           $self->connection()->Write( command => "DISPlay:TEXT:CLEar" );
54             }
55              
56             sub _id {
57 0     0     my $self = shift;
58 0           return $self->query('*IDN?');
59             }
60              
61             sub _get_value {
62 0     0     my $self = shift;
63 0           my $value = $self->query('READ?');
64 0           chomp $value;
65 0           return $value;
66             }
67              
68             sub _device_init {
69 0     0     my $self = shift;
70              
71             }
72              
73             #
74             # all methods that are called directly
75             #
76              
77             sub get_resistance {
78 0     0 1   my $self = shift;
79 0           my ( $range, $resolution ) = @_;
80              
81 0 0         $range = "DEF" unless ( defined $range );
82 0 0         $resolution = "DEF" unless ( defined $resolution );
83              
84 0           my $cmd
85             = sprintf( "MEASure:SCALar:RESIStance? %s,%s", $range, $resolution );
86 0           my $value = $self->query($cmd);
87 0           return $value;
88             }
89              
90             sub get_4wresistance {
91 0     0 0   my $self = shift;
92 0           my ( $range, $resolution ) = @_;
93              
94 0 0         $range = "DEF" unless ( defined $range );
95 0 0         $resolution = "DEF" unless ( defined $resolution );
96              
97 0           my $cmd
98             = sprintf( "MEASure:SCALar:FRESIStance? %s,%s", $range, $resolution );
99 0           my $value = $self->query($cmd);
100 0           return $value;
101             }
102              
103             sub get_voltage_dc {
104 0     0 1   my $self = shift;
105 0           my ( $range, $resolution ) = @_;
106              
107 0 0         $range = "DEF" unless ( defined $range );
108 0 0         $resolution = "DEF" unless ( defined $resolution );
109              
110 0           my $cmd = sprintf( "MEASure:VOLTage:DC? %s,%s", $range, $resolution );
111 0           my $value = $self->query($cmd);
112 0           return $value;
113             }
114              
115             sub get_voltage_ac {
116 0     0 1   my $self = shift;
117 0           my ( $range, $resolution ) = @_;
118              
119 0 0         $range = "DEF" unless ( defined $range );
120 0 0         $resolution = "DEF" unless ( defined $resolution );
121              
122 0           my $cmd = sprintf( "MEASure:VOLTage:AC? %s,%s", $range, $resolution );
123 0           my $value = $self->query($cmd);
124 0           return $value;
125             }
126              
127             sub get_current_dc {
128 0     0 1   my $self = shift;
129 0           my ( $range, $resolution ) = @_;
130              
131 0 0         $range = "DEF" unless ( defined $range );
132 0 0         $resolution = "DEF" unless ( defined $resolution );
133              
134 0           my $cmd = sprintf( "MEASure:CURRent:DC? %s,%s", $range, $resolution );
135 0           my $value = $self->query($cmd);
136 0           return $value;
137             }
138              
139             sub get_current_ac {
140 0     0 1   my $self = shift;
141 0           my ( $range, $resolution ) = @_;
142              
143 0 0         $range = "DEF" unless ( defined $range );
144 0 0         $resolution = "DEF" unless ( defined $resolution );
145              
146 0           my $cmd = sprintf( "MEASure:CURRent:AC? %s,%s", $range, $resolution );
147 0           my $value = $self->query($cmd);
148 0           return $value;
149             }
150              
151             sub beep {
152 0     0 1   my $self = shift;
153 0           $self->write("SYSTem:BEEPer");
154             }
155              
156             sub get_error {
157 0     0 1   my $self = shift;
158 0           my $error = $self->query("SYST:ERR?");
159 0 0         if ( $error !~ /\+0,/ ) {
160 0 0         if ( $error =~ /^(\+[0-9]*)\,\"?(.*)\"?$/ ) {
161 0           return ( $1, $2 ); # ($code, $message)
162             }
163             else {
164 0           Lab::Exception::DeviceError->throw(
165             error =>
166             "Reading the error status of the device failed in Instrument::HP34401A::get_error(). Something's going wrong here.\n",
167             );
168             }
169             }
170             else {
171 0           return undef;
172             }
173             }
174              
175             sub get_status {
176 0     0 1   my $self = shift;
177              
178             # This is to be implemented with code that queries the status bit
179              
180 0           my $request = shift;
181 0           my $status = {};
182              
183             (
184             $status->{NOT_USED1}, $status->{NOT_USED2}, $status->{NOT_USED3},
185             $status->{CORR_DATA}, $status->{MSG_AVAIL}, $status->{EVNT},
186             $status->{SRQ}, $status->{NOT_USED4}
187 0           ) = $self->connection()->serial_poll();
188 0 0         return $status->{$request} if defined $request;
189 0           return $status;
190             }
191              
192             sub set_display_state {
193 0     0 1   my $self = shift;
194 0           my $value = shift;
195              
196 0 0 0       if ( $value == 1 || $value =~ /on/i ) {
    0 0        
197 0           $self->write( "DISP ON", @_ );
198             }
199             elsif ( $value == 0 || $value =~ /off/i ) {
200 0           $self->write( "DISP OFF", @_ );
201             }
202             else {
203 0           Lab::Exception::CorruptParameter->throw(
204             "set_display_state(): Illegal parameter.\n");
205             }
206             }
207              
208             sub set_display_text {
209 0     0 1   my $self = shift;
210 0           my $text = shift;
211 0 0         if ( $text
212             !~ /^[A-Za-z0-9\ \!\#\$\%\&\'\(\)\^\\\/\@\;\:\[\]\,\.\+\-\=\<\>\?\_]*$/
213             ) { # characters allowed by the 3458A
214 0           Lab::Exception::CorruptParameter->throw(
215             "set_display_text(): Illegal characters in given text.\n");
216             }
217 0           $self->write("DISP:TEXT $text");
218              
219 0           $self->check_errors();
220             }
221              
222             sub reset {
223 0     0 1   my $self = shift;
224 0           $self->connection()->Write( command => "*CLS" );
225 0           $self->connection()->Write( command => "*RST" );
226              
227             # $self->connection()->InstrumentClear($self->instrument_handle());
228             }
229              
230             sub wait_done {
231 0     0 0   my $self = shift;
232              
233             # wait until currently running program is finished.
234              
235 0           while ( !$self->get_status()->{"EVNT"} ) {
236 0           sleep 1;
237             }
238              
239             }
240              
241             sub autozero {
242 0     0 1   my $self = shift;
243 0           my $enable = shift;
244 0           my $az_status = undef;
245 0           my $command = "";
246              
247 0 0         if ( !defined $enable ) {
248              
249             # read autozero setting
250 0           $command = "ZERO:AUTO?";
251 0           $az_status = $self->query( $command, error_check => 1 );
252             }
253             else {
254 0 0         if ( $enable =~ /^ONCE$/i ) {
    0          
    0          
255 0           $command = "ZERO:AUTO ONCE";
256             }
257             elsif ( $enable =~ /^(ON|1)$/i ) {
258 0           $command = "ZERO:AUTO ONCE";
259             }
260             elsif ( $enable =~ /^(OFF|0)$/i ) {
261 0           $command = "ZERO:AUTO OFF";
262             }
263             else {
264 0           Lab::Exception::CorruptParameter->throw( error =>
265             "HP34401A::autozero() can be set to 'ON'/1, 'OFF'/0 or 'ONCE'. Received '${enable}'\n"
266             );
267             }
268 0           $self->write( $command, error_check => 1 );
269             }
270              
271 0           return $az_status;
272             }
273              
274             sub _configure_voltage_dc {
275 0     0     my $self = shift;
276 0           my $range = shift; # in V, or "AUTO", "MIN", "MAX"
277 0           my $tint = shift; # integration time in sec, "DEFAULT", "MIN", "MAX"
278 0           my $res_cmd = shift;
279              
280 0 0 0       if ( $range eq 'AUTO' || !defined($range) ) {
    0          
    0          
281 0           $range = 'DEF';
282             }
283             elsif ( $range =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/ ) {
284              
285             #$range = sprintf("%e",abs($range));
286             }
287             elsif ( $range !~ /^(MIN|MAX)$/ ) {
288 0           Lab::Exception::CorruptParameter->throw( error =>
289             "Range has to be set to a decimal value or 'AUTO', 'MIN' or 'MAX' in HP34401A::configure_voltage_dc()\n"
290             );
291             }
292              
293 0 0         if ( $tint =~ /^([+]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/ ) {
    0          
294              
295             # Convert seconds to PLC (power line cycles)
296 0           $tint *= $self->pl_freq();
297             }
298             elsif ( $tint !~ /^(MIN|MAX|DEFAULT)$/ ) {
299 0           Lab::Exception::CorruptParameter->throw( error =>
300             "Integration time has to be set to a positive value or 'AUTO', 'MIN' or 'MAX' in HP34401A::configure_voltage_dc()\n"
301             );
302             }
303              
304 0 0         if ( !defined($res_cmd) ) {
305 0           $res_cmd = '';
306             }
307              
308             # do it
309 0           $self->write( "CONF:VOLT:DC ${range} ${res_cmd}", error_check => 1 );
310 0 0         $self->write( "VOLT:DC:NPLC ${tint}", error_check => 1 )
311             if $res_cmd eq
312             ''; # integration time implicitly set through resolution
313             }
314              
315             sub configure_voltage_dc_trigger {
316 0     0 1   my $self = shift;
317 0           my $tint = shift
318             ; # integration time in sec, Default is 10PLC*pl_freq(), "MIN" = 0.02PLC , "MAX" = 200PLC
319 0           my $range = shift; # in V, or "DEF"(Default), "MIN", "MAX"
320 0           my $count = shift; # Measurment count, Default = 1
321 0           my $delay = shift; # in seconds, Default = 'MIN'
322 0           my $res_cmd = shift
323             ; # Resolution. Decimal (not number of digits!). NOT VALID FOR AC MEASUREMENT
324              
325             ### Check the parameters for errors
326              
327 0 0         $count = 1 if !defined($count);
328 0 0 0       Lab::Exception::CorruptParameter->throw(
      0        
329             error => "Sample count has to be an integer between 1 and 512\n" )
330             if ( $count !~ /^[0-9]*$/ || $count < 1 || $count > 512 );
331              
332 0 0         $delay = 0 if !defined($delay);
333 0 0         Lab::Exception::CorruptParameter->throw(
334             error => "Trigger delay has to be a positive decimal value\n" )
335             if ( $count !~ /^([+]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/ );
336              
337 0 0         if ( !defined($tint) ) {
    0          
    0          
338 0           $tint = 10;
339             }
340             elsif ( $tint =~ /^([+]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/ ) {
341              
342             # Convert seconds to PLC (power line cycles)
343 0           $tint *= $self->pl_freq();
344 0 0 0       if ( $tint > 200 || $tint < 0.02 ) {
345 0           Lab::Exception::CorruptParameter->throw( error =>
346             "Integration time out of bounds (int. time = $tint) in HP34401A::configure_voltage_dc()\n"
347             );
348             }
349             }
350             elsif ( $tint !~ /^(MIN|MAX)$/ ) {
351 0           Lab::Exception::CorruptParameter->throw( error =>
352             "Integration time has to be set to a positive value, 'MIN' or 'MAX' in HP34401A::configure_voltage_dc()\n"
353             );
354             }
355              
356 0 0         if ( !defined($range) ) {
    0          
    0          
357 0           $range = 'DEF';
358             }
359             elsif ( $range =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/ ) {
360 0           $range = sprintf( "%e", abs($range) );
361             }
362             elsif ( $range !~ /^(MIN|MAX)$/ ) {
363 0           Lab::Exception::CorruptParameter->throw( error =>
364             "Range has to be set to a decimal value or 'AUTO', 'MIN' or 'MAX' in HP34401A::configure_voltage_dc()\n"
365             );
366             }
367              
368 0 0         if ( !defined($res_cmd) ) {
369 0           $res_cmd = '';
370             }
371              
372 0           $self->write( "CONF:VOLT:DC ${range} ${res_cmd}", error_check => 1 );
373 0 0         $self->write( "VOLT:DC:NPLC ${tint}", error_check => 1 )
374             if $res_cmd eq
375             ''; # integration time implicitly set if resolution given
376              
377 0           $self->write("*ESE 1");
378 0           $self->write("*CLS");
379              
380 0           $self->write("TRIG:SOURce BUS");
381 0           $self->write("SAMPle:COUNt $count");
382 0           $self->write("TRIG:DELay $delay");
383              
384             }
385              
386             sub trigger {
387 0     0 1   my $self = shift;
388 0           $self->write("INIT");
389              
390 0           $self->write("*TRG");
391 0           $self->write("*OPC");
392              
393             }
394              
395             sub fetch {
396 0     0 1   my $self = shift;
397              
398 0           my $value = $self->query("FETCh?");
399              
400 0           chomp $value;
401              
402 0           my @valarray = split( ",", $value );
403              
404 0           return @valarray;
405             }
406              
407             sub trigger_read {
408 0     0 1   my $self = shift;
409 0           my $args = undef;
410 0 0         if ( ref $_[0] eq 'HASH' ) { $args = shift }
  0            
411 0           else { $args = {@_} }
412              
413             #$args->{'timeout'} = $args->{'timeout'} || $self->timeout();
414              
415 0           $self->write("INIT");
416 0           $self->write("*TRG");
417 0           my $value = $self->query( "FETCh?", $args );
418              
419 0           chomp $value;
420              
421 0           my @valarray = split( ",", $value );
422              
423 0           return @valarray;
424             }
425              
426             sub scroll_message {
427 1     1   16 use Time::HiRes (qw/usleep/);
  1         4  
  1         8  
428 0     0 0   my $self = shift;
429 0   0       my $message = shift
430             || " Lab::Measurement - designed to make measuring fun! ";
431 0           for my $i ( 0 .. ( length($message) - 12 ) ) {
432 0           $self->display_text( sprintf "%12.12s", substr( $message, $i ) );
433 0           usleep(100000);
434             }
435 0           $self->display_clear();
436             }
437              
438             1;
439              
440             __END__
441              
442             =pod
443              
444             =encoding utf-8
445              
446             =head1 NAME
447              
448             Lab::Instrument::HP34420A - HP/Agilent 34420A digital multimeter
449              
450             =head1 VERSION
451              
452             version 3.880
453              
454             =head1 SYNOPSIS
455              
456             use Lab::Instrument::HP34420A;
457            
458             my $Agi = new Lab::Instrument::HP34420A({
459             connection => new Lab::Connection::GPIB(
460             gpib_board => 0,
461             gpib_address => 14,
462             ),
463             }
464              
465             =head1 DESCRIPTION
466              
467             The Lab::Instrument::HP34420A class implements an interface to the 34420A digital
468             multimeter by Agilent (formerly HP). This module is in big parts equal to the
469             34410A and 34411A multimeter drivers.
470              
471             =head1 CONSTRUCTOR
472              
473             my $Agi=new(\%options);
474              
475             =head1 METHODS
476              
477             =head2 fetch
478              
479             $hp->fetch();
480              
481             Fetches the instrument buffer. Returns an array of values.
482              
483             =head2 autozero
484              
485             $hp->autozero($setting);
486              
487             $setting can be 1/'ON', 0/'OFF' or 'ONCE'.
488              
489             When set to "ON", the device takes a zero reading after every measurement.
490             "ONCE" perform one zero reading and disables the automatic zero reading.
491             "OFF" does... you get it.
492              
493             =head2 configure_voltage_dc
494              
495             $hp->configure_voltage_dc($range, $integration_time);
496              
497             Configures all the details of the device's DC voltage measurement function.
498              
499             $range is a positive numeric value (the largest expected value to be measured) or one of 'MIN', 'MAX', 'AUTO'.
500             It specifies the largest value to be measured. You can set any value, but the HP/Agilent 34401A effectively uses
501             one of the values 0.1, 1, 10, 100 and 1000V.
502              
503             $integration_time is the integration time in seconds. This implicitly sets the provided resolution.
504              
505             =head2 pl_freq
506             Parameter: pl_freq
507              
508             $hp->pl_freq($new_freq);
509             $npl_freq = $hp->pl_freq();
510              
511             Get/set the power line frequency at your location (50 Hz for most countries, which is the default). This
512             is the basis of the integration time setting (which is internally specified as a count of power
513             line cycles, or PLCs). The integration time will be set incorrectly if this parameter is set incorrectly.
514              
515             =head2 set_display_text
516              
517             $Agi->display_text($text);
518             print $Agi->display_text();
519              
520             Display a message on the front panel. The multimeter will display up to 12
521             characters in a message; any additional characters are truncated.
522             Without parameter the displayed message is returned.
523             Inherited from L<Lab::Instrument::Multimeter>
524              
525             =head2 set_display_state
526              
527             $Agi->set_display_state($state);
528              
529             Turn the front-panel display on ($state = "ON") or off ($state = "OFF").
530              
531             =head2 get_resistance
532              
533             $resistance=$Agi->get_resistance($range,$resolution);
534              
535             Preset and measure resistance with specified range and resolution.
536              
537             =head2 get_voltage_dc
538              
539             $datum=$Agi->get_voltage_dc($range,$resolution);
540              
541             Preset and make a dc voltage measurement with the specified range
542             and resolution.
543              
544             =over 4
545              
546             =item $range
547              
548             Range is given in terms of volts and can be C<[0.1|1|10|100|1000|MIN|MAX|DEF]>. C<DEF> is default.
549              
550             =item $resolution
551              
552             Resolution is given in terms of C<$range> or C<[MIN|MAX|DEF]>.
553             C<$resolution=0.0001> means 4 1/2 digits for example.
554             The best resolution is 100nV: C<$range=0.1>; C<$resolution=0.000001>.
555              
556             =back
557              
558             =head2 get_voltage_ac
559              
560             $datum=$Agi->get_voltage_ac($range,$resolution);
561              
562             Preset and make an ac voltage measurement with the specified range
563             and resolution. For ac measurements, resolution is actually fixed
564             at 6 1/2 digits. The resolution parameter only affects the front-panel display.
565              
566             =head2 get_current_dc
567              
568             $datum=$Agi->get_current_dc($range,$resolution);
569              
570             Preset and make a dc current measurement with the specified range
571             and resolution.
572              
573             =head2 get_current_ac
574              
575             $datum=$Agi->get_current_ac($range,$resolution);
576              
577             Preset and make an ac current measurement with the specified range
578             and resolution. For ac measurements, resolution is actually fixed
579             at 6 1/2 digits. The resolution parameter only affects the front-panel display.
580              
581             =head2 configure_voltage_dc_trigger
582              
583             $device->configure_voltage_dc_trigger($intt, $range, $count, $delay, $resolution)
584              
585             Configure the multimeter for a triggered reading.
586              
587             =over 4
588              
589             =item $intt
590              
591             The integration time in seconds. You can also set "MIN" or "MAX". This value is overwritten if the resolution is specified.
592              
593             =item $range
594              
595             The range for the measurment.
596              
597             =item $count
598              
599             The number of measurements which are performed after one single trigger impulse.
600              
601             =item $delay
602              
603             The delay between the C<$count> measurements (the integration time is not included).
604              
605             =item $resolution
606              
607             The resolution for the measurement. If given, this overwrites the C<$intt> parameter.
608              
609             =back
610              
611             =head2 trigger_read
612              
613             $data = $device->trigger_read()
614              
615             Sends a trigger signal and fetches the value(s) from the multimeter.
616              
617             =head2 trigger
618              
619             $device->trigger()
620              
621             Sends a trigger signal to the device.
622              
623             =head2 fetch
624              
625             $data = $device->fetch()
626              
627             Fetches the data which is currently in the output buffer of the device.
628              
629             =head2 beep
630              
631             $Agi->beep();
632              
633             Issue a single beep immediately.
634              
635             =head2 get_error
636              
637             ($err_num,$err_msg)=$Agi->get_error();
638              
639             Query the multimeter's error queue. Up to 20 errors can be stored in the
640             queue. Errors are retrieved in first-in-first out (FIFO) order.
641              
642             =head2 reset
643              
644             $Agi->reset();
645              
646             Reset the multimeter to its power-on configuration.
647              
648             =head1 CAVEATS/BUGS
649              
650             probably many
651              
652             =head1 SEE ALSO
653              
654             =over 4
655              
656             =item * L<Lab::Instrument>
657              
658             =item * L<Lab::Instrument::Multimeter>
659              
660             =item * L<Lab::Instrument::HP3458A>
661              
662             =back
663              
664             =head1 COPYRIGHT AND LICENSE
665              
666             This software is copyright (c) 2023 by the Lab::Measurement team; in detail:
667              
668             Copyright 2005-2006 Daniel Schroeer
669             2009 Andreas K. Huettel, Daniela Taubert
670             2010 Andreas K. Huettel, Daniel Schroeer
671             2011 Andreas K. Huettel, Florian Olbrich
672             2012 Alois Dirnaichner, Florian Olbrich
673             2013 Andreas K. Huettel
674             2016 Simon Reinhardt
675             2017 Andreas K. Huettel
676             2020 Andreas K. Huettel
677              
678              
679             This is free software; you can redistribute it and/or modify it under
680             the same terms as the Perl 5 programming language system itself.
681              
682             =cut