HP 3458a + NI GPIB-232CT-A  + Matlab = remote control? - Page 1
Forum section: electronics / testgear

author: LINACboy
author_rank: Contributor
timestamp: September 26, 2015, 10:41:43 pm
content: Hi everyone!I am about to set up my HP 3458a for remote control to do some long term (hrs...days) data logging, but ran into a few obstacles.The EEVblog forum seemed to be the go-to place for quick help. So before I start digging into the IEEE-488 specs and the 3458a command reference and possibly end up writing my own device drivers, I thought I'd finally register after years of lurking and ask the industry's best and brightest.What works:I've connectedHP 3458a ---<GPIB-cable>--- NI GPIB-232CT-A (GPIB-to-serial-converter) ---<Nullmodem-cable>--- LogiLink AU0034 (serial-usb-converter) ---<USB-cable>--- PC (Win10)The USB-serial converter seems to work: I did a loop back test with Putty and verified Tx-ing single characters and strings on a scope.The NI GPIB-serial converter seems to work: It does "stuff" when sending various commands via Putty.echo 1works as expected.idreturns the exprected device information.clrcauses the DMM to stop sampling. I am still not sure whether everything is set up correctly in terms of flow control, GPIB parameters, etc.; but for now I want to believe that things are well on this lowest protocol-level.This is pretty much as far as I got. Now while it surely must be possible to program the 3458a on this level, I was hoping for a more user friendly solution. LabView is out of the question, because I can't afford a license. I do however have access to a Matlab license including Instrument Control and Realtime Toolboxes. Unfortunately, Matlab does not seem to come with suitable device drivers anymore. Years ago, when the Realtime Toolbox was still called xPC Target (or such), there were Simulink BlocksGPIB SetupandGPI Send/Receivewhich could have done the trick.So now for the big question: Has anyone ever successfully configured a NI GPIB-232CT-A for use with Matlab and would like to share their experience? Or do you have a better suggestion to getting started with GPIB control and data acquisition? P.S.: Because I'm rather cheap, I'd like to avoid having to buy a modern GPIB controller and use the existing fossil instead (if at all feasible).Many thanks for many replies!

author: cncjerry
author_rank: Unknown
timestamp: September 27, 2015, 12:10:06 am
content: Matlab works and I've used the instrument control toolbox in simulink. I gave it up because I had inconsistent results. It would hang at init and was too frustrating to debug.What works the best and I've written a ton of code for my 3456, 3457a and Keithley meters is Visual Basic. I use a GPIB to USB converter as well as a GPIB PCI card but your setup should work just as well. The biggest problem with the HP meters is having the line end character set correctly. I would try sending the correct IDN? command first. That is the most predictable in terms of response.If all is well and you have the baud rate, parity, etch set is try sending IDN? followed by a line end command and you should get a response. Try resetting the meter between tries.

author: LINACboy
author_rank: Contributor
timestamp: September 27, 2015, 12:50:19 pm
content: Matlab would have been nice, because for number crunching I'd want to import the data there anyways. Eventually, I would also want to build a little GUI to display my measurements as real-time Y-T or histogramm, like all the modern graphical DMMs (34465A, DMM7510 and such) do.I agree, BASIC would be nice, since its the 3458a's native command language. However I curently lack some fundamental knowledge on how to encapsulate those commands on the virtual COM-port (USB-serial-converter) so that they arrive as proper BASIC instructions at the DMM. If I simply typeID? TEMP? REV?etc. in a serial terminal, it won't do anything, obviously. That line end thing might be exactly my issue, because the DMM occasuinally complains about syntax errors.(Btw.IDN?will not work on the 3458a, because at least my old HP one is a pre-IEEE-488-standard device.ID?should do the equivalent according to the command reference).So, I'm going to play around with it a little more and try to figure it out on my own.Thanks for the input, looking forward for more!

author: cncjerry
author_rank: Unknown
timestamp: September 27, 2015, 05:11:24 pm
content: Two other factors I ran into. The first was a timeout in the Visa dll, but since you are using rs232 it might not apply. The second was that the meter was triggering continuously which added to the timeout problem. So I learned to use a single trigger for each reading. I have command sequences that work with a 3457a I'll post when I find them.

author: Magnum
author_rank: Regular Contributor
timestamp: September 27, 2015, 05:17:37 pm
content: Have you checked Keysight Vee? There is a 30 day trial available and IMHO Keysight has all drivers for their instruments.

author: cncjerry
author_rank: Unknown
timestamp: September 27, 2015, 05:28:58 pm
content: This is the initialization command sequence for my application. The 'true' parameter flushes the line if I remember correctly. On the 3457a I have to read the hires register to get the 7.5th digit returned. If you need that code for the 3458a let me know. I am using the rear scanner (term scanner, chan 0) so you would need to select the right terminals. I also use the beep a lot to signal if the meter is accepting sequential commands or hung waiting for a trigger. Once you get it working it is very reliable.' Intialize VMinstrumentVM.WriteString("PRESET", True)instrumentVM.WriteString("OFORMAT ASCII", True)instrumentVM.WriteString("BEEP", True)instrumentVM.WriteString("DCV AUTO", True)instrumentVM.WriteString("TARM AUTO", True)instrumentVM.WriteString("TRIG AUTO", True)instrumentVM.WriteString("DCV 30,100", True)instrumentVM.WriteString("NRDGS 1,SYN", True)instrumentVM.WriteString("MEM OFF", True)instrumentVM.WriteString("END ALWAYS", True)instrumentVM.WriteString("NDIG 6", True)instrumentVM.WriteString("TERM SCANNER", True)instrumentVM.WriteString("CHAN 0", True)

author: onlooker
author_rank: Frequent Contributor
timestamp: September 27, 2015, 06:48:52 pm
content: QuoteWith a "NI GPIB-232CT-A" the communication with a GPIB device needs to be wrapped with the "NI GPIB-232CT-A" specific command pair RD/WRT. For example, in a serial terminal, to send the "ID?" command to and receive the response from the GPIB device at address 22, you type:WRT 22<cr>ID?;<cr> [click send button now]RD #16 22<cr> [click send button now]

author: LINACboy
author_rank: Contributor
timestamp: September 28, 2015, 12:20:04 am
content: QuoteAlive! It's alive!Code:wrt 22 beep; lets the puppy sing. It seems to work both with and without semi colon after the command. However I had to activate the Putty option "Implicit LF every CR" for things to run as expected.Thank you onlooker, your code example did help a lot. It clearly depends on how the terminal program handles the <CF> and <LF>. I'm going to try out a few other serial terminals and of course the Matlab serial interface commands to see how they react.For reference: The command termination behaviour of the HP 3458a is described in the Keysight 3458A Multimeter - User's Guide" Ch6 p.152 (Edition 7). For the NI GPIB-232CT-A it is Ch6-2 p.107 of the "GPIB-232/485CT-A User Manual"I can now change between the various measurement functions (DCV, DCI, etc.) and the read out of the identity query (ID?) and measurement samples kinda works, too.Code:wrt 22ID?rd #16 220rd #16 22HP3458A-2.056616rd #16 2254427E-06-2.0116rd #16 222453442E-06-1.16My guess is that when the DMM is continuously sampling (like in default local mode) it is also constantly pushing data onto the GPIB, therefore filling up the input buffer of the GPIB-controller. And if you don't hit the correct byte length n with your rd #n command, then you snap off your samples somewhere in the middle rather then from start to end. This might be related to continuous trigger issue cncjerri has mentioned. (Or not, this serial interface digital data transmission stuff is really not my hometurf .-.)QuoteThanks for the hint. Sounds interesting. I will check it out some time, but I have little hope that they support my 90s vintage National Instruments GPIB-RS232 controller, if NI themselves stopped developing drivers for it since Win98.

author: onlooker
author_rank: Frequent Contributor
timestamp: September 28, 2015, 02:09:24 am
content: QuoteYes, <LF> or <cr> can be confusing sometimes.Semi-colons are used as separators between multiple (HP?)GPIB commands issued with a single "wrt". For example, hp3457a may be initialized with,wrt 22<LF> PRESET;TRIG SYN;OFORMAT 1;END ALWAYS;DCV;NDIG 6;<LF>For a single GPIB command, the semi-colon may be omitted.The RD length is a tricky parameter. It is easier to handle RD properly in your own program that can parse the return and compare it to the specific return format of "NI GPIB-232CT-A" (ending with 0 fillers and, then, the number of bytes returned).

author: macboy
author_rank: Super Contributor
timestamp: September 28, 2015, 02:05:15 pm
content: Quote from: LINACboy on September 26, 2015, 10:41:43 pmMaybe not. Earlier this year, they jumped on the maker bandwagon and released "LabVIEW Home". It is the LabVIEW Full Development System, plus the LabVIEW Control Design and Simulation and LabVIEW MathScript RT modules, all for $50, which is roughly 1% of the full (professional) price. As long as this is a non-commercial use, then price should not be an obstacle.

author: LINACboy
author_rank: Contributor
timestamp: September 28, 2015, 02:13:10 pm
content: QuoteSweet! I´ll put it in the letter for Santa. It´s gonna be a long one this year

author: LINACboy
author_rank: Contributor
timestamp: October 10, 2015, 04:49:02 pm
content: Well, I finally got it to run in Matlab.My serial-GPIB adapter is really picky when it comes to correct end-of-line termination symbols. Matlab's serial port object is supposed to add <CR> and <LF> symbols automatically, if configured so. But I still had to append a line feed ('\n') to every string I send to it in order to make it work.Apart from that, it's important to always read the correct number of bytes or the interface gets out of sync. If this happens, a remote reset ('clr' command of the GPIB-232CT-A) seems to be the only thing that helps). The message length is also the reason why my code currently only works for commands which return a message of fixed, known length.example 'ID?':Code:fpintf(s, 'wrt 22');% s is the matlab serial port object% wrt 22 prepares the GPIB controller to write a message the device with address 22fprintf(s, 'ID?');% instructs the controller to write the message ID? to the above devicefprintf(s, 'rd #9 22');% instructs the controller to read 9 bytes from the device with address22% the expected answer is 'HP3458A' + <CR> + <LF>, so a total of 9 ASCII symbols% if one would read just the first 7 bytes, the system would get out of sync and produce only crap the next time a rd command is executedfscanf(s);%serial read. the return value is a string of 9 characters 'HP3458A' + <CR> + <LF> as stated abovefscanf(s);%second serial read. the return value is ASCII '9' + <CR> + <LF> , the ASCII coded number beeing equal to the number of bytes, the controller has read previously%this is a string that is appended by the controller as a means to verify correct transmission% it must always be read out together with the chunk of date one is actually interested in, or the interface will clogfprintf(s, 'sic');%sets the GPIB clear%not necessary, but a good way to put the interface back into a defined stateHere's my code so far. It is highly specific to the GPIB-232CT-A, so probably not very interesting for those using any other adapter. Only the most important functions with fixed length response message are currently implemented. E.g. the return of 'RANGE?' can vary in length and is therefore not supported. But for now it's enough to keep me going.Next steps: Write a GUI for the existing functionality. Add automated data acquisition for long time measurements. Add a feature for real-time plotting Y-T diagrams and histograms.configuration structCode:config = struct;config.GPIB_232CT_A = struct;config.GPIB_232CT_A.serial_port_object_configuration = struct;config.GPIB_232CT_A.serial_port_object_configuration.BaudRate = 38400;config.GPIB_232CT_A.serial_port_object_configuration.BreakInterruptFcn = '';config.GPIB_232CT_A.serial_port_object_configuration.ByteOrder = ...'littleEndian';config.GPIB_232CT_A.serial_port_object_configuration.BytesAvailableFcn = '';config.GPIB_232CT_A.serial_port_object_configuration.BytesAvailableFcnCount = 48;config.GPIB_232CT_A.serial_port_object_configuration.BytesAvailableFcnMode = ...'terminator';config.GPIB_232CT_A.serial_port_object_configuration.DataBits = 7;config.GPIB_232CT_A.serial_port_object_configuration.DataTerminalReady = ...'on';config.GPIB_232CT_A.serial_port_object_configuration.ErrorFcn = '';config.GPIB_232CT_A.serial_port_object_configuration.FlowControl = ...'hardware';config.GPIB_232CT_A.serial_port_object_configuration.InputBufferSize = 512;config.GPIB_232CT_A.serial_port_object_configuration.Name = ...'Serial-COM4';config.GPIB_232CT_A.serial_port_object_configuration.ObjectVisibility = ...'on';config.GPIB_232CT_A.serial_port_object_configuration.OutputBufferSize = 512;config.GPIB_232CT_A.serial_port_object_configuration.OutputEmptyFcn = '';config.GPIB_232CT_A.serial_port_object_configuration.Parity = 'none';config.GPIB_232CT_A.serial_port_object_configuration.PinStatusFcn = '';config.GPIB_232CT_A.serial_port_object_configuration.Port = 'COM4';config.GPIB_232CT_A.serial_port_object_configuration.ReadAsyncMode = ...'continuous';config.GPIB_232CT_A.serial_port_object_configuration.RecordDetail = ...'compact';config.GPIB_232CT_A.serial_port_object_configuration.RecordMode = ...'overwrite';config.GPIB_232CT_A.serial_port_object_configuration.RecordName = ...'record.txt';config.GPIB_232CT_A.serial_port_object_configuration.RequestToSend = ...'on';config.GPIB_232CT_A.serial_port_object_configuration.StopBits = 1;config.GPIB_232CT_A.serial_port_object_configuration.Tag = '';config.GPIB_232CT_A.serial_port_object_configuration.Timeout = 10.1;config.GPIB_232CT_A.serial_port_object_configuration.TimerFcn = '';config.GPIB_232CT_A.serial_port_object_configuration.TimerPeriod = 1;config.GPIB_232CT_A.serial_port_object_configuration.UserData = [];config.GPIB_232CT_A.serial_port_object_configuration.Terminator = cell(1, 2);config.GPIB_232CT_A.serial_port_object_configuration.Terminator{1} = ...'CR/LF';config.GPIB_232CT_A.serial_port_object_configuration.Terminator{2} = ...'CR/LF';config.HP3458A = struct;config.HP3458A.Address = 22;create serial port object for the GPIB controllerCode:function [ serial_port_object ] = init_serial_link( config_struct )%initialises the serial link to the GPIB-232CT-Atryfprintf('Configuring RS232 link... ');serial_port_object = serial(config_struct.serial_port_object_configuration.Port);set(serial_port_object, config_struct.serial_port_object_configuration);fprintf(' done!\n');fprintf('Opening serial port...');fopen(serial_port_object);fprintf(' done!\r\n');fprintf(serial_port_object, 'id');fprintf(fscanf(serial_port_object)); %GPIB-232CT-A Rev. B.3fprintf(fscanf(serial_port_object)); %(c)1995 National Instrumentsfprintf(fscanf(serial_port_object)); %256K bytes RAMfprintf(serial_port_object, 'clr');fprintf(serial_port_object, 'cac 1');fprintf(serial_port_object, 'cac');if str2num(fscanf(serial_port_object)) ~= 1%return value of 1 means, GPIB controler is active controllerfprintf('FOO\n');error('ERROR: GPIB controller faild to become active controller');end;fprintf(serial_port_object, 'clr');fprintf(serial_port_object, 'sic');fprintf('\nGPIB interface ready!\n');catchfclose(serial_port_object);error('Error: operation unsuccessful')end;endHP3458A command interpreterCode:function [ varargout ] = cmd_HP3458A ( varargin )%varargin{1} is serial port object%varargin{2} is device configuration struct%varargin{3} is a HP3458A command%varargin{>3} are parameters of the command (where applicable)tryswitch nargincase 0error('Not enough input arguments specified. \nNeed at least serial_port_object, device_config_struct and command_string');case 1error('Not enough input arguments specified. \nNeed at least serial_port_object, device_config_struct and command_string');case 2error('Not enough input arguments specified. \nNeed at least serial_port_object, device_config_struct and command_string');case 3if isvalid(varargin{1}) && (mod(varargin{2}.Address, 1) == 0) && varargin{2}.Address >= 0 && varargin{2}.Address <= 30%valid serial object && valid GPIB address: 0...30execute_command();elseerror('Error: invalid serial object or GPIB address.');end;otherwiseerror('Error: too many input arguments.');end;catcherror('Error: operation unsuccessful.');end;function execute_command()%executes a valid command%(see HP3458A User Manual - Chapter 6 - Command Reference)%invalid command strings produce an error().fprintf(varargin{1}, 'sic');if ~ischar(varargin{3})error('Error: 3rd input argument is no string.');end;switch varargin{3}case 'ID?'fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'ID?;\n');fprintf(varargin{1}, 'rd #9 %d\n', varargin{2}.Address);varargout{1} = fscanf(varargin{1}); %return device ID 'HP3458A'if str2double(fscanf(varargin{1})) ~= 9 || ~strncmp(varargout{1}, 'HP3458A', 7)error('Error: executing ID? failed');end;case 'TEMP?'fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'TEMP?;\n');fprintf(varargin{1}, 'rd #6 %d\n', varargin{2}.Address);varargout{1} = fscanf(varargin{1}); %return device internal temperature in deg Cif str2double(fscanf(varargin{1})) ~= 6error('Error: executing TEMP? failed');end;case {'FUNC DCV','DCV'}fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'FUNC DCV;\n');case {'FUNC ACV','ACV'}fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'FUNC ACV;\n');case {'FUNC ACDCV','ACDCV'}fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'FUNC ACDCV;\n');case {'FUNC OHM','OHM'}fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'FUNC OHM;\n');case {'FUNC OHMF','OHMF'}fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'FUNC OHMF;\n');case {'FUNC DCI','DCI'}fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'FUNC DCI;\n');case {'FUNC ACI','ACI'}fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'FUNC ACI;\n');case {'FUNC ACDCI','ACDCI'}fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'FUNC ACDCI;\n');case {'TRIG?'}fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'TRIG?;\n');fprintf(varargin{1}, 'rd #3 %d\n', varargin{2}.Address);varargout{1} = fscanf(varargin{1}); %return device ID 'HP3458A'if str2double(fscanf(varargin{1})) ~= 3error('Error: executing TRIG? failed');end;case {'TRIG AUTO'}fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'TRIG AUTO;\n');fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'TRIG?;\n');fprintf(varargin{1}, 'rd #3 %d\n', varargin{2}.Address);varargout{1} = fscanf(varargin{1}); %return trigger event parameter numeric equivalentif str2double(fscanf(varargin{1})) ~= 3 || ~strncmp(varargout{1}, '1', 1)error('Error: setting TRIG AUTO failed');end;case {'TRIG EXT'}fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'TRIG EXT;\n');fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'TRIG?;\n');fprintf(varargin{1}, 'rd #3 %d\n', varargin{2}.Address);varargout{1} = fscanf(varargin{1}); %return trigger event parameter numeric equivalentif str2double(fscanf(varargin{1})) ~= 3 || ~strncmp(varargout{1}, '2', 1)error('Error: setting TRIG EXT failed');end;case {'TRIG SGL'}fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'TRIG SGL;\n');case {'TRIG HOLD'}fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'TRIG HOLD;\n');fprintf(varargin{1}, 'wrt %d\n', varargin{2}.Address);fprintf(varargin{1}, 'TRIG?;\n');fprintf(varargin{1}, 'rd #3 %d\n', varargin{2}.Address);varargout{1} = fscanf(varargin{1}); %return trigger event parameter numeric equivalentif str2double(fscanf(varargin{1})) ~= 3 || ~strncmp(varargout{1}, '4', 1)error('Error: setting TRIG EXT failed');end;otherwiseerror('Error: invalid or unknown command string');endfprintf(varargin{1}, 'sic');endendsample acquisition commandThe HP3458A user manual (Ch.4 'Output Formats' )states that in ASCII mode, the return is 15 bytes, but it is actually a total of 18:# 1sign: "-" (0x2D) or SP (0x20)2digit3decimal point "." (0x2E)4..12digit13exponent indicator "E" (0x45)14sign: "-" (0x2D) or "+" (0x2B)15..16digit17\r (0x0D)18\n (0x0A)Code:function [ sample ] = acquire_sample_HP3458A( serial_port_object, config_struct )%UNTITLED Summary of this function goes here% Detailed explanation goes heretryif isvalid(serial_port_object) && (mod(config_struct.Address, 1) == 0) && config_struct.Address >= 0 && config_struct.Address <= 30%valid serial object && valid GPIB address: 0...30fprintf(serial_port_object, 'rd #18 %d\n', config_struct.Address');sample = str2double(fscanf(serial_port_object));if str2double(fscanf(serial_port_object)) ~= 18error('Error: executing ID? failed');end;elseerror('Error: invalid serial object or GPIB address.');end;catcherror('Error: operation unsuccessful.');end;end

author: onlooker
author_rank: Frequent Contributor
timestamp: October 11, 2015, 03:13:11 am
content: QuoteIn the GPIB-232CT-A manual, under "RD" command,QuoteIt means "RD" can request more bytes than actually is available, and the caller of "RD" needs to read/parse the serial stream to extract the part of response actually from the GPIB device according to the format quoted above.

author: LINACboy
author_rank: Contributor
timestamp: October 11, 2015, 11:13:15 am
content: Yes, but if you are in TRIG AUTO mode, there is always more data available to read on the bus.rd #18 22works correctly the first time. It could produce for example-1.234567890E+12+ <CR> + <LF>18+ <CR> + <LF>now - still auto triggering, you typerd #1922and get-1.234567890E+12+ <CR> + <LF>-19+ <CR> + <LF>So, as the 19th byte it reads the first byte of the next sample, i.e. the sign.If you switch back to reading the correct number of bytes, your - lets call it ´mask´ - has moved forward by one byterd #1822now produces1.234567890E+12+ <CR> + <LF>-18+ <CR> + <LF>The only solution I see is that one would always have to read more than double of the actual number of bytes in order to be sure to receive one complete string of valid data. Not very efficient in my opinion.rd #372234567890E+12-1.234567890E+12-1.2337

author: onlooker
author_rank: Frequent Contributor
timestamp: October 11, 2015, 12:35:31 pm
content: For my HP3457a, I initialize it with "TRIG SYN;END ALWAYS;...". This is one way to get more control as to when the HP3457a should take a reading/sampling. Actaully, in this case, exactly one reading is done with the triggering being implied by just sending the "RD" command to the 3457a.